diff --git a/.clang-format b/.clang-format index 603c00c59b12b51..150127471485c20 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/SECURITY.md b/.github/SECURITY.md index 1b16d94b57520f6..a4e9730d0a10251 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -8,12 +8,12 @@ updates: - The most recent release, and the release prior to that. - Active LTS releases. -At this time, with the latest release of v3.3, the supported +At this time, with the latest release of v3.5, the supported versions are: - v2.7: Current LTS - - v3.2: Prior release - - v3.3: Current release + - v3.4: Prior release + - v3.5: Current release ## Reporting process diff --git a/.github/workflows/assigner.yml b/.github/workflows/assigner.yml index 6a3198086dee78f..6e4e01c8ea1b6a8 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 a66edd318f7d1a9..95175ecf1bbf183 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 a8a49be767080b3..b8b34315772dd50 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,19 +32,20 @@ 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.6 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 bsim_bt_52_test_results_file: ./bsim_bt/52_bsim_results.xml 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: | @@ -59,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 @@ -78,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: | @@ -94,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: | @@ -103,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: | @@ -115,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} ) @@ -134,15 +149,25 @@ jobs: if: steps.check-bluetooth-files.outputs.any_changed == 'true' || steps.check-common-files.outputs.any_changed == 'true' run: | export ZEPHYR_BASE=${PWD} - WORK_DIR=${ZEPHYR_BASE}/bsim_bt nice tests/bsim/bluetooth/compile.sh + export WORK_DIR=${ZEPHYR_BASE}/bsim_bt + # Build and run the BT tests for nrf52_bsim: + nice tests/bsim/bluetooth/compile.sh RESULTS_FILE=${ZEPHYR_BASE}/${bsim_bt_52_test_results_file} \ - SEARCH_PATH=tests/bsim/bluetooth/ tests/bsim/run_parallel.sh - # Run the BT controller tests also for the nrf5340 + TESTS_FILE=tests/bsim/bluetooth/tests.nrf52bsim.txt tests/bsim/run_parallel.sh + # Build and run the BT controller tests also for the nrf5340bsim_nrf5340_cpunet BOARD=nrf5340bsim_nrf5340_cpunet \ - WORK_DIR=${ZEPHYR_BASE}/bsim_bt nice tests/bsim/bluetooth/ll/compile.sh + nice tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpunet.sh BOARD=nrf5340bsim_nrf5340_cpunet \ RESULTS_FILE=${ZEPHYR_BASE}/${bsim_bt_53_test_results_file} \ - SEARCH_PATH=tests/bsim/bluetooth/ll/ tests/bsim/run_parallel.sh + TESTS_FILE=tests/bsim/bluetooth/tests.nrf5340bsim_nrf5340_cpunet.txt \ + tests/bsim/run_parallel.sh + # Build and run the nrf5340 split stack tests set + BOARD=nrf5340bsim_nrf5340_cpuapp \ + nice tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh + BOARD=nrf5340bsim_nrf5340_cpuapp \ + RESULTS_FILE=${ZEPHYR_BASE}/${bsim_bt_53split_test_results_file} \ + TESTS_FILE=tests/bsim/bluetooth/tests.nrf5340bsim_nrf5340_cpuapp.txt \ + tests/bsim/run_parallel.sh - name: Run Networking Tests with BSIM if: steps.check-networking-files.outputs.any_changed == 'true' || steps.check-common-files.outputs.any_changed == 'true' @@ -152,21 +177,37 @@ 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: | ./bsim_bt/52_bsim_results.xml ./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 d19f881ddcd0054..16b251b7f2ff57a 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 0aa8d5cd690d008..caebd7feda12fd1 100644 --- a/.github/workflows/clang.yaml +++ b/.github/workflows/clang.yaml @@ -11,16 +11,15 @@ 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.6 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject strategy: fail-fast: false matrix: - platform: ["native_posix"] + platform: ["native_sim"] 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 }} @@ -42,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: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -66,6 +65,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 @@ -125,7 +126,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.platform }}) path: twister-out/twister.xml @@ -137,7 +138,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 @@ -148,7 +149,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 92cf90b82992585..6924c7e587e5578 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.6 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 + ./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 + 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 ea632b7f0b2b90f..1bc6ee2e6667328 100644 --- a/.github/workflows/coding_guidelines.yml +++ b/.github/workflows/coding_guidelines.yml @@ -8,16 +8,16 @@ 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 }}-doc-pip + key: ${{ runner.os }}-pip-${{ hashFiles('.github/workflows/coding_guidelines.yml') }} - name: Install python dependencies run: | diff --git a/.github/workflows/compliance.yml b/.github/workflows/compliance.yml index 59cfc40c264db73..219fbfae60764f3 100644 --- a/.github/workflows/compliance.yml +++ b/.github/workflows/compliance.yml @@ -12,16 +12,16 @@ 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 }}-doc-pip + key: ${{ runner.os }}-pip-${{ hashFiles('.github/workflows/compliance.yml') }} - name: Install python dependencies run: | @@ -44,8 +44,8 @@ jobs: # debug git log --pretty=oneline | head -n 10 west init -l . || true - west config manifest.group-filter -- +ci,+optional - west update 2>&1 1> west.update.log || west update 2>&1 1> west.update2.log + 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 continue-on-error: true @@ -61,7 +61,7 @@ jobs: -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 ba02bb689750951..31e9fcde9b84430 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 465a86731494fcc..c8408f68c094c97 100644 --- a/.github/workflows/devicetree_checks.yml +++ b/.github/workflows/devicetree_checks.yml @@ -26,7 +26,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.8, 3.9, '3.10'] + python-version: [3.8, 3.9, '3.10', '3.11', '3.12'] os: [ubuntu-22.04, macos-11, windows-2022] exclude: - os: macos-11 @@ -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 14c651a25f1e003..b6954e288c92269 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 351cb041a83a89f..9dde3128477cf6d 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -26,7 +26,7 @@ on: env: # NOTE: west docstrings will be extracted from the version listed here - WEST_VERSION: 1.0.0 + WEST_VERSION: 1.2.0 # The latest CMake available directly with apt is 3.18, but we need >=3.20 # so we fetch that through pip. CMAKE_VERSION: 3.20.5 @@ -35,6 +35,7 @@ env: jobs: doc-build-html: name: "Documentation Build (HTML)" + if: github.repository_owner == 'zephyrproject-rtos' runs-on: zephyr-runner-linux-x64-4xlarge timeout-minutes: 45 concurrency: @@ -43,12 +44,13 @@ jobs: steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 - name: Rebase + if: github.event_name == 'pull_request' continue-on-error: true env: BASE_REF: ${{ github.base_ref }} @@ -62,13 +64,13 @@ jobs: - name: install-pkgs run: | sudo apt-get update - sudo apt-get install -y ninja-build graphviz + sudo apt-get install -y ninja-build graphviz lcov wget --no-verbose "https://github.com/doxygen/doxygen/releases/download/Release_${DOXYGEN_VERSION//./_}/doxygen-${DOXYGEN_VERSION}.linux.bin.tar.gz" tar xf doxygen-${DOXYGEN_VERSION}.linux.bin.tar.gz 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') }} @@ -79,6 +81,7 @@ jobs: pip3 install -r doc/requirements.txt pip3 install west==${WEST_VERSION} pip3 install cmake==${CMAKE_VERSION} + pip3 install coverxygen - name: west setup run: | @@ -98,31 +101,48 @@ jobs: else DOC_TARGET="html" fi - DOC_TAG=${DOC_TAG} SPHINXOPTS_EXTRA="-q -t publish" make -C doc ${DOC_TARGET} + # API documentation coverage + python3 -m coverxygen --xml-dir doc/_build/html/doxygen/xml/ --src-dir include/ --output doc-coverage.info + # deprecated page causing issues + lcov --remove doc-coverage.info \*/deprecated > new.info + genhtml --no-function-coverage --no-branch-coverage new.info -o coverage-report + - name: compress-docs run: | tar cfJ html-output.tar.xz --directory=doc/_build html + tar cfJ api-output.tar.xz --directory=doc/_build html/doxygen/html + 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@v4 + with: + name: api-coverage + path: api-coverage.tar.xz + - name: process-pr if: github.event_name == 'pull_request' run: | REPO_NAME="${{ github.event.repository.name }}" PR_NUM="${{ github.event.pull_request.number }}" DOC_URL="https://builds.zephyrproject.io/${REPO_NAME}/pr/${PR_NUM}/docs/" + API_DOC_URL="https://builds.zephyrproject.io/${REPO_NAME}/pr/${PR_NUM}/docs/doxygen/html/" + API_COVERAGE_URL="https://builds.zephyrproject.io/${REPO_NAME}/pr/${PR_NUM}/api-coverage/" echo "${PR_NUM}" > pr_num echo "Documentation will be available shortly at: ${DOC_URL}" >> $GITHUB_STEP_SUMMARY + echo "API Documentation will be available shortly at: ${API_DOC_URL}" >> $GITHUB_STEP_SUMMARY + 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 @@ -130,7 +150,9 @@ jobs: doc-build-pdf: name: "Documentation Build (PDF)" - if: github.event_name != 'pull_request' + if: | + github.event_name != 'pull_request' && + github.repository_owner == 'zephyrproject-rtos' runs-on: zephyr-runner-linux-x64-4xlarge container: texlive/texlive:latest timeout-minutes: 60 @@ -139,8 +161,12 @@ jobs: cancel-in-progress: true steps: + - name: Apply container owner mismatch workaround + run: | + git config --global --add safe.directory ${GITHUB_WORKSPACE} + - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: install-pkgs run: | @@ -148,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') }} @@ -184,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/doc-publish-pr.yml b/.github/workflows/doc-publish-pr.yml index 6db566d4e1fec93..07ee0c106045cc3 100644 --- a/.github/workflows/doc-publish-pr.yml +++ b/.github/workflows/doc-publish-pr.yml @@ -46,6 +46,7 @@ jobs: - name: Uncompress HTML docs run: | tar xf html-output/html-output.tar.xz -C html-output + tar xf api-coverage/api-coverage.tar.xz -C api-coverage - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v2 @@ -61,3 +62,6 @@ jobs: aws s3 sync --quiet html-output/html \ s3://builds.zephyrproject.org/${{ github.event.repository.name }}/pr/${PR_NUM}/docs \ --delete + aws s3 sync --quiet api-coverage/coverage-report/ \ + s3://builds.zephyrproject.org/${{ github.event.repository.name }}/pr/${PR_NUM}/api-coverage \ + --delete diff --git a/.github/workflows/doc-publish.yml b/.github/workflows/doc-publish.yml index 5262d9db67e5625..c15313bb087fdd6 100644 --- a/.github/workflows/doc-publish.yml +++ b/.github/workflows/doc-publish.yml @@ -32,6 +32,7 @@ jobs: - name: Uncompress HTML docs run: | tar xf html-output/html-output.tar.xz -C html-output + tar xf api-coverage/api-coverage.tar.xz -C api-coverage - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v2 @@ -52,4 +53,5 @@ jobs: aws s3 sync --quiet html-output/html s3://docs.zephyrproject.org/${VERSION} --delete aws s3 sync --quiet html-output/html/doxygen/html s3://docs.zephyrproject.org/apidoc/${VERSION} --delete + aws s3 sync --quiet api-coverage/coverage-report/ s3://docs.zephyrproject.org/api-coverage/${VERSION} --delete aws s3 cp --quiet pdf-output/zephyr.pdf s3://docs.zephyrproject.org/${VERSION}/zephyr.pdf diff --git a/.github/workflows/errno.yml b/.github/workflows/errno.yml index 537470f0a224865..78e8b8e8ed62c09 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.6 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 63a1277be17dcc0..9b90cff1f9e4b06 100644 --- a/.github/workflows/footprint-tracking.yml +++ b/.github/workflows/footprint-tracking.yml @@ -22,15 +22,14 @@ concurrency: jobs: footprint-tracking: - runs-on: ubuntu-22.04 + 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.6 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 6a7005f1880a84a..2b907618082659c 100644 --- a/.github/workflows/footprint.yml +++ b/.github/workflows/footprint.yml @@ -8,15 +8,14 @@ concurrency: jobs: footprint-delta: - runs-on: ubuntu-22.04 + 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.6 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 5984b29fe1f37a4..5f62c03d6def938 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 000000000000000..efa75ef88d7bfc1 --- /dev/null +++ b/.github/workflows/hello_world_multiplatform.yaml @@ -0,0 +1,78 @@ +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' + +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, windows-2022] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout + uses: actions/checkout@v3 + 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@v3 + 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 9c143dbd1f4dc7c..f44ef5531d46ce5 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 dd4e1928a2da4ba..7d2d083faae0e50 100644 --- a/.github/workflows/license_check.yml +++ b/.github/workflows/license_check.yml @@ -8,14 +8,16 @@ 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 id: scancode uses: zephyrproject-rtos/action_scancode@v4 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 49f67fb95b735c8..040ec957e3904cb 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 }} @@ -26,7 +26,7 @@ jobs: west init -l . || true - name: Manifest - uses: zephyrproject-rtos/action-manifest@f223dce288b0d8f30bfd57eb2b14b18c230a7d8b + uses: zephyrproject-rtos/action-manifest@v1.2.2 with: github-token: ${{ secrets.ZB_GITHUB_TOKEN }} manifest-path: 'west.yml' diff --git a/.github/workflows/pylib_tests.yml b/.github/workflows/pylib_tests.yml index 06f61f32c243104..70bd107f8e52c93 100644 --- a/.github/workflows/pylib_tests.yml +++ b/.github/workflows/pylib_tests.yml @@ -25,18 +25,18 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.8, 3.9, '3.10'] + python-version: [3.8, 3.9, '3.10', '3.11', '3.12'] 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 ab0e9384ae7c210..ccecd17df807925 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 132d8f357c81294..2e2356910b13916 100644 --- a/.github/workflows/scripts_tests.yml +++ b/.github/workflows/scripts_tests.yml @@ -25,11 +25,11 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.8, 3.9, '3.10'] + python-version: [3.8, 3.9, '3.10', '3.11', '3.12'] 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/stale_issue.yml b/.github/workflows/stale_issue.yml index d93aa1f381d128f..8dc313701258c05 100644 --- a/.github/workflows/stale_issue.yml +++ b/.github/workflows/stale_issue.yml @@ -24,5 +24,5 @@ jobs: stale-issue-label: 'Stale' stale-pr-label: 'Stale' exempt-pr-labels: 'Blocked,In progress' - exempt-issue-labels: 'In progress,Enhancement,Feature,Feature Request,RFC,Meta,Process' + exempt-issue-labels: 'In progress,Enhancement,Feature,Feature Request,RFC,Meta,Process,Coverity' operations-per-run: 400 diff --git a/.github/workflows/stats_merged_prs.yml b/.github/workflows/stats_merged_prs.yml new file mode 100644 index 000000000000000..cd874b65b1ac877 --- /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 23174d7ab7cc5f1..7f65178e1030b6f 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.6 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.6 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 05ea87dfd4258f8..92de15b81b0b999 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' @@ -29,18 +29,18 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.8, 3.9, '3.10'] + python-version: [3.8, 3.9, '3.10', '3.11', '3.12'] 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 }} @@ -48,7 +48,7 @@ jobs: ${{ runner.os }}-pip-${{ matrix.python-version }} - name: install-packages run: | - pip3 install -r scripts/requirements-base.txt -r scripts/requirements-build-test.txt + pip3 install -r scripts/requirements-base.txt -r scripts/requirements-build-test.txt -r scripts/requirements-run-test.txt - name: Run pytest for twisterlib env: ZEPHYR_BASE: ./ diff --git a/.github/workflows/twister_tests_blackbox.yml b/.github/workflows/twister_tests_blackbox.yml index abf8b324356fa3f..3811b9b3fb8b9e3 100644 --- a/.github/workflows/twister_tests_blackbox.yml +++ b/.github/workflows/twister_tests_blackbox.yml @@ -19,12 +19,10 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.8, 3.9, '3.10'] + 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.6 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 0d30209831df584..25a5fc88fd62767 100644 --- a/.github/workflows/west_cmds.yml +++ b/.github/workflows/west_cmds.yml @@ -27,7 +27,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.8, 3.9, '3.10'] + python-version: [3.8, 3.9, '3.10', '3.11', '3.12'] os: [ubuntu-22.04, macos-11, windows-2022] exclude: - os: macos-11 @@ -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/.gitignore b/.gitignore index fae5aabbf3087f6..13c99731c52966b 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ ImageSize.txt Kconfig.txt KconfigBasic.txt KconfigBasicNoModules.txt +KeepSorted.txt MaintainersFormat.txt ModulesMaintainers.txt Nits.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 7aae816c4b9c271..ff12e0852eced06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,19 +118,7 @@ zephyr_include_directories( include(${ZEPHYR_BASE}/cmake/linker_script/${ARCH}/linker.cmake OPTIONAL) -# Don't add non-existing include directories, it creates noise and -# warnings in some tooling -foreach(optional_include_dir - ${SOC_DIR}/${ARCH}/${SOC_PATH} - ${SOC_DIR}/${ARCH}/${SOC_PATH}/include - ${SOC_DIR}/${ARCH}/${SOC_PATH}/include/${SOC_NAME} - ${SOC_DIR}/${ARCH}/${SOC_FAMILY}/include - ${SOC_DIR}/${ARCH}/${SOC_FAMILY}/common/include - ) - if(EXISTS ${optional_include_dir}) - zephyr_include_directories(${optional_include_dir}) - endif() -endforeach() +zephyr_include_directories(${SOC_DIR}/${ARCH}/${SOC_PATH}) # Don't inherit compiler flags from the environment foreach(var AFLAGS CFLAGS CXXFLAGS CPPFLAGS LDFLAGS) @@ -484,30 +472,6 @@ if(CONFIG_USERSPACE) set(KOBJECT_LINKER_DEP kobject_linker) endif() -get_property(TOPT GLOBAL PROPERTY TOPT) -get_property(COMPILER_TOPT TARGET compiler PROPERTY linker_script) -set_ifndef( TOPT "${COMPILER_TOPT}") -set_ifndef( TOPT -Wl,-T) # Use this if the compiler driver doesn't set a value - -if(CONFIG_HAVE_CUSTOM_LINKER_SCRIPT) - set(LINKER_SCRIPT ${APPLICATION_SOURCE_DIR}/${CONFIG_CUSTOM_LINKER_SCRIPT}) - if(NOT EXISTS ${LINKER_SCRIPT}) - set(LINKER_SCRIPT ${CONFIG_CUSTOM_LINKER_SCRIPT}) - assert_exists(CONFIG_CUSTOM_LINKER_SCRIPT) - endif() -else() - # Try a board specific linker file - set(LINKER_SCRIPT ${BOARD_DIR}/linker.ld) - if(NOT EXISTS ${LINKER_SCRIPT}) - # If not available, try an SoC specific linker file - set(LINKER_SCRIPT ${SOC_DIR}/${ARCH}/${SOC_PATH}/linker.ld) - endif() -endif() - -if(NOT EXISTS ${LINKER_SCRIPT}) - message(FATAL_ERROR "Could not find linker script: '${LINKER_SCRIPT}'. Corrupted configuration?") -endif() - if(DEFINED BUILD_VERSION) set(build_version_argument "-DBUILD_VERSION=${BUILD_VERSION}") elseif(NOT ZEPHYR_GIT_INDEX) @@ -555,10 +519,11 @@ add_custom_command( -DOUT_FILE=${PROJECT_BINARY_DIR}/include/generated/version.h -DVERSION_TYPE=KERNEL -DVERSION_FILE=${ZEPHYR_BASE}/VERSION - -DKERNEL_VERSION_CUSTOMIZATION="${KERNEL_VERSION_CUSTOMIZATION}" + -DKERNEL_VERSION_CUSTOMIZATION="$" ${build_version_argument} -P ${ZEPHYR_BASE}/cmake/gen_version_h.cmake DEPENDS ${ZEPHYR_BASE}/VERSION ${git_dependency} + COMMAND_EXPAND_LISTS ) add_custom_target(version_h DEPENDS ${PROJECT_BINARY_DIR}/include/generated/version.h) @@ -569,10 +534,11 @@ if(EXISTS ${APPLICATION_SOURCE_DIR}/VERSION) -DOUT_FILE=${PROJECT_BINARY_DIR}/include/generated/app_version.h -DVERSION_TYPE=APP -DVERSION_FILE=${APPLICATION_SOURCE_DIR}/VERSION - -DAPP_VERSION_CUSTOMIZATION="${APP_VERSION_CUSTOMIZATION}" + -DAPP_VERSION_CUSTOMIZATION="$" ${build_version_argument} -P ${ZEPHYR_BASE}/cmake/gen_version_h.cmake DEPENDS ${APPLICATION_SOURCE_DIR}/VERSION ${git_dependency} + COMMAND_EXPAND_LISTS ) add_custom_target(app_version_h DEPENDS ${PROJECT_BINARY_DIR}/include/generated/app_version.h) add_dependencies(zephyr_interface app_version_h) @@ -615,12 +581,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) @@ -974,6 +942,29 @@ set(CMAKE_C_COMPILE_FEATURES ${compile_features_${CSTD}} PARENT_SCOPE) # @Intent: Configure linker scripts, i.e. generate linker scripts with variables substituted toolchain_ld_configure_files() +get_property(TOPT GLOBAL PROPERTY TOPT) +get_property(COMPILER_TOPT TARGET compiler PROPERTY linker_script) +set_ifndef( TOPT "${COMPILER_TOPT}") +set_ifndef( TOPT -Wl,-T) # Use this if the compiler driver doesn't set a value + +if(CONFIG_HAVE_CUSTOM_LINKER_SCRIPT) + set(LINKER_SCRIPT ${APPLICATION_SOURCE_DIR}/${CONFIG_CUSTOM_LINKER_SCRIPT}) + if(NOT EXISTS ${LINKER_SCRIPT}) + set(LINKER_SCRIPT ${CONFIG_CUSTOM_LINKER_SCRIPT}) + assert_exists(CONFIG_CUSTOM_LINKER_SCRIPT) + endif() +elseif(DEFINED BOARD_LINKER_SCRIPT) + set(LINKER_SCRIPT ${BOARD_LINKER_SCRIPT}) +elseif(DEFINED SOC_LINKER_SCRIPT) + set(LINKER_SCRIPT ${SOC_LINKER_SCRIPT}) +else() + find_package(Deprecated COMPONENTS SEARCHED_LINKER_SCRIPT) +endif() + +if(NOT EXISTS ${LINKER_SCRIPT}) + message(FATAL_ERROR "Could not find linker script: '${LINKER_SCRIPT}'. Corrupted configuration?") +endif() + if(CONFIG_USERSPACE) set(APP_SMEM_ALIGNED_LD "${PROJECT_BINARY_DIR}/include/generated/app_smem_aligned.ld") set(APP_SMEM_UNALIGNED_LD "${PROJECT_BINARY_DIR}/include/generated/app_smem_unaligned.ld") @@ -1123,7 +1114,7 @@ if(CONFIG_USERSPACE) ${PROCESS_GPERF} -i ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC_PRE} -o ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC} - -p "struct z_object" + -p "struct k_object" $<$:--verbose> DEPENDS kobj_prebuilt_hash_output_src_pre ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC_PRE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} @@ -1237,20 +1228,13 @@ 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 isrList.bin - COMMAND $ - $ - $${OUTPUT_FORMAT} - $binary - $.intList - $$ - $isrList.bin - $ + OUTPUT isr_tables.c COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/gen_isr_tables.py --output-source isr_tables.c --kernel $ - --intlist isrList.bin + --intlist-section .intList + --intlist-section intList $<$:--big-endian> $<$:--debug> ${GEN_ISR_TABLE_EXTRA_ARG} @@ -1322,7 +1306,7 @@ if(CONFIG_USERSPACE) ${PROCESS_GPERF} -i ${KOBJECT_HASH_OUTPUT_SRC_PRE} -o ${KOBJECT_HASH_OUTPUT_SRC} - -p "struct z_object" + -p "struct k_object" $<$:--verbose> DEPENDS kobj_hash_output_src_pre ${CMAKE_CURRENT_BINARY_DIR}/${KOBJECT_HASH_OUTPUT_SRC_PRE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} @@ -1640,18 +1624,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() @@ -1769,7 +1755,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") @@ -1780,12 +1765,13 @@ if(CONFIG_BUILD_OUTPUT_EXE) COMMENT "Building native simulator runner, and linking final executable" COMMAND ${MAKE} -f ${ZEPHYR_BASE}/scripts/native_simulator/Makefile all --warn-undefined-variables - -r NSI_CONFIG_FILE=${CMAKE_BINARY_DIR}/zephyr/NSI/nsi_config + -r NSI_CONFIG_FILE=${APPLICATION_BINARY_DIR}/zephyr/NSI/nsi_config # nsi_config is created by the board cmake file DEPENDS ${logical_target_for_zephyr_elf} 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) @@ -1802,25 +1788,32 @@ if(CONFIG_BUILD_OUTPUT_INFO_HEADER) ) endif() -if(CONFIG_CHECK_INIT_PRIORITIES) - if(CONFIG_CHECK_INIT_PRIORITIES_FAIL_ON_WARNING) - set(fail_on_warning "--fail-on-warning") - endif() - list(APPEND - post_build_commands - COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/check_init_priorities.py - --elf-file=${ZEPHYR_BINARY_DIR}/${KERNEL_ELF_NAME} - ${fail_on_warning} +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() @@ -1896,12 +1889,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 2aabb0a3299df17..df8b4cb4d42218d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -11,25 +11,13 @@ # add others as needed. # Do not use wildcard on all source yet -# * @galak @nashif +# +# +++++++++++ NOTE ++++++++++++++++ +# +# Please use the MAINTAINERS file to add yourself in an area or to add a new +# component or code. This file is going to be deprecated and currently only had +# entries that are not covered by the MAINTAINERS file. -/.github/ @nashif @stephanosio -/.github/workflows/ @galak @nashif -/MAINTAINERS.yml @MaureenHelm -/arch/arc/ @abrodkin @ruuddw @evgeniy-paltsev -/arch/arm/ @MaureenHelm @galak @ioannisg -/arch/arm/core/cortex_m/cmse/ @ioannisg -/arch/arm/include/cortex_m/cmse.h @ioannisg -/arch/arm/core/cortex_a_r/ @MaureenHelm @galak @ioannisg @bbolen @stephanosio -/arch/arm64/ @carlocaione -/arch/arm64/core/cortex_r/ @povergoing -/arch/arm64/core/xen/ @lorc @firscity -/arch/common/ @ioannisg @andyross -/arch/mips/ @frantony -/soc/arc/snps_*/ @abrodkin @ruuddw @evgeniy-paltsev -/soc/nios2/ @nashif -/soc/arm/ @MaureenHelm @galak @ioannisg -/soc/arm/arm/mps2/ @fvincenzo /soc/arm/aspeed/ @aspeeddylan /soc/arm/atmel_sam/common/*_sam4l_*.c @nandojve /soc/arm/atmel_sam/sam3x/ @ioannisg @@ -38,18 +26,9 @@ /soc/arm/atmel_sam/sam4s/ @fallrisk /soc/arm/atmel_sam/same70/ @nandojve /soc/arm/atmel_sam/samv71/ @nandojve -/soc/arm/cypress/ @ifyall @npal-cy /soc/arm/bcm*/ @sbranden -/soc/arm/gigadevice/ @nandojve /soc/arm/infineon_cat1/ @ifyall @npal-cy /soc/arm/infineon_xmc/ @parthitce -/soc/arm/nxp*/ @mmahadevan108 @dleach02 -/soc/arm/nxp_s32/ @manuargue -/soc/arm/nordic_nrf/ @anangl -/soc/arm/nuvoton_npcx/ @MulinChao @ChiHuaL -/soc/arm/nuvoton_numicro/ @ssekar15 -/soc/arm/quicklogic_eos_s3/ @fkokosinski @kgugala -/soc/arm/rpi_pico/ @yonsch /soc/arm/silabs_exx32/efm32pg1b/ @rdmeneze /soc/arm/silabs_exx32/efr32mg21/ @l-alfred /soc/arm/st_stm32/ @erwango @@ -63,37 +42,11 @@ /soc/arm/xilinx_zynq7000/ @ibirnbaum /soc/arm/xilinx_zynqmp/ @stephanosio /soc/arm/renesas_rcar/ @aaillet -/soc/arm64/ @carlocaione -/soc/arm64/qemu_cortex_a53/ @carlocaione -/soc/arm64/bcm_vk/ @abhishek-brcm -/soc/arm64/nxp_layerscape/ @JiafeiPan -/soc/arm64/xenvm/ @lorc @firscity -/soc/arm64/nxp_imx/ @MrVan @JiafeiPan -/soc/arm64/arm/ @povergoing -/soc/arm64/arm/fvp_aemv8a/ @carlocaione -/soc/arm64/intel_socfpga/* @siclim -/soc/arm64/renesas_rcar/ @lorc @xakep-amatop -/soc/Kconfig @tejlmand @galak @nashif @nordicjm -/submanifests/* @mbolivar-ampere -/arch/x86/ @jhedberg @nashif -/arch/nios2/ @nashif -/arch/posix/ @aescolar @daor-oti -/arch/riscv/ @kgugala @pgielda -/soc/mips/ @frantony -/soc/posix/ @aescolar @daor-oti -/soc/riscv/ @kgugala @pgielda /soc/riscv/openisa*/ @dleach02 /soc/riscv/riscv-privileged/andes_v5/ @cwshu @kevinwang821020 @jimmyzhe /soc/riscv/riscv-privileged/neorv32/ @henrikbrixandersen /soc/riscv/riscv-privileged/gd32vf103/ @soburi /soc/riscv/riscv-privileged/niosv/ @sweeaun -/soc/x86/ @dcpleung @nashif -/arch/xtensa/ @dcpleung @andyross @nashif -/soc/xtensa/ @dcpleung @andyross @nashif -/arch/sparc/ @julius-barendt -/soc/sparc/ @julius-barendt -/boards/arc/ @abrodkin @ruuddw @evgeniy-paltsev -/boards/arm/ @MaureenHelm @galak /boards/arm/96b_argonkey/ @avisconti /boards/arm/96b_avenger96/ @Mani-Sadhasivam /boards/arm/96b_carbon/ @idlethread @@ -102,7 +55,6 @@ /boards/arm/96b_neonkey/ @Mani-Sadhasivam /boards/arm/96b_stm32_sensor_mez/ @Mani-Sadhasivam /boards/arm/96b_wistrio/ @Mani-Sadhasivam -/boards/arm/arduino_due/ @ioannisg /boards/arm/acn52832/ @sven-hm /boards/arm/arduino_mkrzero/ @soburi /boards/arm/bbc_microbit_v2/ @LingaoM @@ -168,15 +120,7 @@ /boards/arm/rcar_*/ @aaillet /boards/arm/ubx_bmd345eval_nrf52840/ @Navin-Sankar @brec-u-blox /boards/arm/nrf5340_audio_dk_nrf5340 @koffes @alexsven @erikrobstad @rick1082 @gWacey -/boards/common/ @mbolivar-ampere -/boards/deprecated.cmake @tejlmand -/boards/mips/ @frantony -/boards/nios2/ @nashif -/boards/nios2/altera_max10/ @nashif /boards/arm/stm32_min_dev/ @sidcha -/boards/posix/ @aescolar @daor-oti -/boards/posix/nrf52_bsim/ @aescolar @wopu-ot -/boards/riscv/ @kgugala @pgielda /boards/riscv/rv32m1_vega/ @dleach02 /boards/riscv/adp_xc7k_ae350/ @cwshu @kevinwang821020 @jimmyzhe /boards/riscv/longan_nano/ @soburi @@ -184,16 +128,12 @@ /boards/riscv/niosv*/ @sweeaun /boards/riscv/sparkfun_red_v_things_plus/ @soburi /boards/riscv/stamp_c3/ @soburi -/boards/shields/ @erwango /boards/shields/atmel_rf2xx/ @nandojve /boards/shields/esp_8266/ @nandojve /boards/shields/inventek_eswifi/ @nandojve -/boards/x86/ @dcpleung @nashif -/boards/x86/acrn/ @enjiamai -/boards/xtensa/ @nashif @dcpleung /boards/xtensa/odroid_go/ @ydamigos /boards/xtensa/nxp_adsp_imx8/ @iuliana-prodan @dbaluta -/boards/sparc/ @julius-barendt +/boards/xtensa/kincony_kc868_a32/ @bbilas /boards/arm64/qemu_cortex_a53/ @carlocaione /boards/arm64/bcm958402m2_a72/ @abhishek-brcm /boards/arm64/mimx8mm_evk/ @MrVan @JiafeiPan @@ -205,27 +145,15 @@ /boards/arm64/fvp_baser_aemv8r/ @povergoing /boards/arm64/fvp_base_revc_2xaemv8a/ @carlocaione /boards/arm64/intel_socfpga_agilex_socdk/ @siclim @ngboonkhai -/boards/arm64/intel_socfpga_agilex5_socdk/ @chongteikheng +/boards/arm64/intel_socfpga_agilex5_socdk/ @teikheng @gdengi /boards/arm64/rcar_*/ @lorc @xakep-amatop -/boards/Kconfig @tejlmand @galak @nashif @nordicjm # All cmake related files -/cmake/ @tejlmand @nashif -/cmake/*/arcmwdt/ @abrodkin @evgeniy-paltsev @tejlmand -/CMakeLists.txt @tejlmand @nashif -/doc/ @carlescufi /doc/develop/tools/coccinelle.rst @himanshujha199640 @JuliaLawall /doc/services/device_mgmt/smp_protocol.rst @de-nordic @nordicjm /doc/services/device_mgmt/smp_groups/ @de-nordic @nordicjm /doc/services/sensing/ @lixuzha @ghu0510 @qianruh /doc/CMakeLists.txt @carlescufi /doc/_scripts/ @carlescufi -/doc/connectivity/bluetooth/ @alwa-nordic @jhedberg @Vudentz -/doc/connectivity/networking/conn_mgr @carlescufi @glarsennordic -/doc/build/dts/ @galak @mbolivar-ampere -/doc/build/sysbuild/ @tejlmand @nordicjm -/doc/hardware/peripherals/canbus/ @alexanderwachter @henrikbrixandersen -/doc/security/ @ceolin @d3zd3z -/drivers/debug/ @nashif /drivers/*/*sam4l* @nandojve /drivers/*/*cc13xx_cc26xx* @bwitherspoon /drivers/*/*gd32* @nandojve @@ -239,28 +167,24 @@ /drivers/*/*ifx_cat1* @ifyall @npal-cy /drivers/*/*neorv32* @henrikbrixandersen /drivers/*/*_s32* @manuargue -/drivers/adc/ @anangl /drivers/adc/adc_ads1x1x.c @XenuIsWatching /drivers/adc/adc_stm32.c @cybertale /drivers/adc/adc_rpi_pico.c @soburi /drivers/adc/*ads114s0x* @benediktibk /drivers/adc/*max11102_17* @benediktibk +/drivers/adc/adc_ad5592.c @bbilas /drivers/audio/*nrfx* @anangl /drivers/auxdisplay/*pt6314* @xingrz /drivers/auxdisplay/* @thedjnK /drivers/bbram/* @yperess @sjg20 @jackrosenthal /drivers/bluetooth/ @alwa-nordic @jhedberg @Vudentz /drivers/bluetooth/hci/hci_esp32.c @sylvioalves -/drivers/cache/ @carlocaione -/drivers/syscon/ @carlocaione @yperess -/drivers/can/ @alexanderwachter @henrikbrixandersen /drivers/can/*mcp2515* @karstenkoenig /drivers/can/*rcar* @aaillet /drivers/clock_control/*agilex* @siclim @gdengi /drivers/clock_control/*nrf* @nordic-krch /drivers/clock_control/*esp32* @extremegtx @sylvioalves /drivers/clock_control/*cpg_mssr* @aaillet -/drivers/counter/ @nordic-krch /drivers/console/ipm_console.c @finikorg /drivers/console/semihost_console.c @luozhongyao /drivers/console/jailhouse_debug_console.c @MrVan @@ -272,8 +196,8 @@ /drivers/crypto/*nrf_ecb* @maciekfabia @anangl /drivers/display/*rm68200* @mmahadevan108 /drivers/display/display_ili9342c.* @extremegtx -/drivers/dac/ @martinjaeger /drivers/dac/*ad56xx* @benediktibk +/drivers/dac/dac_ad5592.c @bbilas /drivers/dai/ @kv2019i @marcinszkudlinski @abonislawski /drivers/dai/intel/ @kv2019i @marcinszkudlinski @abonislawski /drivers/dai/intel/ssp/ @kv2019i @marcinszkudlinski @abonislawski @@ -288,34 +212,29 @@ /drivers/dma/*intel_adsp* @teburd @abonislawski /drivers/dma/*rpi_pico* @soburi /drivers/dma/*xmc4xxx* @talih0 -/drivers/edac/ @finikorg -/drivers/eeprom/ @henrikbrixandersen /drivers/eeprom/eeprom_stm32.c @KwonTae-young /drivers/entropy/*b91* @andy-liu-telink /drivers/entropy/*bt_hci* @JordanYates /drivers/entropy/*rv32m1* @dleach02 /drivers/entropy/*litex* @mateusz-holenko @kgugala @pgielda -/drivers/espi/ @albertofloyd @franciscomunoz @sjvasanth1 -/drivers/ethernet/ @tbursztyka @jukkar /drivers/ethernet/*dwmac* @npitre /drivers/ethernet/*stm32* @Nukersson @lochej /drivers/ethernet/*w5500* @parthitce /drivers/ethernet/*xlnx_gem* @ibirnbaum /drivers/ethernet/*smsc91x* @sgrrzhf /drivers/ethernet/*adin2111* @GeorgeCGV +/drivers/ethernet/*oa_tc6* @lmajewski +/drivers/ethernet/*lan865x* @lmajewski /drivers/ethernet/phy/ @rlubos @tbursztyka @arvinf @jukkar /drivers/ethernet/phy/*adin2111* @GeorgeCGV -/drivers/mdio/ @rlubos @tbursztyka @arvinf /drivers/mdio/*adin2111* @GeorgeCGV -/drivers/flash/ @nashif @de-nordic /drivers/flash/*stm32_qspi* @lmajewski /drivers/flash/*b91* @andy-liu-telink /drivers/flash/*cadence* @ngboonkhai /drivers/flash/*cc13xx_cc26xx* @pepe2k /drivers/flash/*nrf* @de-nordic /drivers/flash/*esp32* @sylvioalves -/drivers/fpga/ @tgorochowik @kgugala -/drivers/gpio/ @mnkp +/drivers/flash/flash_cadence_nand* @nbalabak /drivers/gpio/*b91* @andy-liu-telink /drivers/gpio/*lmp90xxx* @henrikbrixandersen /drivers/gpio/*nct38xx* @MulinChao @ChiHuaL @@ -329,7 +248,7 @@ /drivers/gpio/*bd8lb600fs* @benediktibk /drivers/gpio/*pcal64xxa* @benediktibk /drivers/gpio/gpio_altera_pio.c @shilinte -/drivers/hwinfo/ @alexanderwachter +/drivers/gpio/gpio_ad5592.c @bbilas /drivers/i2c/i2c_common.c @sjg20 /drivers/i2c/i2c_emul.c @sjg20 /drivers/i2c/i2c_ite_enhance.c @GTLin08 @@ -344,7 +263,6 @@ /drivers/i2s/*litex* @mateusz-holenko @kgugala @pgielda /drivers/i2s/i2s_ll_stm32* @avisconti /drivers/i2s/*nrfx* @anangl -/drivers/i3c/ @dcpleung /drivers/i3c/i3c_cdns.c @XenuIsWatching /drivers/ieee802154/ @rlubos @tbursztyka @jukkar @fgrandel /drivers/ieee802154/*b91* @andy-liu-telink @@ -365,31 +283,22 @@ /drivers/ipm/ipm_stm32_hsem.c @cameled /drivers/ipm/ipm_esp32.c @uLipe /drivers/ipm/ipm_ivshmem.c @uLipe -/drivers/kscan/ @VenkatKotakonda @franciscomunoz @sjvasanth1 /drivers/kscan/*xec* @franciscomunoz @sjvasanth1 /drivers/kscan/*ft5336* @MaureenHelm /drivers/kscan/*ht16k33* @henrikbrixandersen -/drivers/led/ @Mani-Sadhasivam /drivers/led_strip/ @mbolivar-ampere -/drivers/lora/ @Mani-Sadhasivam -/drivers/mbox/ @carlocaione -/drivers/misc/ @tejlmand +/drivers/mfd/mfd_ad5592.c @bbilas +/drivers/mfd/mfd_max20335.c @bbilas /drivers/misc/ft8xx/ @hubertmis -/drivers/mm/ @dcpleung /drivers/modem/hl7800.c @rerickson1 /drivers/modem/simcom-sim7080.c @lgehreke /drivers/modem/simcom-sim7080.h @lgehreke /drivers/modem/Kconfig.hl7800 @rerickson1 /drivers/modem/Kconfig.simcom-sim7080 @lgehreke -/drivers/pcie/ @dcpleung @nashif @jhedberg -/drivers/peci/ @albertofloyd @franciscomunoz @sjvasanth1 -/drivers/pinctrl/ @gmarull /drivers/pinctrl/*esp32* @sylvioalves /drivers/pinctrl/*it8xxx2* @ite -/drivers/pm_cpu_ops/ @carlocaione @gdengi /drivers/pm_cpu_ops/psci_shell.c @nbalabak @gdengi /drivers/power_domain/ @ceolin -/drivers/ps2/ @franciscomunoz @sjvasanth1 /drivers/ps2/*xec* @franciscomunoz @sjvasanth1 /drivers/ps2/*npcx* @MulinChao @ChiHuaL /drivers/pwm/*b91* @andy-liu-telink @@ -407,13 +316,12 @@ /drivers/pwm/*rcar* @aaillet /drivers/pwm/*max31790* @benediktibk /drivers/regulator/* @gmarull +/drivers/regulator/regulator_max20335.c @bbilas /drivers/regulator/regulator_pca9420.c @danieldegrasse /drivers/regulator/regulator_rpi_pico.c @soburi /drivers/regulator/regulator_shell.c @danieldegrasse -/drivers/reset/ @andrei-edward-popa /drivers/reset/reset_intel_socfpga.c @nbalabak /drivers/reset/Kconfig.intel_socfpga @nbalabak -/drivers/sensor/ @MaureenHelm /drivers/sensor/ams_iAQcore/ @alexanderwachter /drivers/sensor/ens210/ @alexanderwachter /drivers/sensor/grow_r502a/ @DineshDK03 @@ -444,28 +352,21 @@ /drivers/serial/*numicro* @ssekar15 /drivers/serial/*apbuart* @julius-barendt /drivers/serial/*rcar* @aaillet -/drivers/serial/Kconfig.test @str4t0m -/drivers/serial/serial_test.c @str4t0m /drivers/serial/Kconfig.xen @lorc @firscity /drivers/serial/uart_hvc_xen.c @lorc @firscity /drivers/serial/uart_hvc_xen_consoleio.c @lorc @firscity /drivers/serial/Kconfig.it8xxx2 @GTLin08 /drivers/serial/uart_ite_it8xxx2.c @GTLin08 -/drivers/smbus/ @finikorg -/drivers/sip_svc/ @maheshraotm -/drivers/disk/ @jfischer-no +/drivers/serial/*intel_lw* @shilinte /drivers/disk/sdmmc_sdhc.h @JunYangNXP /drivers/disk/sdmmc_stm32.c @anthonybrandon -/drivers/net/ @rlubos @tbursztyka @jukkar /drivers/ptp_clock/ @tbursztyka @jukkar -/drivers/spi/ @tbursztyka /drivers/spi/*b91* @andy-liu-telink /drivers/spi/spi_rv32m1_lpspi* @karstenkoenig /drivers/spi/*esp32* @sylvioalves /drivers/spi/*pl022* @soburi /drivers/sdhc/ @danieldegrasse -/drivers/timer/*apic* @dcpleung @nashif -/drivers/timer/apic_tsc.c @andyross +/drivers/sdhc/sdhc_cdns* @roymurlidhar @tanmaykathpalia /drivers/timer/*arm_arch* @carlocaione /drivers/timer/*cortex_m_systick* @anangl /drivers/timer/*altera_avalon* @nashif @@ -485,10 +386,7 @@ /drivers/timer/*rv32m1_lptmr* @mbolivar /drivers/timer/*nrf_rtc* @anangl /drivers/timer/*hpet* @dcpleung -/drivers/usb/ @jfischer-no /drivers/usb/device/usb_dc_stm32.c @ydamigos @loicpoulain -/drivers/usb_c/ @sambhurst -/drivers/video/ @loicpoulain /drivers/i2c/*b91* @andy-liu-telink /drivers/i2c/i2c_ll_stm32* @ydamigos /drivers/i2c/i2c_rv32m1_lpi2c* @henrikbrixandersen @@ -496,7 +394,6 @@ /drivers/i2c/i2c_dw* @dcpleung /drivers/i2c/*tca954x* @kurddt /drivers/*/*xec* @franciscomunoz @albertofloyd @sjvasanth1 -/drivers/w1/ @str4t0m /drivers/watchdog/*gecko* @oanerer /drivers/watchdog/*sifive* @katsuster /drivers/watchdog/wdt_handlers.c @dcpleung @nashif @@ -505,14 +402,12 @@ /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/ @rlubos @tbursztyka @jukkar /drivers/wifi/esp_at/ @mniestroj /drivers/wifi/eswifi/ @loicpoulain @nandojve /drivers/wifi/winc1500/ @kludentwo /drivers/virtualization/ @tbursztyka -/drivers/xen/ @lorc @firscity /dts/arc/ @abrodkin @ruuddw @iriszzw @evgeniy-paltsev /dts/arm/acsip/ @NorthernDean /dts/arm/aspeed/ @aspeeddylan @@ -525,10 +420,9 @@ /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/ @carlocaione /dts/arm64/armv8-r.dtsi @povergoing /dts/arm64/intel/*intel_socfpga* @siclim /dts/arm64/nxp/ @JiafeiPan @@ -555,7 +449,6 @@ /dts/arm/silabs/efm32pg1b* @rdmeneze /dts/arm/silabs/efr32mg21* @l-alfred /dts/arm/silabs/efr32fg13* @yonsch -/dts/riscv/ @kgugala @pgielda /dts/riscv/ite/ @ite /dts/riscv/microchip/microchip-miv.dtsi @galak /dts/riscv/openisa/rv32m1* @dleach02 @@ -568,13 +461,10 @@ /dts/arm/armv7-r.dtsi @bbolen @stephanosio /dts/arm/xilinx/ @bbolen @stephanosio /dts/arm/renesas/rcar/ @aaillet -/dts/x86/ @jhedberg /dts/xtensa/xtensa.dtsi @ydamigos /dts/xtensa/intel/ @dcpleung /dts/xtensa/espressif/ @sylvioalves /dts/xtensa/nxp/ @iuliana-prodan @dbaluta -/dts/sparc/ @julius-barendt -/dts/bindings/ @galak /dts/bindings/can/ @alexanderwachter @henrikbrixandersen /dts/bindings/i2c/zephyr*i2c-emul*.yaml @sjg20 /dts/bindings/adc/st*stm32-adc.yaml @cybertale @@ -606,7 +496,6 @@ /dts/bindings/ethernet/*gem.yaml @ibirnbaum /dts/bindings/auxdisplay/*pt6314.yaml @xingrz /dts/bindings/auxdisplay/* @thedjnK -/dts/posix/ @aescolar @daor-oti /dts/bindings/sensor/*bme680* @BoschSensortec /dts/bindings/sensor/*ina23* @bbilas /dts/bindings/sensor/st* @avisconti @@ -621,338 +510,3 @@ /dts/bindings/gpio/*ads114s0x* @benediktibk /dts/bindings/pwm/*max31790* @benediktibk /dts/bindings/dac/*ad56* @benediktibk -/dts/common/ @galak -/include/ @nashif @carlescufi @galak @MaureenHelm -/include/zephyr/drivers/*/*litex* @mateusz-holenko @kgugala @pgielda -/include/zephyr/drivers/adc.h @anangl -/include/zephyr/drivers/adc/ads114s0x.h @benediktibk -/include/zephyr/drivers/auxdisplay.h @thedjnK -/include/zephyr/drivers/can.h @alexanderwachter @henrikbrixandersen -/include/zephyr/drivers/can/ @alexanderwachter @henrikbrixandersen -/include/zephyr/drivers/counter.h @nordic-krch -/include/zephyr/drivers/dac.h @martinjaeger -/include/zephyr/drivers/espi.h @albertofloyd @franciscomunoz @sjvasanth1 -/include/zephyr/drivers/bluetooth/ @alwa-nordic @jhedberg @Vudentz -/include/zephyr/drivers/flash.h @nashif @carlescufi @galak @MaureenHelm @de-nordic -/include/zephyr/drivers/i2c_emul.h @sjg20 -/include/zephyr/drivers/i3c.h @dcpleung -/include/zephyr/drivers/i3c/ @dcpleung -/include/zephyr/drivers/led/ht16k33.h @henrikbrixandersen -/include/zephyr/drivers/interrupt_controller/ @dcpleung @nashif -/include/zephyr/drivers/interrupt_controller/gic.h @stephanosio -/include/zephyr/drivers/modem/hl7800.h @rerickson1 -/include/zephyr/drivers/pcie/ @dcpleung -/include/zephyr/drivers/hwinfo.h @alexanderwachter -/include/zephyr/drivers/led.h @Mani-Sadhasivam -/include/zephyr/drivers/led_strip.h @mbolivar-ampere -/include/zephyr/drivers/sensor.h @MaureenHelm -/include/zephyr/drivers/smbus.h @finikorg -/include/zephyr/drivers/spi.h @tbursztyka -/include/zephyr/drivers/sip_svc/ @maheshraotm -/include/zephyr/drivers/lora.h @Mani-Sadhasivam -/include/zephyr/drivers/peci.h @albertofloyd @franciscomunoz @sjvasanth1 -/include/zephyr/drivers/pm_cpu_ops.h @carlocaione -/include/zephyr/drivers/pm_cpu_ops/ @carlocaione -/include/zephyr/drivers/w1.h @str4t0m -/include/zephyr/drivers/pwm/max31790.h @benediktibk -/include/zephyr/app_memory/ @dcpleung -/include/zephyr/arch/arc/ @abrodkin @ruuddw @evgeniy-paltsev -/include/zephyr/arch/arc/arch.h @abrodkin @ruuddw @evgeniy-paltsev -/include/zephyr/arch/arc/v2/irq.h @abrodkin @ruuddw @evgeniy-paltsev -/include/zephyr/arch/arm @MaureenHelm @galak @ioannisg -/include/zephyr/arch/arm/cortex_a_r/ @stephanosio -/include/zephyr/arch/arm64/ @carlocaione -/include/zephyr/arch/arm64/cortex_r/ @povergoing -/include/zephyr/arch/arm/irq.h @carlocaione -/include/zephyr/arch/mips/ @frantony -/include/zephyr/arch/nios2/ @nashif -/include/zephyr/arch/nios2/arch.h @nashif -/include/zephyr/arch/posix/ @aescolar @daor-oti -/include/zephyr/arch/riscv/ @kgugala @pgielda -/include/zephyr/arch/x86/ @jhedberg @dcpleung -/include/zephyr/arch/common/ @andyross @nashif -/include/zephyr/arch/xtensa/ @andyross @dcpleung -/include/zephyr/arch/sparc/ @julius-barendt -/include/zephyr/sys/atomic.h @andyross -/include/zephyr/bluetooth/ @alwa-nordic @jhedberg @Vudentz @sjanc -/include/zephyr/bluetooth/audio/ @jhedberg @Vudentz @Thalley -/include/zephyr/cache.h @carlocaione @andyross -/include/zephyr/canbus/ @alexanderwachter @henrikbrixandersen -/include/zephyr/tracing/ @nashif -/include/zephyr/debug/ @nashif -/include/zephyr/debug/coredump.h @dcpleung -/include/zephyr/debug/gdbstub.h @ceolin -/include/zephyr/device.h @tbursztyka @nashif -/include/zephyr/devicetree.h @galak -/include/zephyr/devicetree/can.h @henrikbrixandersen -/include/zephyr/dt-bindings/clock/kinetis_mcg.h @henrikbrixandersen -/include/zephyr/dt-bindings/clock/kinetis_scg.h @henrikbrixandersen -/include/zephyr/dt-bindings/ethernet/xlnx_gem.h @ibirnbaum -/include/zephyr/dt-bindings/pcie/ @dcpleung -/include/zephyr/dt-bindings/pinctrl/esp* @sylvioalves -/include/zephyr/dt-bindings/pwm/*it8xxx2* @RuibinChang -/include/zephyr/dt-bindings/usb/usb.h @galak -/include/zephyr/dt-bindings/adc/ads114s0x_adc.h @benediktibk -/include/zephyr/drivers/emul.h @sjg20 -/include/zephyr/fs/ @nashif @de-nordic -/include/zephyr/init.h @nashif @andyross -/include/zephyr/irq.h @dcpleung @nashif @andyross -/include/zephyr/irq_offload.h @dcpleung @nashif @andyross -/include/zephyr/kernel.h @dcpleung @nashif @andyross -/include/zephyr/kernel_version.h @dcpleung @nashif @andyross -/include/zephyr/linker/app_smem*.ld @dcpleung @nashif -/include/zephyr/linker/ @dcpleung @nashif @andyross -/include/zephyr/logging/ @nordic-krch -/include/zephyr/lorawan/lorawan.h @Mani-Sadhasivam -/include/zephyr/mgmt/osdp.h @sidcha -/include/zephyr/mgmt/mcumgr/ @nordicjm -/include/zephyr/net/ @rlubos @tbursztyka @jukkar -/include/zephyr/net/buf.h @jhedberg @tbursztyka @rlubos @jukkar -/include/zephyr/net/coap*.h @rlubos -/include/zephyr/net/conn_mgr*.h @rlubos @glarsennordic @jukkar -/include/zephyr/net/gptp.h @rlubos @jukkar @fgrandel -/include/zephyr/net/ieee802154*.h @rlubos @tbursztyka @jukkar @fgrandel -/include/zephyr/net/lwm2m*.h @rlubos -/include/zephyr/net/mqtt.h @rlubos -/include/zephyr/net/mqtt_sn.h @rlubos @BeckmaR -/include/zephyr/net/net_pkt_filter.h @npitre -/include/zephyr/posix/ @cfreidt -/include/zephyr/pm/pm.h @nashif @ceolin -/include/zephyr/drivers/ptp_clock.h @tbursztyka @jukkar -/include/zephyr/rtio/ @teburd -/include/zephyr/sensing/ @lixuzha @ghu0510 @qianruh -/include/zephyr/shared_irq.h @dcpleung @nashif @andyross -/include/zephyr/shell/ @jakub-uC @nordic-krch -/include/zephyr/shell/shell_mqtt.h @ycsin -/include/zephyr/sw_isr_table.h @dcpleung @nashif @andyross -/include/zephyr/sd/ @danieldegrasse -/include/zephyr/sip_svc/ @maheshraotm -/include/zephyr/sys_clock.h @dcpleung @nashif @andyross -/include/zephyr/sys/sys_io.h @dcpleung @nashif @andyross -/include/zephyr/sys/kobject.h @dcpleung @nashif -/include/zephyr/toolchain.h @dcpleung @andyross @nashif -/include/zephyr/toolchain/ @dcpleung @nashif @andyross -/include/zephyr/zephyr.h @dcpleung @nashif @andyross -/kernel/ @dcpleung @nashif @andyross -/lib/cpp/ @stephanosio -/lib/smf/ @sambhurst -/lib/util/ @carlescufi @jakub-uC -/lib/util/fnmatch/ @carlescufi @jakub-uC -/lib/open-amp/ @arnopo -/lib/os/ @dcpleung @nashif @andyross -/lib/os/cbprintf_packaged.c @npitre -/lib/posix/ @cfriedt -/lib/posix/getopt/ @jakub-uC -/subsys/portability/ @nashif -/subsys/sensing/ @lixuzha @ghu0510 @qianruh -/lib/libc/ @nashif -/lib/libc/arcmwdt/ @abrodkin @ruuddw @evgeniy-paltsev -/misc/ @tejlmand -/modules/ @nashif -/modules/canopennode/ @henrikbrixandersen -/modules/mbedtls/ @ceolin @d3zd3z -/modules/hal_gigadevice/ @nandojve -/modules/hal_nordic/nrf_802154/ @jciupis -/modules/trusted-firmware-m/ @microbuilder -/kernel/device.c @andyross @nashif -/kernel/idle.c @andyross @nashif -/samples/ @nashif -/samples/application_development/sysbuild/ @tejlmand @nordicjm -/samples/basic/minimal/ @carlescufi -/samples/basic/servo_motor/boards/*microbit* @jhe -/samples/bluetooth/ @jhedberg @Vudentz @alwa-nordic @sjanc -/samples/compression/ @Navin-Sankar -/samples/drivers/can/ @alexanderwachter @henrikbrixandersen -/samples/drivers/clock_control_litex/ @mateusz-holenko @kgugala @pgielda -/samples/drivers/eeprom/ @henrikbrixandersen -/samples/drivers/ht16k33/ @henrikbrixandersen -/samples/drivers/lora/ @Mani-Sadhasivam -/samples/drivers/smbus/ @finikorg -/samples/subsys/lorawan/ @Mani-Sadhasivam -/samples/modules/canopennode/ @henrikbrixandersen -/samples/net/ @rlubos @tbursztyka @jukkar -/samples/net/cloud/tagoio_http_post/ @nandojve -/samples/net/dns_resolve/ @rlubos @tbursztyka @jukkar -/samples/net/gptp/ @rlubos @jukkar @fgrandel -/samples/net/lwm2m_client/ @rlubos -/samples/net/mqtt_publisher/ @rlubos -/samples/net/mqtt_sn_publisher/ @rlubos @BeckmaR -/samples/net/sockets/coap_*/ @rlubos -/samples/net/sockets/ @rlubos @tbursztyka @jukkar -/samples/sensor/ @MaureenHelm -/samples/shields/ @avisconti -/samples/subsys/ipc/ipc_service/icmsg @emob-nordic -/samples/subsys/logging/ @nordic-krch @jakub-uC -/samples/subsys/logging/syst/ @dcpleung -/samples/subsys/shell/ @jakub-uC @nordic-krch @gdengi -/samples/subsys/sip_svc/ @maheshraotm -/samples/subsys/mgmt/mcumgr/ @de-nordic @nordicjm -/samples/subsys/mgmt/updatehub/ @nandojve @otavio -/samples/subsys/mgmt/osdp/ @sidcha -/samples/subsys/usb/ @jfischer-no -/samples/subsys/usb_c/ @sambhurst -/samples/subsys/pm/ @nashif @ceolin -/samples/subsys/sensing/ @lixuzha @ghu0510 @qianruh -/samples/tfm_integration/ @microbuilder -/samples/userspace/ @dcpleung @nashif -/scripts/release/bug_bash.py @cfriedt -/scripts/coccicheck @himanshujha199640 @JuliaLawall -/scripts/coccinelle/ @himanshujha199640 @JuliaLawall -/scripts/coredump/ @dcpleung -/scripts/footprint/ @nashif -/scripts/kconfig/ @ulfalizer -/scripts/logging/dictionary/ @dcpleung -/scripts/native_simulator/ @aescolar -/scripts/pylib/twister/expr_parser.py @nashif -/scripts/schemas/twister/ @nashif -/scripts/build/gen_app_partitions.py @dcpleung @nashif -scripts/build/gen_image_info.py @tejlmand -/scripts/get_maintainer.py @nashif -/scripts/dts/ @mbolivar-ampere @galak -/scripts/release/ @nashif -/scripts/ci/ @nashif -/scripts/ci/check_compliance.py @nashif @carlescufi -/arch/x86/gen_gdt.py @dcpleung @nashif -/arch/x86/gen_idt.py @dcpleung @nashif -/scripts/build/gen_kobject_list.py @dcpleung @nashif -/scripts/build/gen_kobject_placeholders.py @dcpleung -/scripts/build/gen_syscalls.py @dcpleung @nashif -/scripts/list_boards.py @mbolivar-ampere -/scripts/build/process_gperf.py @dcpleung @nashif -/scripts/build/gen_relocate_app.py @dcpleung -/scripts/generate_usb_vif/ @madhurimaparuchuri -/scripts/requirements*.txt @mbolivar-ampere @galak @nashif -/scripts/tests/build/test_subfolder_list.py @rmstoi -/scripts/tracing/ @nashif -/scripts/pylib/twister/ @nashif -/scripts/twister @nashif -/scripts/series-push-hook.sh @erwango -/scripts/utils/pinctrl_nrf_migrate.py @gmarull -/scripts/utils/migrate_mcumgr_kconfigs.py @de-nordic -/scripts/west_commands/ @mbolivar-ampere -/scripts/west_commands/blobs.py @carlescufi -/scripts/west_commands/fetchers/ @carlescufi -/scripts/west_commands/runners/gd32isp.py @mbolivar-ampere @nandojve -/scripts/west_commands/tests/test_gd32isp.py @mbolivar-ampere @nandojve -/scripts/west-commands.yml @mbolivar-ampere -/scripts/zephyr_module.py @tejlmand -/scripts/build/uf2conv.py @petejohanson -/scripts/build/user_wordsize.py @cfriedt -/scripts/valgrind.supp @aescolar @daor-oti -/share/sysbuild/ @tejlmand @nordicjm -/share/zephyr-package/ @tejlmand -/share/zephyrunittest-package/ @tejlmand -/subsys/bluetooth/ @alwa-nordic @jhedberg @Vudentz -/subsys/bluetooth/audio/ @jhedberg @Vudentz @Thalley @sjanc -/subsys/bluetooth/controller/ @carlescufi @cvinayak @thoh-ot @kruithofa -/subsys/bluetooth/host/ @alwa-nordic @jhedberg @Vudentz @sjanc -/subsys/bluetooth/mesh/ @jhedberg @PavelVPV @Vudentz @LingaoM -/subsys/canbus/ @alexanderwachter @henrikbrixandersen -/subsys/debug/ @nashif -/subsys/debug/coredump/ @dcpleung -/subsys/debug/gdbstub/ @ceolin -/subsys/debug/gdbstub.c @ceolin -/subsys/dfu/ @de-nordic @nordicjm -/subsys/disk/ @jfischer-no -/subsys/dsp/ @yperess -/subsys/tracing/ @nashif -/subsys/debug/asan_hacks.c @aescolar @daor-oti -/subsys/demand_paging/ @dcpleung @nashif -/subsys/emul/ @sjg20 -/subsys/fb/ @jfischer-no -/subsys/fs/ @nashif -/subsys/fs/nvs/ @Laczen -/subsys/ipc/ @carlocaione -/subsys/ipc/ipc_service/*/*icmsg* @emob-nordic -/subsys/logging/ @nordic-krch -/subsys/logging/backends/log_backend_net.c @nordic-krch @rlubos @jukkar -/subsys/lorawan/ @Mani-Sadhasivam -/subsys/mgmt/ec_host_cmd/ @jettr -/subsys/mgmt/mcumgr/ @carlescufi @de-nordic @nordicjm -/subsys/mgmt/hawkbit/ @Navin-Sankar -/subsys/mgmt/updatehub/ @nandojve @otavio -/subsys/mgmt/osdp/ @sidcha -/subsys/modbus/ @jfischer-no -/subsys/net/buf.c @jhedberg @tbursztyka @rlubos @jukkar -/subsys/net/conn_mgr/ @rlubos @glarsennordic @jukkar -/subsys/net/ip/ @rlubos @tbursztyka @jukkar -/subsys/net/lib/ @rlubos @tbursztyka @jukkar -/subsys/net/lib/dns/ @rlubos @tbursztyka @cfriedt @jukkar -/subsys/net/lib/lwm2m/ @rlubos -/subsys/net/lib/config/ @rlubos @tbursztyka @jukkar -/subsys/net/lib/mqtt/ @rlubos -/subsys/net/lib/mqtt_sn/ @rlubos @BeckmaR -/subsys/net/lib/coap/ @rlubos -/subsys/net/lib/sockets/socketpair.c @cfriedt -/subsys/net/lib/sockets/ @rlubos @tbursztyka @jukkar -/subsys/net/lib/tls_credentials/ @rlubos -/subsys/net/l2/ @rlubos @tbursztyka @jukkar -/subsys/net/l2/ethernet/gptp/ @rlubos @jukkar @fgrandel -/subsys/net/l2/ieee802154/ @rlubos @tbursztyka @jukkar @fgrandel -/subsys/net/l2/canbus/ @alexanderwachter -/subsys/net/pkt_filter/ @npitre -/subsys/net/*/openthread/ @rlubos -/subsys/pm/ @nashif @ceolin -/subsys/random/ @dleach02 -/subsys/shell/ @jakub-uC @nordic-krch -/subsys/shell/backends/shell_mqtt.c @ycsin -/subsys/sd/ @danieldegrasse -/subsys/sip_svc/ @maheshraotm -/subsys/task_wdt/ @martinjaeger -/subsys/testsuite/ @nashif -/subsys/testsuite/ztest/*/ztress* @nordic-krch -/subsys/timing/ @nashif @dcpleung -/subsys/usb/ @jfischer-no -/subsys/usb/usb_c/ @sambhurst -/tests/ @nashif -/tests/arch/arm/ @ioannisg @stephanosio -/tests/benchmarks/cmsis_dsp/ @stephanosio -/tests/boards/native_posix/ @aescolar @daor-oti -/tests/bluetooth/ @alwa-nordic @jhedberg @Vudentz @sjanc -/tests/bluetooth/audio/ @jhedberg @Vudentz @wopu-ot @Thalley -/tests/bluetooth/controller/ @cvinayak @thoh-ot @kruithofa @erbr-ot @sjanc @ppryga -/tests/bsim/bluetooth/ @alwa-nordic @jhedberg @Vudentz @wopu-ot -/tests/bsim/bluetooth/audio/ @jhedberg @Vudentz @wopu-ot @Thalley -/tests/bsim/bluetooth/mesh/ @jhedberg @Vudentz @wopu-ot @PavelVPV -/tests/bluetooth/mesh_shell/ @jhedberg @Vudentz @sjanc @PavelVPV -/tests/bluetooth/tester/ @alwa-nordic @jhedberg @Vudentz @sjanc -/tests/posix/ @cfriedt -/tests/crypto/ @ceolin -/tests/crypto/mbedtls/ @nashif @ceolin @d3zd3z -/tests/drivers/can/ @alexanderwachter @henrikbrixandersen -/tests/drivers/counter/ @nordic-krch -/tests/drivers/eeprom/ @henrikbrixandersen @sjg20 -/tests/drivers/flash_simulator/ @de-nordic -/tests/drivers/gpio/ @mnkp -/tests/drivers/hwinfo/ @alexanderwachter -/tests/drivers/smbus/ @finikorg -/tests/drivers/spi/ @tbursztyka -/tests/drivers/uart/uart_async_api/ @anangl -/tests/drivers/w1/ @str4t0m -/tests/kernel/ @dcpleung @andyross @nashif -/tests/lib/ @nashif -/tests/lib/cmsis_dsp/ @stephanosio -/tests/net/ @rlubos @tbursztyka @jukkar -/tests/net/buf/ @jhedberg @tbursztyka @jukkar -/tests/net/conn_mgr_monitor/ @rlubos @glarsennordic @jukkar -/tests/net/conn_mgr_conn/ @rlubos @glarsennordic @jukkar -/tests/net/ieee802154/l2/ @rlubos @tbursztyka @jukkar @fgrandel -/tests/net/lib/ @rlubos @tbursztyka @jukkar -/tests/net/lib/http_header_fields/ @rlubos @tbursztyka @jukkar -/tests/net/lib/mqtt_packet/ @rlubos -/tests/net/lib/mqtt_sn_packet/ @rlubos @BeckmaR -/tests/net/lib/mqtt_sn_client/ @rlubos @BeckmaR -/tests/net/lib/coap/ @rlubos -/tests/net/npf/ @npitre -/tests/net/socket/socketpair/ @cfriedt -/tests/net/socket/ @rlubos @tbursztyka @jukkar -/tests/subsys/debug/coredump/ @dcpleung -/tests/subsys/fs/ @nashif @de-nordic -/tests/subsys/mgmt/mcumgr/ @de-nordic @nordicjm -/tests/subsys/sd/ @danieldegrasse -/tests/subsys/rtio/ @teburd -/tests/subsys/shell/ @jakub-uC @nordic-krch -# Get all docs reviewed -*.rst @nashif -/doc/kernel/ @andyross @nashif -*posix*.rst @aescolar @daor-oti diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 18d668a1332334c..f81c519c7831036 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 f47373a3bb665c3..f62689b9b6d0a69 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 @@ -315,6 +326,24 @@ config LINKER_USE_RELAX endmenu # "Linker Sections" +config LINKER_DEVNULL_SUPPORT + bool + default y if CPU_CORTEX_M || (RISCV && !64BIT) + +config LINKER_DEVNULL_MEMORY + bool "Devnull region" + depends on LINKER_DEVNULL_SUPPORT + help + Devnull region is created. It is stripped from final binary but remains + in byproduct elf file. + +config LINKER_DEVNULL_MEMORY_SIZE + int "Devnull region size" + depends on LINKER_DEVNULL_MEMORY + default 262144 + help + Size can be adjusted so it fits all data placed in that region. + endmenu menu "Compiler Options" @@ -325,10 +354,22 @@ config CODING_GUIDELINE_CHECK Use available compiler flags to check coding guideline rules during the build. -config NATIVE_BUILD +config NATIVE_LIBC bool select FULL_LIBC_SUPPORTED - select FULL_LIBCPP_SUPPORTED if CPP + help + Zephyr will use the host system C library. + +config NATIVE_LIBCPP + bool + select FULL_LIBCPP_SUPPORTED + help + Zephyr will use the host system C++ library + +config NATIVE_BUILD + bool + select NATIVE_LIBC if EXTERNAL_LIBC + select NATIVE_LIBCPP if EXTERNAL_LIBCPP help Zephyr will be built targeting the host system for debug and development purposes. @@ -756,7 +797,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 @@ -764,16 +807,7 @@ config CHECK_INIT_PRIORITIES derived from the devicetree definition. Fails the build on priority errors (dependent devices, inverted - priority), see CHECK_INIT_PRIORITIES_FAIL_ON_WARNING to fail on - warnings (dependent devices, same priority) as well. - -config CHECK_INIT_PRIORITIES_FAIL_ON_WARNING - bool "Fail the build on priority check warnings" - depends on CHECK_INIT_PRIORITIES - help - Fail the build if the dependency check script identifies any pair of - devices depending on each other but initialized with the same - priority. + priority). config EMIT_ALL_SYSCALLS bool "Emit all possible syscalls in the tree" @@ -847,7 +881,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 @@ -858,6 +892,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 @@ -909,14 +957,3 @@ config BOOTLOADER_BOSSA_ADAFRUIT_UF2 endchoice endmenu - -menu "Compatibility" - -config COMPAT_INCLUDES - bool "Suppress warnings when using header shims" - default y - help - Suppress any warnings from the pre-processor when including - deprecated header files. - -endmenu diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 13bdf72abd0b922..d025cff00b8cca2 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -111,6 +111,23 @@ # Areas are sorted by name +ACPI: + status: maintained + maintainers: + - jhedberg + - najumon1980 + collaborators: + - finikorg + - tbursztyka + files: + - lib/acpi/ + - include/zephyr/acpi/ + - tests/lib/acpi/ + labels: + - "area: ACPI" + tests: + - acpi + ARC arch: status: maintained maintainers: @@ -124,8 +141,11 @@ ARC arch: - include/zephyr/arch/arc/ - tests/arch/arc/ - dts/arc/synopsys/ + - doc/hardware/arch/arc-support-status.rst labels: - "area: ARC" + tests: + - arch.arc ARM arch: status: maintained @@ -139,6 +159,7 @@ ARM arch: - bbolen - povergoing - ithinuel + - sgrrzhf files: - arch/arm/ - arch/arm/core/offsets/ @@ -147,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 @@ -167,6 +191,41 @@ ARM64 arch: - dts/arm64/ labels: - "area: ARM64" + tests: + - arch.arm64 + +ARM Platforms: + status: odd fixes + files: + - 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: + - subsys/sip_svc/ + - tests/subsys/sip_svc/ + - include/zephyr/sip_svc/ + - include/zephyr/drivers/sip_svc/ + - drivers/sip_svc/ + labels: + - "area: ARM SiP SVC" + tests: + - sip_svc MIPS arch: status: odd fixes @@ -177,6 +236,8 @@ MIPS arch: - boards/mips/ labels: - "area: MIPS" + tests: + - arch.mips Ambiq Platforms: status: maintained @@ -185,15 +246,45 @@ 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: + - peter-mitsis + collaborators: + - nashif + - dcpleung + files: + - tests/benchmarks/ + labels: + - "area: Benchmarks" + Binary Descriptors: status: maintained maintainers: @@ -203,8 +294,11 @@ Binary Descriptors: - include/zephyr/bindesc.h - samples/subsys/bindesc/ - scripts/west_commands/bindesc.py + - tests/subsys/bindesc/ labels: - "area: Binary Descriptors" + tests: + - bindesc Bluetooth: status: maintained @@ -219,7 +313,6 @@ Bluetooth: files: - doc/connectivity/bluetooth/ - include/zephyr/bluetooth/ - - include/zephyr/drivers/bluetooth/ - samples/bluetooth/ - subsys/bluetooth/ - subsys/bluetooth/common/ @@ -245,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 @@ -265,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/ @@ -301,6 +416,7 @@ Bluetooth Mesh: - alxelax - Andrewpini - akredalen + - HaavardRei files: - subsys/bluetooth/mesh/ - include/zephyr/bluetooth/mesh/ @@ -310,6 +426,8 @@ Bluetooth Mesh: labels: - "area: Bluetooth Mesh" - "area: Bluetooth" + tests: + - bluetooth.mesh Bluetooth Audio: status: maintained @@ -334,6 +452,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 @@ -353,8 +504,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 @@ -384,6 +541,25 @@ Board/SoC configuration: - samples/cpp/ labels: - "area: C++" + tests: + - cpp + +Cache: + status: maintained + maintainers: + - carlocaione + collaborators: + - nashif + files: + - include/zephyr/drivers/cache.h + - include/zephyr/cache.h + - doc/hardware/cache/index.rst + - drivers/cache/ + - tests/kernel/cache/ + labels: + - "area: Cache" + tests: + - kernel.cache C library: status: maintained @@ -399,20 +575,25 @@ C library: - tests/lib/newlib/ labels: - "area: C Library" + tests: + - libraries.libc CMSIS API layer: status: odd fixes collaborators: - nashif files: - - subsys/portability/cmsis_rtos_v*/ + - subsys/portability/ - 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 @@ -428,6 +609,8 @@ DSP subsystem: - doc/services/dsp/ labels: - "area: DSP" + tests: + - zdsp CMSIS-DSP integration: status: maintained @@ -442,6 +625,8 @@ CMSIS-DSP integration: - tests/lib/cmsis_dsp/ labels: - "area: CMSIS-DSP" + tests: + - libraries.cmsis_dsp CMSIS-NN integration: status: maintained @@ -455,6 +640,8 @@ CMSIS-NN integration: - tests/lib/cmsis_nn/ labels: - "area: CMSIS-NN" + tests: + - libraries.cmsis_nn Coding Guidelines: status: maintained @@ -491,10 +678,16 @@ Common Architecture Interface: - dcpleung - nashif files: + - arch/Kconfig + - include/zephyr/arch/ - arch/common/ - include/zephyr/arch/common/ + - tests/arch/common/ + - doc/hardware/porting/arch.rst labels: - "area: Architectures" + tests: + - arch Console: status: odd fixes @@ -503,6 +696,8 @@ Console: - subsys/console/ labels: - "area: Console" + tests: + - sample.console Debug: status: maintained @@ -520,6 +715,22 @@ Debug: - doc/services/debugging/ labels: - "area: Debugging" + tests: + - debug + +Demand Paging: + status: maintained + maintainers: + - dcpleung + collaborators: + - ceolin + - peter-mitsis + - nashif + files: + - subsys/demand_paging/ + - tests/kernel/mem_protect/demand_paging/ + tests: + - kernel.demand_paging Device Driver Model: status: maintained @@ -535,8 +746,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 @@ -549,11 +763,12 @@ DFU: - tests/subsys/dfu/ labels: - "area: DFU" + tests: + - dfu Devicetree: status: maintained maintainers: - - mbolivar-ampere - galak files: - scripts/dts/ @@ -565,6 +780,8 @@ Devicetree: - include/zephyr/devicetree.h labels: - "area: Devicetree" + tests: + - libraries.devicetree Devicetree Bindings: status: maintained @@ -572,6 +789,8 @@ Devicetree Bindings: - galak files: - dts/bindings/ + - include/zephyr/dt-bindings/ + - dts/binding-template.yaml labels: - "area: Devicetree Binding" @@ -590,8 +809,11 @@ Disk: - subsys/sd/ - tests/subsys/sd/ - tests/drivers/disk/ + - include/zephyr/sd/ labels: - "area: Disk Access" + tests: + - drivers.disk Display drivers: status: odd fixes @@ -605,6 +827,8 @@ Display drivers: - include/zephyr/drivers/display.h - subsys/fb/ - samples/subsys/display/ + - doc/hardware/peripherals/display/ + - tests/drivers/*/display/ labels: - "area: Display" @@ -616,6 +840,9 @@ Documentation: collaborators: - nashif files: + - CODE_OF_CONDUCT.md + - CONTRIBUTING.rst + - doc/glossary.rst - doc/contribute/ - doc/develop/ - doc/introduction/ @@ -631,7 +858,9 @@ 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-* labels: - "area: Documentation" @@ -656,9 +885,12 @@ Documentation Infrastructure: Release Notes: status: maintained maintainers: - - jhedberg - - fabiobaltieri + - MaureenHelm + - henrikbrixandersen + collaborators: + - kartben files: + - doc/releases/migration-guide-* - doc/releases/release-notes-* labels: - "Release Notes" @@ -678,6 +910,8 @@ Release Notes: - include/zephyr/dt-bindings/adc/ labels: - "area: ADC" + tests: + - drivers.adc "Drivers: Audio": status: odd fixes @@ -689,6 +923,7 @@ Release Notes: files: - drivers/audio/ - include/zephyr/audio/ + - doc/hardware/peripherals/audio/ labels: - "area: Audio" @@ -700,8 +935,11 @@ Release Notes: - tests/drivers/bbram/ - drivers/bbram/ - include/zephyr/drivers/bbram.h + - doc/hardware/peripherals/bbram.rst labels: - "area: Battery Backed RAM (bbram)" + tests: + - drivers.bbram "Drivers: Aux display": status: maintained @@ -713,8 +951,11 @@ Release Notes: - include/zephyr/drivers/auxdisplay.h - drivers/auxdisplay/* - dts/bindings/auxdisplay/* + - doc/hardware/peripherals/auxdisplay.rst labels: - "area: Aux display" + tests: + - sample.drivers.auxdisplay "Drivers: CAN": status: maintained @@ -728,7 +969,8 @@ Release Notes: files: - boards/shields/mcp2515/ - boards/shields/tcan4550evm/ - - doc/hardware/peripherals/canbus/ + - doc/connectivity/canbus/ + - doc/hardware/peripherals/can/ - drivers/can/ - drivers/net/canbus.c - dts/bindings/can/ @@ -751,6 +993,26 @@ Release Notes: - tests/subsys/canbus/ labels: - "area: CAN" + tests: + - drivers.can + - canbus + +"Drivers: Charger": + status: maintained + maintainers: + - aaronemassey + - rriveramcrus + 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 @@ -766,6 +1028,8 @@ Release Notes: - doc/hardware/peripherals/clock_control.rst labels: - "area: Clock control" + tests: + - drivers.clock "Drivers: Console": status: odd fixes @@ -776,6 +1040,8 @@ Release Notes: - samples/subsys/console/ labels: - "area: Console" + tests: + - drivers.console "Drivers: Coredump": status: maintained @@ -789,6 +1055,8 @@ Release Notes: - doc/hardware/peripherals/coredump.rst labels: - "area: Coredump" + tests: + - debug.codedump "Drivers: Counter": status: maintained @@ -803,6 +1071,8 @@ Release Notes: - tests/drivers/build_all/counter/ labels: - "area: Counter" + tests: + - drivers.counter "Drivers: Crypto": status: maintained @@ -816,6 +1086,8 @@ Release Notes: - tests/crypto/ labels: - "area: Crypto / RNG" + tests: + - crypto "Drivers: DAC": status: maintained @@ -830,6 +1102,8 @@ Release Notes: - tests/drivers/build_all/dac/ labels: - "area: DAC" + tests: + - drivers.dac "Drivers: DAI": status: maintained @@ -845,6 +1119,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: @@ -858,6 +1145,8 @@ Release Notes: - include/zephyr/dt-bindings/dma/ labels: - "area: DMA" + tests: + - drivers.dma "Drivers: EDAC": status: maintained @@ -872,6 +1161,8 @@ Release Notes: - doc/hardware/peripherals/edac/ labels: - "area: EDAC" + tests: + - edac "Drivers: EEPROM": status: maintained @@ -879,12 +1170,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 @@ -894,8 +1190,11 @@ Release Notes: - drivers/entropy/ - include/zephyr/drivers/entropy.h - tests/drivers/entropy/ + - doc/hardware/peripherals/entropy.rst labels: - "area: Crypto / RNG" + tests: + - drivers.entropy "Drivers: ESPI": status: maintained @@ -912,18 +1211,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 @@ -937,8 +1246,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 @@ -956,6 +1269,8 @@ Release Notes: - tests/drivers/build_all/fpga/ labels: - "area: FPGA" + tests: + - drivers.fpga "Drivers: Fuel Gauge": status: maintained @@ -970,6 +1285,8 @@ Release Notes: - doc/hardware/peripherals/fuel_gauge.rst labels: - "area: Fuel Gauge" + tests: + - drivers.fuel_gauge "Drivers: GPIO": status: odd fixes @@ -986,6 +1303,24 @@ Release Notes: - tests/drivers/build_all/gpio/ labels: - "area: GPIO" + tests: + - drivers.gpio + +"Drivers: GNSS": + status: maintained + maintainers: + - bjarki-trackunit + files: + - 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 @@ -999,6 +1334,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 @@ -1012,9 +1358,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 @@ -1029,6 +1378,8 @@ Release Notes: - samples/drivers/i2s/ labels: - "area: I2S" + tests: + - drivers.i2s "Drivers: I3C": status: maintained @@ -1045,6 +1396,8 @@ Release Notes: - tests/drivers/build_all/i3c/ labels: - "area: I3C" + tests: + - drivers.i3c "Drivers: IEEE 802.15.4": status: maintained @@ -1057,19 +1410,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: 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 -"Drivers: Interrupt controllers": +"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 @@ -1081,10 +1507,13 @@ Release Notes: - dts/bindings/ipm/ - tests/drivers/ipm/ - doc/hardware/peripherals/ipm.rst + - include/zephyr/drivers/ipm.h description: >- Inter-processor mailboxes labels: - "area: IPM" + tests: + - drivers.ipm "Drivers: kscan": status: maintained @@ -1095,15 +1524,14 @@ Release Notes: files: - drivers/kscan/ - include/zephyr/drivers/kscan.h - - samples/drivers/espi/ - samples/drivers/kscan/ - - samples/drivers/kscan_touch/ - tests/drivers/kscan/ - - tests/drivers/espi/ - dts/bindings/kscan/ - doc/hardware/peripherals/kscan.rst labels: - "area: Kscan" + tests: + - drivers.kscan "Drivers: LED": status: maintained @@ -1119,8 +1547,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 @@ -1132,8 +1563,26 @@ 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 + collaborators: + - gmarull + - aasinclair + files: + - drivers/mfd/ + - include/zephyr/drivers/mfd/ + - dts/bindings/mfd/ + - tests/drivers/build_all/mfd/ + labels: + - "area: MFD" + tests: + - drivers.mfd "Drivers: Modem": status: maintained @@ -1145,7 +1594,9 @@ Release Notes: - dts/bindings/modem/ - include/zephyr/drivers/modem/ labels: - - "area: Modem" + - "area: Modem Drivers" + tests: + - drivers.modem "Drivers: Regulators": status: maintained @@ -1164,6 +1615,8 @@ Release Notes: - doc/hardware/peripherals/regulators.rst labels: - "area: Regulators" + tests: + - drivers.regulator "Drivers: Retained Memory": status: maintained @@ -1174,8 +1627,11 @@ Release Notes: - dts/bindings/retained_mem/ - include/zephyr/drivers/retained_mem.h - tests/drivers/retained_mem/ + - doc/hardware/peripherals/retained_mem.rst labels: - "area: Retained Memory" + tests: + - drivers.retained_mem "Drivers: RTC": status: maintained @@ -1183,11 +1639,15 @@ Release Notes: - bjarki-trackunit files: - drivers/rtc/ + - include/zephyr/drivers/rtc/ - 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 @@ -1200,6 +1660,7 @@ Release Notes: files: - drivers/pcie/ - include/zephyr/drivers/pcie/ + - doc/hardware/peripherals/pcie.rst labels: - "area: PCI" @@ -1216,6 +1677,8 @@ Release Notes: - doc/hardware/peripherals/peci.rst labels: - "area: PECI" + tests: + - samples.drivers.peci "Drivers: Pin Control": status: maintained @@ -1231,6 +1694,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 @@ -1271,8 +1749,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 @@ -1286,6 +1767,8 @@ Release Notes: - doc/hardware/peripherals/sdhc.rst labels: - "area: Disk Access" + tests: + - drivers.sdhc "Drivers: Serial/UART": status: maintained @@ -1300,8 +1783,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 @@ -1315,6 +1802,7 @@ Release Notes: files: - drivers/sensor/ - include/zephyr/drivers/sensor.h + - include/zephyr/drivers/sensor_data_types.h - samples/sensor/ - tests/drivers/sensor/ - dts/bindings/sensor/ @@ -1324,6 +1812,8 @@ Release Notes: - tests/drivers/build_all/sensor/ labels: - "area: Sensors" + tests: + - drivers.sensors "Drivers: SMBus": status: maintained @@ -1338,6 +1828,8 @@ Release Notes: - doc/hardware/peripherals/smbus.rst labels: - "area: SMBus" + tests: + - drivers.smbus "Drivers: SPI": status: maintained @@ -1352,6 +1844,8 @@ Release Notes: - doc/hardware/peripherals/spi.rst labels: - "area: SPI" + tests: + - drivers.spi "Drivers: System timer": status: maintained @@ -1373,8 +1867,12 @@ Release Notes: - drivers/video/ - 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 @@ -1392,6 +1890,8 @@ Release Notes: - samples/drivers/w1/ labels: - "area: W1" + tests: + - drivers.w1 "Drivers: Watchdog": status: odd fixes @@ -1405,8 +1905,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 @@ -1462,17 +1965,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 @@ -1506,6 +2013,8 @@ Filesystems: - tests/subsys/fs/ labels: - "area: File System" + tests: + - filesystem "Filesystems: FatFs reentrant support": status: maintained @@ -1516,6 +2025,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 @@ -1532,6 +2043,9 @@ Formatted Output: - doc/services/formatted_output.rst labels: - "area: Formatting Output" + tests: + - utilities.prf + - libraries.cbprintf Google Platforms: status: maintained @@ -1555,6 +2069,9 @@ Hash Utilities: Hash Functions and Hash Maps (Hash Tables) labels: - "area: hash utils" + tests: + - libraries.hash_function + - libraries.hash_map Input: status: maintained @@ -1572,10 +2089,14 @@ Input: - subsys/input/ - tests/drivers/build_all/input/ - tests/subsys/input/ + - tests/drivers/input/ description: >- Input subsystem and drivers labels: - "area: Input" + tests: + - drivers.input + - input IPC: status: maintained @@ -1587,23 +2108,32 @@ 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: odd fixes + status: maintained + maintainers: + - d3zd3z collaborators: - mrfuchs - sir-branch 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 @@ -1614,25 +2144,32 @@ Kconfig: - scripts/kconfig/ - doc/build/kconfig/ - Kconfig.zephyr + - tests/kconfig/configdefault/ + - tests/misc/kconfigoptions/ labels: - "area: 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 maintainers: - andyross + - peter-mitsis collaborators: - nashif - ceolin - dcpleung - - peter-mitsis - cfriedt + - npitre files: - doc/kernel/ - include/zephyr/kernel*.h + - include/zephyr/spinlock.h + - include/zephyr/fatal.h - kernel/ - tests/kernel/ - include/zephyr/sys_clock.h @@ -1643,25 +2180,102 @@ Kernel: - tests/kernel/mem_protect/ labels: - "area: Kernel" + tests: + - kernel -Base OS: +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 + maintainers: + - andyross - nashif + collaborators: + - dcpleung + - peter-mitsis 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/ - tests/lib/cbprintf_*/ - lib/os/cbprintf* - lib/os/Kconfig.cbprintf + - include/zephyr/sys/mem_manage.h + - include/zephyr/sys/mpsc_pbuf.h + - include/zephyr/sys/mpsc_packet.h + - 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 @@ -1679,6 +2293,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: @@ -1689,6 +2316,8 @@ Little FS: Little FS labels: - "area: File System" + tests: + - filesystem.littlefs Logging: status: maintained @@ -1698,13 +2327,21 @@ Logging: - dcpleung files: - include/zephyr/logging/ + - include/zephyr/sys/mpsc_pbuf.h + - include/zephyr/sys/mpsc_packet.h + - lib/os/mpsc_pbuf.c + - doc/kernel/data_structures/mpsc_pbuf.rst + - tests/lib/mpsc_pbuf/ - samples/subsys/logging/ - subsys/logging/ - tests/subsys/logging/ - scripts/logging/ - doc/services/logging/ + - tests/lib/spsc_pbuf/ labels: - "area: Logging" + tests: + - logging LoRa and LoRaWAN: status: maintained @@ -1724,6 +2361,8 @@ LoRa and LoRaWAN: - doc/connectivity/lora_lorawan/index.rst labels: - "area: LoRa" + tests: + - sample.driver.lora MAINTAINERS file: status: maintained @@ -1752,6 +2391,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 @@ -1765,8 +2407,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 @@ -1780,8 +2425,10 @@ Modbus: - doc/services/modbus/ labels: - "area: modbus" + tests: + - modbus -Modem Modules: +Modem: status: maintained maintainers: - bjarki-trackunit @@ -1789,6 +2436,13 @@ Modem Modules: - subsys/modem/ - include/zephyr/modem/ - tests/subsys/modem/ + - doc/services/modem/ + - samples/net/cellular_modem/ + - include/zephyr/drivers/cellular.h + labels: + - "area: Modem" + tests: + - modem OSDP: status: maintained @@ -1803,6 +2457,8 @@ OSDP: - samples/subsys/mgmt/osdp/ labels: - "area: OSDP" + tests: + - sample.mgmt.osdp hawkBit: status: odd fixes @@ -1814,6 +2470,8 @@ hawkBit: - samples/subsys/mgmt/hawkbit/ labels: - "area: hawkBit" + tests: + - sample.net.hawkbit "mgmt: updatehub": status: maintained @@ -1821,11 +2479,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 @@ -1833,6 +2494,7 @@ Native POSIX/Sim and POSIX arch: - aescolar files: - arch/posix/ + - boards/posix/common/ - boards/posix/native_*/ - boards/posix/doc/ - boards/posix/*.rst @@ -1845,11 +2507,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 @@ -1860,12 +2524,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 @@ -1873,10 +2539,12 @@ Networking: - include/zephyr/net/gptp.h - include/zephyr/net/ieee802154*.h - include/zephyr/net/wifi*.h + - include/zephyr/net/buf.h - samples/net/gptp/ - samples/net/sockets/coap_*/ - samples/net/lwm2m_client/ - samples/net/wifi/ + - subsys/net/buf*.c - subsys/net/l2/ethernet/gptp/ - subsys/net/l2/ieee802154/ - subsys/net/l2/wifi/ @@ -1888,6 +2556,8 @@ Networking: - tests/net/wifi/ labels: - "area: Networking" + tests: + - net "Networking: BSD sockets": status: odd fixes @@ -1900,6 +2570,8 @@ Networking: - tests/net/socket/ labels: - "area: Sockets" + tests: + - net.socket "Networking: Buffers": status: maintained @@ -1911,10 +2583,12 @@ Networking: - jukkar files: - include/zephyr/net/buf.h - - subsys/net/buf.c + - subsys/net/buf*.c - tests/net/buf/ labels: - - "area: Networking" + - "area: Networking Buffers" + tests: + - net.buf "Networking: Connection Manager": status: maintained @@ -1931,6 +2605,8 @@ Networking: - doc/connectivity/networking/conn_mgr/ labels: - "area: Networking" + tests: + - net.conn_mgr "Networking: CoAP": status: maintained @@ -1944,6 +2620,8 @@ Networking: - tests/net/lib/coap/ labels: - "area: Networking" + tests: + - net.coap "Networking: gPTP": status: maintained @@ -1958,6 +2636,8 @@ Networking: - subsys/net/l2/ethernet/gptp/ labels: - "area: Networking" + tests: + - sample.net.gptp "Networking: LWM2M": status: maintained @@ -1971,6 +2651,8 @@ Networking: - subsys/net/lib/lwm2m/ labels: - "area: LWM2M" + tests: + - net.lwm2m "Networking: MQTT": status: maintained @@ -1985,6 +2667,8 @@ Networking: - tests/net/lib/mqtt_sn*/ labels: - "area: Networking" + tests: + - net.mqtt "Networking: MQTT-SN": status: maintained @@ -1998,6 +2682,8 @@ Networking: - samples/net/mqtt_sn_publisher/ labels: - "area: Networking" + tests: + - net.mqtt_sn "Networking: Native IEEE 802.15.4": status: maintained @@ -2014,6 +2700,8 @@ Networking: - tests/net/ieee802154/ labels: - "area: IEEE 802.15.4" + tests: + - net.ieee802154 "Networking: OpenThread": status: maintained @@ -2023,6 +2711,8 @@ Networking: - pdgendt - canisLupus1313 - mariuszpos + - edmont + - maciejbaczmanski files: - subsys/net/l2/openthread/ - samples/net/openthread/ @@ -2030,6 +2720,8 @@ Networking: labels: - "area: Networking" - "area: OpenThread" + tests: + - openthread "Networking: Wi-Fi": status: maintained @@ -2047,6 +2739,8 @@ Networking: labels: - "area: Networking" - "area: Wi-Fi" + tests: + - net.wifi NIOS-2 arch: status: maintained @@ -2054,12 +2748,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 @@ -2073,19 +2773,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 @@ -2105,6 +2821,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 @@ -2117,16 +2843,21 @@ RISCV arch: - katsuster - edersondisouza - carlocaione + - npitre files: - arch/riscv/ - boards/riscv/ - dts/bindings/riscv/ + - dts/riscv/ - include/zephyr/arch/riscv/ - soc/riscv/ - tests/arch/riscv/ - doc/hardware/arch/risc-v.rst + - drivers/interrupt_controller/intc_plic.c labels: - "area: RISCV" + tests: + - arch.riscv Retention: status: maintained @@ -2136,9 +2867,21 @@ Retention: - dts/bindings/retention/ - include/zephyr/retention/ - subsys/retention/ + - doc/services/retention/ labels: - "area: Retention" +Samples: + status: maintained + maintainers: + - kartben + collaborators: + - nashif + files: + - samples/ + labels: + - "area: Samples" + Sensor Subsystem: status: maintained maintainers: @@ -2156,6 +2899,16 @@ Sensor Subsystem: - samples/subsys/sensing/ labels: - "area: Sensor Subsystem" + tests: + - sample.sensing + +Stats: + status: odd fixes + files: + - subsys/stats/ + - include/zephyr/stats/stats.h + labels: + - "area: Stats" Twister: status: maintained @@ -2170,12 +2923,16 @@ Twister: - gchwier files: - scripts/twister + - scripts/schemas/twister/ - scripts/pylib/twister/ - scripts/tests/twister/ - scripts/tests/twister_blackbox/ - doc/develop/test/twister.rst - 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" @@ -2189,6 +2946,8 @@ Settings: - doc/services/settings/ labels: - "area: Settings" + tests: + - settings Shell: status: maintained @@ -2204,6 +2963,8 @@ Shell: - doc/services/shell/ labels: - "area: Shell" + tests: + - shell Shields: status: maintained @@ -2219,6 +2980,8 @@ Shields: - samples/shields/ labels: - "area: Shields" + tests: + - sample.shields SPARC arch: status: odd fixes @@ -2246,6 +3009,8 @@ State machine framework: - tests/lib/smf/ labels: - "area: State Machine Framework" + tests: + - libraries.smf ADI Platforms: status: maintained @@ -2255,6 +3020,7 @@ ADI Platforms: - galak - microbuilder files: + - boards/arm/adi_*/ - drivers/*/max* - drivers/*/*max*/ - drivers/dac/dac_ltc* @@ -2269,6 +3035,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: @@ -2282,10 +3055,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" @@ -2314,8 +3086,8 @@ Nuvoton NPCX Platforms: - MulinChao - ChiHuaL collaborators: - - MulinChao - - ChiHuaL + - TomChang19 + - alvsun - sjg20 - keith-zephyr - jackrosenthal @@ -2329,18 +3101,24 @@ Nuvoton NPCX Platforms: labels: - "platform: Nuvoton NPCX" -Nuvoton Numicro Platforms: - status: odd fixes +Nuvoton Numicro Numaker Platforms: + status: maintained + maintainers: + - cyliangtw collaborators: - ssekar15 files: - soc/arm/nuvoton_numicro/ + - soc/arm/nuvoton_numaker/ - boards/arm/nuvoton_pfm*/ + - boards/arm/numaker_*/ - dts/arm/nuvoton/ - dts/bindings/*/*numicro* + - dts/bindings/*/*numaker* - drivers/*/*_numicro* + - drivers/*/*_numaker* labels: - - "platform: Nuvoton Numicro" + - "platform: Nuvoton Numicro Numaker" Raspberry Pi Pico Platforms: status: maintained @@ -2403,7 +3181,6 @@ Intel Platforms (Xtensa): - marc-hb - kv2019i - ceolin - - aborisovich - tmleman - softwarecki - jxstelter @@ -2415,6 +3192,7 @@ Intel Platforms (Xtensa): - tests/boards/intel_adsp/ - samples/boards/intel_adsp/ - dts/bindings/*/intel,adsp* + - scripts/west_commands/runners/intel_adsp.py labels: - "platform: Intel ADSP" @@ -2440,17 +3218,52 @@ Intel Platforms (Agilex): - gdengi collaborators: - nbalabak - - chongteikheng + - teikheng files: - 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 + - decsny + - manuargue + - dbaluta + files: + - drivers/*/*imx* + - drivers/*/*lpc*.c + - drivers/*/*mcux*.c + - drivers/*/*.mcux + - drivers/*/*.nxp + - drivers/*/*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* + 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 @@ -2461,33 +3274,63 @@ NXP Platforms: - 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*/ + 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 - - 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/*/*nxp* - - dts/arm/nxp/ - - dts/bindings/*/nxp* + - 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/ - - samples/boards/nxp*/ - - include/zephyr/dt-bindings/*/nxp* - - include/zephyr/drivers/*/*nxp* + - boards/xtensa/nxp_adsp_*/ labels: - - "platform: NXP" + - "platform: NXP ADSP" + description: NXP Xtensa platforms Microchip MEC Platforms: status: maintained @@ -2558,6 +3401,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: @@ -2566,6 +3441,7 @@ Renesas R-Car Platforms: collaborators: - xakep-amatop files: + - dts/arm/renesas/rcar/ - boards/arm/rcar_*/ - boards/arm64/rcar_*/ - drivers/*/*rcar* @@ -2593,6 +3469,7 @@ STM32 Platforms: - Desvauxm-st - GeorgeCGV files: + - boards/arm/b_*/ - boards/arm/nucleo_*/ - boards/arm/stm32*_disco/ - boards/arm/stm32*_dk*/ @@ -2601,6 +3478,7 @@ STM32 Platforms: - drivers/*/*stm32*.c - drivers/*/*stm32*.h - drivers/*/*/*stm32* + - drivers/*/*stm32* - dts/arm/st/ - dts/bindings/*/*stm32* - soc/arm/st_stm32/ @@ -2649,9 +3527,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" @@ -2661,7 +3540,6 @@ TI SimpleLink Platforms: - vaishnavachath collaborators: - vanti - - cfriedt files: - boards/arm/cc13*/ - boards/arm/cc26*/ @@ -2675,6 +3553,7 @@ TI SimpleLink Platforms: - dts/bindings/*/ti,* - soc/arm/ti_simplelink/ - dts/bindings/*/ti,* + - modules/Kconfig.simplelink labels: - "platform: TI SimpleLink" @@ -2693,6 +3572,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: @@ -2723,6 +3610,8 @@ Infineon Platforms: - drivers/*/*xmc*.c - drivers/*/*/*xmc* - dts/arm/infineon/ + - dts/arm/cypress/ + - soc/arm/cypress/ - dts/bindings/*/*infineon* - soc/arm/infineon_*/ labels: @@ -2731,6 +3620,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: @@ -2745,6 +3643,8 @@ RTIO: - doc/services/rtio/ labels: - "area: RTIO" + tests: + - rtio Storage: status: odd fixes @@ -2755,6 +3655,8 @@ Storage: - doc/services/storage/ labels: - "area: Storage" + tests: + - storage Sysbuild: status: maintained @@ -2769,6 +3671,8 @@ Sysbuild: - doc/build/sysbuild/ labels: - "area: Sysbuild" + tests: + - sample.application_development.sysbuild Task Watchdog: status: maintained @@ -2781,19 +3685,49 @@ 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 + maintainers: + - akanisetti + files: + - doc/hardware/peripherals/tgpio.rst + - drivers/misc/timeaware_gpio/ + - include/zephyr/drivers/misc/timeaware_gpio/ + - 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": status: maintained @@ -2806,6 +3740,8 @@ TF-M Integration: - cmake/compiler/ - cmake/linker/ - cmake/toolchain/ + - include/zephyr/toolchain/ + - include/zephyr/toolchain.h labels: - "area: Toolchains" @@ -2851,6 +3787,7 @@ Tracing: - teburd files: - subsys/tracing/ + - scripts/tracing/ - include/zephyr/tracing/ - subsys/timing/ - samples/subsys/tracing/ @@ -2858,6 +3795,8 @@ Tracing: - tests/subsys/tracing/ labels: - "area: tracing" + tests: + - tracing USB: status: maintained @@ -2873,10 +3812,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 @@ -2892,8 +3836,11 @@ USB-C: - samples/subsys/usb_c/ - subsys/usb/usb_c/ - doc/connectivity/usb/pd/ + - doc/hardware/peripherals/usbc_vbus.rst labels: - "area: USB-C" + tests: + - sample.usbc Userspace: status: maintained @@ -2902,6 +3849,7 @@ Userspace: collaborators: - ceolin files: + - include/zephyr/internal/syscall_handler.h - doc/kernel/usermode/kernelobjects.rst - include/zephyr/app_memory/ - include/zephyr/linker/app_smem*.ld @@ -2915,8 +3863,14 @@ Userspace: - scripts/build/process_gperf.py - scripts/build/gen_relocate_app.py - include/zephyr/sys/kobject.h + - include/zephyr/sys/mem_manage.h + - include/zephyr/kernel/mm.h + - include/zephyr/kernel/internal/mm.h + - include/zephyr/kernel/mm/demand_paging.h labels: - "area: Userspace" + tests: + - kernel.memory_protection VFS: status: maintained @@ -2930,6 +3884,8 @@ VFS: labels: - "area: File System" + tests: + - filesystem West: status: maintained @@ -2950,10 +3906,13 @@ West: status: maintained maintainers: - najumon1980 + - jhedberg + collaborators: + - tbursztyka files: - modules/acpica/ labels: - - manifest-acpica + - "area: ACPI" "West project: canopennode": status: maintained @@ -2970,6 +3929,7 @@ West: - yperess files: - samples/modules/chre/ + - modules/Kconfig.chre labels: - "area: CHRE" @@ -2981,7 +3941,7 @@ West: - microbuilder - povergoing files: - - modules/cmsis/Kconfig + - modules/cmsis/ labels: - "area: ARM" @@ -3043,7 +4003,10 @@ West: collaborators: - tgorochowik - msobkowski - files: [] + - aaronyegx + - RichardSWheatley + files: + - modules/hal_ambiq/ labels: - "platform: Ambiq" @@ -3077,7 +4040,8 @@ West: collaborators: - LucasTambor - marekmatej - files: [] + files: + - modules/Kconfig.esp32 labels: - "platform: ESP32" @@ -3089,7 +4053,7 @@ West: - drivers/misc/ethos_u/ - modules/hal_ethos_u/ labels: - - manifest-hal_ethos_u + - "area: ARM" "West project: hal_gigadevice": status: maintained @@ -3223,7 +4187,7 @@ West: collaborators: - erwango files: - - modules/Kconfig.st + - modules/hal_st/Kconfig labels: - "area: Sensors" @@ -3254,8 +4218,6 @@ West: status: maintained maintainers: - vaishnavachath - collaborators: - - cfriedt files: [] labels: - "platform: TI" @@ -3435,6 +4397,8 @@ West: - pdgendt - canisLupus1313 - mariuszpos + - edmont + - maciejbaczmanski files: - modules/openthread/ labels: @@ -3456,7 +4420,8 @@ West: - keith-packard collaborators: - stephanosio - files: [] + files: + - modules/Kconfig.picolibc labels: - "area: C Library" - "area: picolibc" @@ -3519,7 +4484,6 @@ West: maintainers: - d3zd3z collaborators: - - joerchan - SebastianBoe files: - modules/trusted-firmware-m/ @@ -3531,7 +4495,6 @@ West: maintainers: - d3zd3z collaborators: - - joerchan - SebastianBoe files: [] labels: @@ -3554,7 +4517,6 @@ West: maintainers: - d3zd3z collaborators: - - joerchan - SebastianBoe files: [] labels: @@ -3567,6 +4529,7 @@ West: - StefanHri files: - modules/uoscore-uedhoc/ + - tests/modules/uoscore/ labels: - "area: Networking" - "area: Crypto / RNG" @@ -3588,6 +4551,16 @@ West: labels: - "area: Sensors" +"West project: hostap": + status: maintained + maintainers: + - krish2718 + - jukkar + files: + - modules/hostap/ + labels: + - "area: Wi-Fi" + Xtensa arch: status: maintained maintainers: @@ -3602,6 +4575,9 @@ Xtensa arch: - dts/xtensa/ - boards/xtensa/qemu_xtensa/ - boards/xtensa/xt-sim/ + - soc/xtensa/dc233c/ + - soc/xtensa/sample_controller/ + - soc/xtensa/CMakeLists.txt labels: - "area: Xtensa" @@ -3632,16 +4608,19 @@ Continuous Integration: maintainers: - stephanosio - nashif - - galak + collaborators: + - fabiobaltieri + - kartben files: - .github/ - scripts/ci/ - .checkpatch.conf - scripts/gitlint/ + - scripts/set_assignees.py labels: - "area: Continuous Integration" -ZTest: +Test Framework (Ztest): status: maintained maintainers: - nashif @@ -3654,6 +4633,7 @@ ZTest: - subsys/testsuite/ - tests/ztest/ - tests/unit/util/ + - tests/subsys/testsuite/ - samples/subsys/testsuite/ - doc/develop/test/ztest.rst labels: @@ -3671,6 +4651,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 @@ -3715,6 +4696,8 @@ zbus: - doc/services/zbus/ labels: - "area: zbus" + tests: + - message_bus.zbus "Linkable Loadable Extensions": status: maintained @@ -3722,6 +4705,7 @@ zbus: - teburd collaborators: - lyakh + - pillo79 files: - samples/subsys/llext/ - include/zephyr/llext/ @@ -3730,3 +4714,5 @@ zbus: - doc/services/llext/ labels: - "area: Linkable Loadable Extensions" + tests: + - llext diff --git a/README.rst b/README.rst index 9770417087d05a6..45a3998194dcfc1 100644 --- a/README.rst +++ b/README.rst @@ -54,39 +54,59 @@ Resources Here's a quick summary of resources to help you find your way around: -* **Help**: `Asking for Help Tips`_ -* **Documentation**: http://docs.zephyrproject.org (`Getting Started Guide`_) -* **Source Code**: https://github.com/zephyrproject-rtos/zephyr is the main - repository; https://elixir.bootlin.com/zephyr/latest/source contains a - searchable index -* **Releases**: https://github.com/zephyrproject-rtos/zephyr/releases -* **Samples and example code**: see `Sample and Demo Code Examples`_ -* **Mailing Lists**: users@lists.zephyrproject.org and - devel@lists.zephyrproject.org are the main user and developer mailing lists, - respectively. You can join the developer's list and search its archives at - `Zephyr Development mailing list`_. The other `Zephyr mailing list - subgroups`_ have their own archives and sign-up pages. -* **Nightly CI Build Status**: https://lists.zephyrproject.org/g/builds - The builds@lists.zephyrproject.org mailing list archives the CI nightly build results. -* **Chat**: Real-time chat happens in Zephyr's Discord Server. Use - this `Discord Invite`_ to register. -* **Contributing**: see the `Contribution Guide`_ -* **Wiki**: `Zephyr GitHub wiki`_ -* **Issues**: https://github.com/zephyrproject-rtos/zephyr/issues -* **Security Issues**: Email vulnerabilities@zephyrproject.org to report - security issues; also see our `Security`_ documentation. Security issues are - tracked separately at https://zephyrprojectsec.atlassian.net. -* **Zephyr Project Website**: https://zephyrproject.org - -.. _Discord Invite: https://chat.zephyrproject.org -.. _supported boards: http://docs.zephyrproject.org/latest/boards/index.html -.. _Zephyr Documentation: http://docs.zephyrproject.org -.. _Introduction to Zephyr: http://docs.zephyrproject.org/latest/introduction/index.html -.. _Getting Started Guide: http://docs.zephyrproject.org/latest/develop/getting_started/index.html -.. _Contribution Guide: http://docs.zephyrproject.org/latest/contribute/index.html -.. _Zephyr GitHub wiki: https://github.com/zephyrproject-rtos/zephyr/wiki -.. _Zephyr Development mailing list: https://lists.zephyrproject.org/g/devel -.. _Zephyr mailing list subgroups: https://lists.zephyrproject.org/g/main/subgroups -.. _Sample and Demo Code Examples: http://docs.zephyrproject.org/latest/samples/index.html -.. _Security: http://docs.zephyrproject.org/latest/security/index.html -.. _Asking for Help Tips: https://docs.zephyrproject.org/latest/develop/getting_started/index.html#asking-for-help +Getting Started +--------------- + + | 📖 `Zephyr Documentation`_ + | 🚀 `Getting Started Guide`_ + | 🙋🏽 `Tips when asking for help`_ + | 💻 `Code samples`_ + +Code and Development +-------------------- + + | 🌐 `Source Code Repository`_ + | 📦 `Releases`_ + | 🤝 `Contribution Guide`_ + +Community and Support +--------------------- + + | 💬 `Discord Server`_ for real-time community discussions + | 📧 `User mailing list (users@lists.zephyrproject.org)`_ + | 📧 `Developer mailing list (devel@lists.zephyrproject.org)`_ + | 📬 `Other project mailing lists`_ + | 📚 `Project Wiki`_ + +Issue Tracking and Security +--------------------------- + + | 🐛 `GitHub Issues`_ + | 🔒 `Security documentation`_ + | 🛡️ `Security Advisories Repository`_ + | ⚠️ Report security vulnerabilities at vulnerabilities@zephyrproject.org + +Additional Resources +-------------------- + | 🌐 `Zephyr Project Website`_ + | 📺 `Zephyr Tech Talks`_ + +.. _Zephyr Project Website: https://www.zephyrproject.org +.. _Discord Server: https://chat.zephyrproject.org +.. _supported boards: https://docs.zephyrproject.org/latest/boards/index.html +.. _Zephyr Documentation: https://docs.zephyrproject.org +.. _Introduction to Zephyr: https://docs.zephyrproject.org/latest/introduction/index.html +.. _Getting Started Guide: https://docs.zephyrproject.org/latest/develop/getting_started/index.html +.. _Contribution Guide: https://docs.zephyrproject.org/latest/contribute/index.html +.. _Source Code Repository: https://github.com/zephyrproject-rtos/zephyr +.. _GitHub Issues: https://github.com/zephyrproject-rtos/zephyr/issues +.. _Releases: https://github.com/zephyrproject-rtos/zephyr/releases +.. _Project Wiki: https://github.com/zephyrproject-rtos/zephyr/wiki +.. _User mailing list (users@lists.zephyrproject.org): https://lists.zephyrproject.org/g/users +.. _Developer mailing list (devel@lists.zephyrproject.org): https://lists.zephyrproject.org/g/devel +.. _Other project mailing lists: https://lists.zephyrproject.org/g/main/subgroups +.. _Code samples: https://docs.zephyrproject.org/latest/samples/index.html +.. _Security documentation: https://docs.zephyrproject.org/latest/security/index.html +.. _Security Advisories Repository: https://github.com/zephyrproject-rtos/zephyr/security +.. _Tips when asking for help: https://docs.zephyrproject.org/latest/develop/getting_started/index.html#asking-for-help +.. _Zephyr Tech Talks: https://www.zephyrproject.org/tech-talks diff --git a/SDK_VERSION b/SDK_VERSION new file mode 100644 index 000000000000000..5f2491c5adcaef4 --- /dev/null +++ b/SDK_VERSION @@ -0,0 +1 @@ +0.16.4 diff --git a/VERSION b/VERSION index 5ed75f8b8ea3106..a2cbf5c13353b22 100644 --- a/VERSION +++ b/VERSION @@ -1,5 +1,5 @@ VERSION_MAJOR = 3 VERSION_MINOR = 5 -PATCHLEVEL = 0 +PATCHLEVEL = 99 VERSION_TWEAK = 0 -EXTRAVERSION = rc3 +EXTRAVERSION = diff --git a/arch/Kconfig b/arch/Kconfig index 110938528ed392e..b8661fa596413ce 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -19,7 +19,6 @@ source "$(ARCH_DIR)/$(ARCH)/Kconfig" config ARC bool select ARCH_IS_SET - select HAS_DTS imply XIP select ARCH_HAS_THREAD_LOCAL_STORAGE select ARCH_SUPPORTS_ROM_START @@ -30,7 +29,6 @@ config ARM bool select ARCH_IS_SET select ARCH_SUPPORTS_COREDUMP if CPU_CORTEX_M - select HAS_DTS # FIXME: current state of the code for all ARM requires this, but # is really only necessary for Cortex-M with ARM MPU! select GEN_PRIV_STACKS @@ -43,7 +41,6 @@ config ARM64 bool select ARCH_IS_SET select 64BIT - select HAS_DTS select ARCH_SUPPORTS_COREDUMP select HAS_ARM_SMCCC select ARCH_HAS_THREAD_LOCAL_STORAGE @@ -58,14 +55,12 @@ config MIPS bool select ARCH_IS_SET select ATOMIC_OPERATIONS_C - select HAS_DTS help MIPS architecture config SPARC bool select ARCH_IS_SET - select HAS_DTS select USE_SWITCH select USE_SWITCH_SUPPORTED select BIG_ENDIAN @@ -80,7 +75,6 @@ config X86 bool select ARCH_IS_SET select ATOMIC_OPERATIONS_BUILTIN - select HAS_DTS select ARCH_SUPPORTS_COREDUMP select ARCH_SUPPORTS_ROM_START if !X86_64 select CPU_HAS_MMU @@ -102,7 +96,6 @@ config NIOS2 bool select ARCH_IS_SET select ATOMIC_OPERATIONS_C - select HAS_DTS imply XIP select ARCH_HAS_TIMING_FUNCTIONS help @@ -111,7 +104,6 @@ config NIOS2 config RISCV bool select ARCH_IS_SET - select HAS_DTS select ARCH_SUPPORTS_COREDUMP select ARCH_SUPPORTS_ROM_START if !SOC_SERIES_ESP32C3 select ARCH_HAS_CODE_DATA_RELOCATION @@ -128,20 +120,18 @@ config RISCV config XTENSA bool select ARCH_IS_SET - select HAS_DTS select USE_SWITCH select USE_SWITCH_SUPPORTED 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 config ARCH_POSIX bool select ARCH_IS_SET - select HAS_DTS select ATOMIC_OPERATIONS_BUILTIN select ARCH_HAS_CUSTOM_SWAP_TO_MAIN select ARCH_HAS_CUSTOM_BUSY_WAIT @@ -149,6 +139,8 @@ config ARCH_POSIX select NATIVE_BUILD select HAS_COVERAGE_SUPPORT select BARRIER_OPERATIONS_BUILTIN + # POSIX arch based targets get their memory cleared on entry by the host OS + select SKIP_BSS_CLEAR help POSIX (native) architecture @@ -521,6 +513,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 @@ -663,6 +665,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 @@ -827,6 +834,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 @@ -986,3 +1004,10 @@ config TOOLCHAIN_HAS_BUILTIN_FFS default y if !(64BIT && RISCV) help Hidden option to signal that toolchain has __builtin_ffs*(). + +config ARCH_CPU_IDLE_CUSTOM + bool "Custom arch_cpu_idle implementation" + default n + help + This options allows applications to override the default arch idle implementation with + a custom one. diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index ce23b12aa1d67b9..80b46876e10ae0b 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 3325e27ff88ed4e..00c9f775038247d 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 9fb43c411524168..000000000000000 --- 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 1536c5a173f2b0a..8c2aab29fed5dbf 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 396f9c6840e34fa..48a910198ecd501 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 bc606c9c26e6bb4..77db2d82c1fae12 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 0d322fa28fcf032..07615286683fb4f 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 df8af4c1b446f0f..346a04062c1b2a6 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 9e0ddaf7ed92383..8034f5673d48ee5 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 450a6d23047bdbf..855270fa3ab72f6 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 8bf481c86b29128..0e4975cd3fcad80 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 ba29f44051b5186..a2b038d387ee200 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 000000000000000..6bc89883fad999d --- /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 eeb12d45f6a8ec9..563401201433e85 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 14f7869763fa94d..efe2bd7d1c6585b 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 fc828c7ddaf558d..1d7b1ca122023b3 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/Kconfig b/arch/arm/Kconfig index 3f775e4d6389095..8b0d53ec3cf2031 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -16,23 +16,23 @@ config CPU_CORTEX config ARM_CUSTOM_INTERRUPT_CONTROLLER bool - depends on !CPU_CORTEX_M help This option indicates that the ARM CPU is connected to a custom (i.e. - non-GIC) interrupt controller. + non-GIC or NVIC) interrupt controller. A number of Cortex-A and Cortex-R cores (Cortex-A5, Cortex-R4/5, ...) allow interfacing to a custom external interrupt controller and this option must be selected when such cores are connected to an interrupt - controller that is not the ARM Generic Interrupt Controller (GIC). + controller that is not the ARM Generic Interrupt Controller (GIC) or + the Cortex-M ARM Nested Vectored Interrupt Controller (NVIC). When this option is selected, the architecture interrupt control functions are mapped to the SoC interrupt control interface, which is implemented at the SoC level. - N.B. This option is only applicable to the Cortex-A and Cortex-R - family cores. The Cortex-M family cores are always equipped with - the ARM Nested Vectored Interrupt Controller (NVIC). + N.B. Since all Cortex-M cores have a NVIC, if this option is selected it + is assumed that the custom interrupt control interface implementation + assumes responsibility for handling the NVIC. config CODE_DATA_RELOCATION_SRAM bool "Relocate code/data sections to SRAM" diff --git a/arch/arm/core/CMakeLists.txt b/arch/arm/core/CMakeLists.txt index 1b4fa58eae5c115..41e3dc485ffcf34 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) diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index a06b4cb5e9570cd..e446eb25c1db25b 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -34,11 +34,12 @@ config CPU_AARCH32_CORTEX_R select HAS_CMSIS_CORE select ARCH_HAS_NESTED_EXCEPTION_DETECTION select HAS_FLASH_LOAD_OFFSET - select ARCH_HAS_USERSPACE if ARM_MPU - select ARCH_HAS_EXTRA_EXCEPTION_INFO + select ARCH_HAS_USERSPACE if ARM_MPU && !USE_SWITCH + select ARCH_HAS_EXTRA_EXCEPTION_INFO if !USE_SWITCH select ARCH_HAS_CODE_DATA_RELOCATION select ARCH_HAS_NOCACHE_MEMORY_SUPPORT if ARM_MPU && CPU_HAS_ARM_MPU && CPU_HAS_DCACHE select ARCH_SUPPORTS_ROM_START + select USE_SWITCH_SUPPORTED help This option signifies the use of a CPU of the Cortex-R family. @@ -54,11 +55,21 @@ config CPU_AARCH32_CORTEX_A select CPU_HAS_MMU select HAS_CMSIS_CORE select HAS_FLASH_LOAD_OFFSET - select ARCH_HAS_EXTRA_EXCEPTION_INFO + 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 @@ -266,17 +277,11 @@ choice config FP_HARDABI bool "Floating point Hard ABI" - # TF-M build system does not build the NS app and libraries correctly with Hard ABI. - # This limitation should be removed in the next TF-M synchronization. - depends on !TFM_BUILD_NS - depends on !(BUILD_WITH_TFM && !TFM_IPC) help This option selects the Floating point ABI in which hardware floating 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/CMakeLists.txt b/arch/arm/core/cortex_a_r/CMakeLists.txt index 8b0dac374ee2b70..d4e18a614f0ab09 100644 --- a/arch/arm/core/cortex_a_r/CMakeLists.txt +++ b/arch/arm/core/cortex_a_r/CMakeLists.txt @@ -4,7 +4,6 @@ zephyr_library() zephyr_library_sources( exc.S - exc_exit.S fault.c irq_init.c reboot.c @@ -12,12 +11,11 @@ zephyr_library_sources( stacks.c tcm.c vector_table.S - swap.c - swap_helper.S irq_manage.c prep_c.c thread.c cpu_idle.S + smp.c ) zephyr_library_sources_ifdef(CONFIG_GEN_SW_ISR_TABLE isr_wrapper.S) @@ -25,3 +23,5 @@ zephyr_library_sources_ifdef(CONFIG_USERSPACE thread.c) zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c) zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE __aeabi_read_tp.S) zephyr_library_sources_ifdef(CONFIG_ARCH_CACHE cache.c) +zephyr_library_sources_ifdef(CONFIG_USE_SWITCH switch.S) +zephyr_library_sources_ifndef(CONFIG_USE_SWITCH swap.c swap_helper.S exc_exit.S) diff --git a/arch/arm/core/cortex_a_r/Kconfig b/arch/arm/core/cortex_a_r/Kconfig index 10bf721a87006ab..3ec57cc408e1bc9 100644 --- a/arch/arm/core/cortex_a_r/Kconfig +++ b/arch/arm/core/cortex_a_r/Kconfig @@ -99,7 +99,7 @@ config CPU_CORTEX_R52 select AARCH32_ARMV8_R select CPU_HAS_ICACHE select CPU_HAS_DCACHE - select VFP_SP_D16 + select VFP_SP_D16 if !USE_SWITCH help This option signifies the use of a Cortex-R52 CPU @@ -130,6 +130,7 @@ config ARMV7_R_FP config AARCH32_ARMV8_R bool select ATOMIC_OPERATIONS_BUILTIN + select SCHED_IPI_SUPPORTED if SMP help This option signifies the use of an ARMv8-R AArch32 processor implementation. @@ -188,3 +189,6 @@ config ICACHE_LINE_SIZE default 32 endif # CPU_AARCH32_CORTEX_R + +config TEST_EXTRA_STACK_SIZE + default 1024 if SMP diff --git a/arch/arm/core/cortex_a_r/__aeabi_read_tp.S b/arch/arm/core/cortex_a_r/__aeabi_read_tp.S index 25e240b39d3434f..40874c4a1fa0b77 100644 --- a/arch/arm/core/cortex_a_r/__aeabi_read_tp.S +++ b/arch/arm/core/cortex_a_r/__aeabi_read_tp.S @@ -11,5 +11,8 @@ _ASM_FILE_PROLOGUE GTEXT(__aeabi_read_tp) SECTION_FUNC(text, __aeabi_read_tp) - mrc 15, 0, r0, c13, c0, 3 + /* + * TPIDRURW will be used as a base pointer point to TLS aera. + */ + mrc 15, 0, r0, c13, c0, 2 bx lr diff --git a/arch/arm/core/cortex_a_r/boot.h b/arch/arm/core/cortex_a_r/boot.h new file mode 100644 index 000000000000000..7eeba8b6adae667 --- /dev/null +++ b/arch/arm/core/cortex_a_r/boot.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Definitions for boot code + */ + +#ifndef _BOOT_H_ +#define _BOOT_H_ + +#ifndef _ASMLANGUAGE + +extern void *_vector_table[]; +extern void __start(void); + +#endif /* _ASMLANGUAGE */ + +/* Offsets into the boot_params structure */ +#define BOOT_PARAM_MPID_OFFSET 0 +#define BOOT_PARAM_IRQ_SP_OFFSET 4 +#define BOOT_PARAM_FIQ_SP_OFFSET 8 +#define BOOT_PARAM_ABT_SP_OFFSET 12 +#define BOOT_PARAM_UDF_SP_OFFSET 16 +#define BOOT_PARAM_SVC_SP_OFFSET 20 +#define BOOT_PARAM_SYS_SP_OFFSET 24 + +#endif /* _BOOT_H_ */ diff --git a/arch/arm/core/cortex_a_r/exc.S b/arch/arm/core/cortex_a_r/exc.S index 87742b39808126c..78414fcd0a19393 100644 --- a/arch/arm/core/cortex_a_r/exc.S +++ b/arch/arm/core/cortex_a_r/exc.S @@ -27,6 +27,7 @@ #include #include #include +#include "macro_priv.inc" _ASM_FILE_PROLOGUE @@ -41,6 +42,8 @@ GTEXT(z_arm_undef_instruction) GTEXT(z_arm_prefetch_abort) GTEXT(z_arm_data_abort) +#ifndef CONFIG_USE_SWITCH + .macro exception_entry mode /* * Store r0-r3, r12, lr, lr_und and spsr_und into the stack to @@ -86,10 +89,10 @@ GTEXT(z_arm_data_abort) #endif /* Increment exception nesting count */ - ldr r2, =_kernel - ldr r1, [r2, #_kernel_offset_to_nested] + get_cpu r2 + ldr r1, [r2, #___cpu_t_nested_OFFSET] add r1, r1, #1 - str r1, [r2, #_kernel_offset_to_nested] + str r1, [r2, #___cpu_t_nested_OFFSET] .endm .macro exception_exit @@ -128,10 +131,10 @@ SECTION_SUBSEC_FUNC(TEXT, __exc, z_arm_undef_instruction) sub sp, #24 /* Increment exception nesting count */ - ldr r2, =_kernel - ldr r1, [r2, #_kernel_offset_to_nested] + get_cpu r2 + ldr r1, [r2, #___cpu_t_nested_OFFSET] add r1, r1, #1 - str r1, [r2, #_kernel_offset_to_nested] + str r1, [r2, #___cpu_t_nested_OFFSET] #if defined(CONFIG_FPU_SHARING) sub sp, #___fpu_t_SIZEOF @@ -232,3 +235,59 @@ SECTION_SUBSEC_FUNC(TEXT, __exc, z_arm_data_abort) streq r1, [sp, #24 + FPU_SF_SIZE] b z_arm_exc_exit + +#else +/** + * @brief Undefined instruction exception handler + * + * An undefined instruction (UNDEF) exception is generated when an undefined + * instruction, or a VFP instruction when the VFP is not enabled, is + * encountered. + */ +SECTION_SUBSEC_FUNC(TEXT, __exc, z_arm_undef_instruction) + /* + * The undefined instruction address is offset by 2 if the previous + * mode is Thumb; otherwise, it is offset by 4. + */ + push {r0} + mrs r0, spsr + tst r0, #T_BIT + subeq lr, #4 /* ARM (!T_BIT) */ + subne lr, #2 /* Thumb (T_BIT) */ + pop {r0} + + z_arm_cortex_ar_enter_exc + bl z_arm_fault_undef_instruction + b z_arm_cortex_ar_exit_exc + +/** + * @brief Prefetch abort exception handler + * + * A prefetch abort (PABT) exception is generated when the processor marks the + * prefetched instruction as invalid and the instruction is executed. + */ +SECTION_SUBSEC_FUNC(TEXT, __exc, z_arm_prefetch_abort) + /* + * The faulting instruction address is always offset by 4 for the + * prefetch abort exceptions. + */ + sub lr, #4 + z_arm_cortex_ar_enter_exc + bl z_arm_fault_prefetch + b z_arm_cortex_ar_exit_exc + +/** + * @brief Data abort exception handler + * + * A data abort (DABT) exception is generated when an error occurs on a data + * memory access. This exception can be either synchronous or asynchronous, + * depending on the type of fault that caused it. + */ +SECTION_SUBSEC_FUNC(TEXT, __exc, z_arm_data_abort) + sub lr, #8 + + z_arm_cortex_ar_enter_exc + bl z_arm_fault_data + b z_arm_cortex_ar_exit_exc + +#endif diff --git a/arch/arm/core/cortex_a_r/exc_exit.S b/arch/arm/core/cortex_a_r/exc_exit.S index 67fc5fa6e00fd0b..499fa17d30a4719 100644 --- a/arch/arm/core/cortex_a_r/exc_exit.S +++ b/arch/arm/core/cortex_a_r/exc_exit.S @@ -18,6 +18,7 @@ #include #include #include +#include "macro_priv.inc" _ASM_FILE_PROLOGUE @@ -52,8 +53,8 @@ GDATA(_kernel) bne system_thread_exit\@ /* Restore user stack pointer */ - ldr r0, =_kernel - ldr r0, [r0, #_kernel_offset_to_current] + get_cpu r0 + ldr r0, [r0, #___cpu_t_current_OFFSET] cps #MODE_SYS ldr sp, [r0, #_thread_offset_to_sp_usr] /* sp_usr */ cps #MODE_SVC @@ -68,8 +69,8 @@ system_thread_exit\@: * If the floating point context pointer is null, then a context was * saved so restore the float context from the exception stack frame. */ - ldr r2, =_kernel - ldr r1, [r2, #_kernel_offset_to_fp_ctx] + get_cpu r2 + ldr r1, [r2, #___cpu_t_fp_ctx_OFFSET] cmp r1, #0 beq vfp_restore\@ @@ -79,7 +80,7 @@ system_thread_exit\@: */ cmp r0, #0 moveq r1, #0 - streq r1, [r2, #_kernel_offset_to_fp_ctx] + streq r1, [r2, #___cpu_t_fp_ctx_OFFSET] b vfp_exit\@ vfp_restore\@: @@ -140,23 +141,24 @@ SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, z_arm_int_exit) #ifdef CONFIG_PREEMPT_ENABLED /* Do not context switch if exiting a nested interrupt */ - ldr r3, =_kernel - ldr r0, [r3, #_kernel_offset_to_nested] + get_cpu r3 + ldr r0, [r3, #___cpu_t_nested_OFFSET] cmp r0, #1 bhi __EXIT_INT - ldr r1, [r3, #_kernel_offset_to_current] - ldr r0, [r3, #_kernel_offset_to_ready_q_cache] + ldr r1, [r3, #___cpu_t_current_OFFSET] + ldr r2, =_kernel + ldr r0, [r2, #_kernel_offset_to_ready_q_cache] cmp r0, r1 blne z_arm_do_swap __EXIT_INT: #endif /* CONFIG_PREEMPT_ENABLED */ /* Decrement interrupt nesting count */ - ldr r2, =_kernel - ldr r0, [r2, #_kernel_offset_to_nested] + get_cpu r2 + ldr r0, [r2, #___cpu_t_nested_OFFSET] sub r0, r0, #1 - str r0, [r2, #_kernel_offset_to_nested] + str r0, [r2, #___cpu_t_nested_OFFSET] /* Restore previous stack pointer */ pop {r2, r3} @@ -207,8 +209,8 @@ __EXIT_INT: */ SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, z_arm_exc_exit) /* Do not context switch if exiting a nested exception */ - ldr r3, =_kernel - ldr r1, [r3, #_kernel_offset_to_nested] + get_cpu r3 + ldr r1, [r3, #___cpu_t_nested_OFFSET] cmp r1, #1 bhi __EXIT_EXC @@ -239,10 +241,10 @@ SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, z_arm_exc_exit) bl z_arm_do_swap /* Decrement exception nesting count */ - ldr r3, =_kernel - ldr r0, [r3, #_kernel_offset_to_nested] + get_cpu r3 + ldr r0, [r3, #___cpu_t_nested_OFFSET] sub r0, r0, #1 - str r0, [r3, #_kernel_offset_to_nested] + str r0, [r3, #___cpu_t_nested_OFFSET] /* Return to the switched thread */ cps #MODE_SYS @@ -255,9 +257,9 @@ SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, z_arm_exc_exit) __EXIT_EXC: /* Decrement exception nesting count */ - ldr r0, [r3, #_kernel_offset_to_nested] + ldr r0, [r3, #___cpu_t_nested_OFFSET] sub r0, r0, #1 - str r0, [r3, #_kernel_offset_to_nested] + str r0, [r3, #___cpu_t_nested_OFFSET] #if defined(CONFIG_FPU_SHARING) add sp, sp, #___fpu_t_SIZEOF diff --git a/arch/arm/core/cortex_a_r/fault.c b/arch/arm/core/cortex_a_r/fault.c index 752fe5a95f00795..a39efeb96e02768 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) @@ -147,7 +152,7 @@ bool z_arm_fault_undef_instruction_fp(void) __set_FPEXC(FPEXC_EN); - if (_kernel.cpus[0].nested > 1) { + if (_current_cpu->nested > 1) { /* * If the nested count is greater than 1, the undefined * instruction exception came from an irq/svc context. (The @@ -155,12 +160,12 @@ bool z_arm_fault_undef_instruction_fp(void) * the undef exception would increment it to 2). */ struct __fpu_sf *spill_esf = - (struct __fpu_sf *)_kernel.cpus[0].fp_ctx; + (struct __fpu_sf *)_current_cpu->fp_ctx; if (spill_esf == NULL) return false; - _kernel.cpus[0].fp_ctx = NULL; + _current_cpu->fp_ctx = NULL; /* * If the nested count is 2 and the current thread has used the @@ -170,9 +175,9 @@ bool z_arm_fault_undef_instruction_fp(void) * saved exception stack frame, then save the floating point * context because it is about to be overwritten. */ - if (((_kernel.cpus[0].nested == 2) + if (((_current_cpu->nested == 2) && (_current->base.user_options & K_FP_REGS)) - || ((_kernel.cpus[0].nested > 2) + || ((_current_cpu->nested > 2) && (spill_esf->undefined & FPEXC_EN))) { /* * Spill VFP registers to specified exception stack @@ -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/isr_wrapper.S b/arch/arm/core/cortex_a_r/isr_wrapper.S index dc5fa9cac048750..0cd30e0a34313c3 100644 --- a/arch/arm/core/cortex_a_r/isr_wrapper.S +++ b/arch/arm/core/cortex_a_r/isr_wrapper.S @@ -22,6 +22,7 @@ #include #include #include +#include "macro_priv.inc" _ASM_FILE_PROLOGUE @@ -31,6 +32,7 @@ GDATA(_sw_isr_table) GTEXT(_isr_wrapper) GTEXT(z_arm_int_exit) +#ifndef CONFIG_USE_SWITCH /** * * @brief Wrapper around ISRs when inserted in software ISR table @@ -57,8 +59,8 @@ SECTION_FUNC(TEXT, _isr_wrapper) cmp r0, #MODE_USR bne isr_system_thread - ldr r0, =_kernel - ldr r0, [r0, #_kernel_offset_to_current] + get_cpu r0 + ldr r0, [r0, #___cpu_t_current_OFFSET] /* Save away user stack pointer */ cps #MODE_SYS @@ -108,10 +110,10 @@ _vfp_not_enabled: * Mark where to store the floating context for the undefined * instruction handler */ - ldr r2, =_kernel - ldr r0, [r2, #_kernel_offset_to_fp_ctx] + get_cpu r2 + ldr r0, [r2, #___cpu_t_fp_ctx_OFFSET] cmp r0, #0 - streq sp, [r2, #_kernel_offset_to_fp_ctx] + streq sp, [r2, #___cpu_t_fp_ctx_OFFSET] #endif /* CONFIG_FPU_SHARING */ /* @@ -139,10 +141,10 @@ _vfp_not_enabled: push {r2, r3} /* Increment interrupt nesting count */ - ldr r2, =_kernel - ldr r0, [r2, #_kernel_offset_to_nested] + get_cpu r2 + ldr r0, [r2, #___cpu_t_nested_OFFSET] add r0, r0, #1 - str r0, [r2, #_kernel_offset_to_nested] + str r0, [r2, #___cpu_t_nested_OFFSET] #ifdef CONFIG_TRACING_ISR bl sys_trace_isr_enter @@ -227,3 +229,145 @@ spurious_continue: * z_arm_int_exit() */ ldr r1, =z_arm_int_exit bx r1 + +#else +/** + * + * @brief Wrapper around ISRs when inserted in software ISR table + * + * When inserted in the vector table, _isr_wrapper() demuxes the ISR table + * using the running interrupt number as the index, and invokes the registered + * ISR with its corresponding argument. When returning from the ISR, it + * determines if a context switch needs to happen and invoke the arch_switch + * function if so. + * + */ +SECTION_FUNC(TEXT, _isr_wrapper) + sub lr, #4 + z_arm_cortex_ar_enter_exc + + /* Increment interrupt nesting count */ + get_cpu r2 + ldr r0, [r2, #___cpu_t_nested_OFFSET] + add r0, #1 + str r0, [r2, #___cpu_t_nested_OFFSET] + + /* If not nested: switch to IRQ stack and save current sp on it. */ + cmp r0, #1 + bhi 1f + mov r0, sp + cps #MODE_IRQ + push {r0} +1: +#ifdef CONFIG_TRACING_ISR + bl sys_trace_isr_enter +#endif /* CONFIG_TRACING_ISR */ + +#ifdef CONFIG_PM + /* + * All interrupts are disabled when handling idle wakeup. For tickless + * idle, this ensures that the calculation and programming of the + * device for the next timer deadline is not interrupted. For + * non-tickless idle, this ensures that the clearing of the kernel idle + * state is not interrupted. In each case, z_pm_save_idle_exit + * is called with interrupts disabled. + */ + + /* is this a wakeup from idle ? */ + ldr r2, =_kernel + /* requested idle duration, in ticks */ + ldr r0, [r2, #_kernel_offset_to_idle] + cmp r0, #0 + + beq _idle_state_cleared + movs r1, #0 + /* clear kernel idle state */ + str r1, [r2, #_kernel_offset_to_idle] + bl z_pm_save_idle_exit +_idle_state_cleared: +#endif /* CONFIG_PM */ + + /* Get active IRQ number from the interrupt controller */ +#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + bl arm_gic_get_active +#else + bl z_soc_irq_get_active +#endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ + + push {r0, r1} + lsl r0, r0, #3 /* table is 8-byte wide */ + + /* + * Skip calling the isr if it is a spurious interrupt. + */ + mov r1, #CONFIG_NUM_IRQS + lsl r1, r1, #3 + cmp r0, r1 + bge spurious_continue + + ldr r1, =_sw_isr_table + add r1, r1, r0 /* table entry: ISRs must have their MSB set to stay + * in thumb mode */ + ldm r1!,{r0,r3} /* arg in r0, ISR in r3 */ + + /* + * Enable and disable interrupts again to allow nested in exception handlers. + */ + cpsie i + blx r3 /* call ISR */ + cpsid i + +spurious_continue: + /* Signal end-of-interrupt */ + pop {r0, r1} +#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + bl arm_gic_eoi +#else + bl z_soc_irq_eoi +#endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ + +#ifdef CONFIG_TRACING_ISR + bl sys_trace_isr_exit +#endif + +GTEXT(z_arm_cortex_ar_irq_done) +z_arm_cortex_ar_irq_done: + /* Decrement interrupt nesting count */ + get_cpu r2 + ldr r0, [r2, #___cpu_t_nested_OFFSET] + sub r0, r0, #1 + str r0, [r2, #___cpu_t_nested_OFFSET] + /* Do not context switch if exiting a nested interrupt */ + cmp r0, #0 + bhi __EXIT_INT + + /* retrieve pointer to the current thread */ + pop {r0} + cps #MODE_SYS + mov sp, r0 + + ldr r1, [r2, #___cpu_t_current_OFFSET] + push {r1} + mov r0, #0 + bl z_get_next_switch_handle + + pop {r1} + cmp r0, #0 + beq __EXIT_INT + + /* + * Switch thread + * r0: new thread + * r1: old thread + */ + bl z_arm_context_switch + +__EXIT_INT: + +#ifdef CONFIG_STACK_SENTINEL + bl z_check_stack_sentinel +#endif /* CONFIG_STACK_SENTINEL */ + + b z_arm_cortex_ar_exit_exc + +#endif diff --git a/arch/arm/core/cortex_a_r/macro_priv.inc b/arch/arm/core/cortex_a_r/macro_priv.inc new file mode 100644 index 000000000000000..e02433692f94551 --- /dev/null +++ b/arch/arm/core/cortex_a_r/macro_priv.inc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _MACRO_PRIV_INC_ +#define _MACRO_PRIV_INC_ + +#include + +/* + * Get CPU id + */ + +.macro get_cpu_id rreg0 + /* Read MPIDR register */ + mrc p15, 0, \rreg0, c0, c0, 5 + ubfx \rreg0, \rreg0, #0, #24 +.endm + +.macro get_cpu rreg0 + /* + * Get CPU pointer. + */ + mrc p15, 0, \rreg0, c13, c0, 3 + and \rreg0, #TPIDRURO_CURR_CPU +.endm + +.macro z_arm_cortex_ar_enter_exc + /* + * Store r0-r3, r12, lr into the stack to construct an exception + * stack frame. + */ + srsdb sp!, #MODE_SYS + cps #MODE_SYS + stmdb sp, {r0-r3, r12, lr}^ + sub sp, #24 + + /* TODO: EXTRA_EXCEPTION_INFO */ + mov r0, sp + + /* increment exception depth */ + get_cpu r2 + ldrb r1, [r2, #_cpu_offset_to_exc_depth] + add r1, r1, #1 + strb r1, [r2, #_cpu_offset_to_exc_depth] +.endm + +#endif /* _MACRO_PRIV_INC_ */ diff --git a/arch/arm/core/cortex_a_r/prep_c.c b/arch/arm/core/cortex_a_r/prep_c.c index dc7786af59ee334..e510d06ee956442 100644 --- a/arch/arm/core/cortex_a_r/prep_c.c +++ b/arch/arm/core/cortex_a_r/prep_c.c @@ -44,6 +44,13 @@ Z_GENERIC_SECTION(.vt_pointer_section) __attribute__((used)) void *_vector_table_pointer; #endif +#ifdef CONFIG_ARM_MPU +extern void z_arm_mpu_init(void); +extern void z_arm_configure_static_mpu_regions(void); +#elif defined(CONFIG_ARM_AARCH32_MMU) +extern int z_arm_mmu_init(void); +#endif + #if defined(CONFIG_AARCH32_ARMV8_R) #define VECTOR_ADDRESS ((uintptr_t)_vector_start) @@ -138,8 +145,11 @@ 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]); + relocate_vector_table(); #if defined(CONFIG_CPU_HAS_FPU) z_arm_floating_point_init(); @@ -150,6 +160,12 @@ void z_arm_prep_c(void) z_arm_init_stacks(); #endif z_arm_interrupt_init(); +#ifdef CONFIG_ARM_MPU + z_arm_mpu_init(); + z_arm_configure_static_mpu_regions(); +#elif defined(CONFIG_ARM_AARCH32_MMU) + z_arm_mmu_init(); +#endif z_cstart(); CODE_UNREACHABLE; } diff --git a/arch/arm/core/cortex_a_r/reset.S b/arch/arm/core/cortex_a_r/reset.S index c72f0814c7ab6fb..0b107fbf596afc7 100644 --- a/arch/arm/core/cortex_a_r/reset.S +++ b/arch/arm/core/cortex_a_r/reset.S @@ -18,6 +18,8 @@ #include #include #include "vector_table.h" +#include "boot.h" +#include "macro_priv.inc" _ASM_FILE_PROLOGUE @@ -40,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. * */ @@ -76,6 +78,7 @@ SECTION_SUBSEC_FUNC(TEXT, _reset_section, __start) EL1_Reset_Handler: #endif + #if defined(CONFIG_DCLS) /* * Initialise CPU registers to a defined state if the processor is @@ -196,33 +199,72 @@ EL1_Reset_Handler: #endif /* CONFIG_DCLS */ + ldr r0, =arm_cpu_boot_params +#if CONFIG_MP_MAX_NUM_CPUS > 1 + get_cpu_id r1 + + ldrex r2, [r0, #BOOT_PARAM_MPID_OFFSET] + cmp r2, #-1 + bne 1f + strex r3, r1, [r0, #BOOT_PARAM_MPID_OFFSET] + cmp r3, #0 + beq _primary_core + +1: + dmb ld + ldr r2, [r0, #BOOT_PARAM_MPID_OFFSET] + cmp r1, r2 + bne 1b + + /* we can now move on */ + 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] + ldr r8, [r0, #BOOT_PARAM_UDF_SP_OFFSET] + ldr r9, [r0, #BOOT_PARAM_SVC_SP_OFFSET] + ldr r10, [r0, #BOOT_PARAM_SYS_SP_OFFSET] + b 2f + +_primary_core: +#endif + + 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) + ldr r8, =(z_arm_undef_stack + CONFIG_ARMV7_EXCEPTION_STACK_SIZE) + ldr r9, =(z_arm_svc_stack + CONFIG_ARMV7_SVC_STACK_SIZE) + ldr r10, =(z_arm_sys_stack + CONFIG_ARMV7_SYS_STACK_SIZE) + +2: /* * Configure stack. */ /* FIQ mode stack */ msr CPSR_c, #(MODE_FIQ | I_BIT | F_BIT) - ldr sp, =(z_arm_fiq_stack + CONFIG_ARMV7_FIQ_STACK_SIZE) + mov sp, r5 /* IRQ mode stack */ msr CPSR_c, #(MODE_IRQ | I_BIT | F_BIT) - ldr sp, =(z_interrupt_stacks + CONFIG_ISR_STACK_SIZE) + mov sp, r6 /* ABT mode stack */ msr CPSR_c, #(MODE_ABT | I_BIT | F_BIT) - ldr sp, =(z_arm_abort_stack + CONFIG_ARMV7_EXCEPTION_STACK_SIZE) + mov sp, r7 /* UND mode stack */ msr CPSR_c, #(MODE_UND | I_BIT | F_BIT) - ldr sp, =(z_arm_undef_stack + CONFIG_ARMV7_EXCEPTION_STACK_SIZE) + mov sp, r8 /* SVC mode stack */ msr CPSR_c, #(MODE_SVC | I_BIT | F_BIT) - ldr sp, =(z_arm_svc_stack + CONFIG_ARMV7_SVC_STACK_SIZE) + mov sp, r9 /* SYS mode stack */ msr CPSR_c, #(MODE_SYS | I_BIT | F_BIT) - ldr sp, =(z_arm_sys_stack + CONFIG_ARMV7_SYS_STACK_SIZE) + mov sp, r10 #if defined(CONFIG_PLATFORM_SPECIFIC_INIT) /* Execute platform-specific initialisation if applicable */ @@ -238,4 +280,4 @@ EL1_Reset_Handler: bl z_arm_tcm_disable_ecc #endif - b z_arm_prep_c + bx r4 diff --git a/arch/arm/core/cortex_a_r/smp.c b/arch/arm/core/cortex_a_r/smp.c new file mode 100644 index 000000000000000..f581c7703104060 --- /dev/null +++ b/arch/arm/core/cortex_a_r/smp.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "boot.h" +#include "zephyr/cache.h" +#include "zephyr/kernel/thread_stack.h" +#include "zephyr/toolchain/gcc.h" + +#define INV_MPID UINT32_MAX + +#define SGI_SCHED_IPI 0 +#define SGI_MMCFG_IPI 1 +#define SGI_FPU_IPI 2 + +K_KERNEL_PINNED_STACK_ARRAY_DECLARE(z_interrupt_stacks, + CONFIG_MP_MAX_NUM_CPUS, + CONFIG_ISR_STACK_SIZE); + +K_KERNEL_STACK_ARRAY_DECLARE(z_arm_fiq_stack, + CONFIG_MP_MAX_NUM_CPUS, + CONFIG_ARMV7_FIQ_STACK_SIZE); + +K_KERNEL_STACK_ARRAY_DECLARE(z_arm_abort_stack, + CONFIG_MP_MAX_NUM_CPUS, + CONFIG_ARMV7_EXCEPTION_STACK_SIZE); + +K_KERNEL_STACK_ARRAY_DECLARE(z_arm_undef_stack, + CONFIG_MP_MAX_NUM_CPUS, + CONFIG_ARMV7_EXCEPTION_STACK_SIZE); + +K_KERNEL_STACK_ARRAY_DECLARE(z_arm_svc_stack, + CONFIG_MP_MAX_NUM_CPUS, + CONFIG_ARMV7_SVC_STACK_SIZE); + +K_KERNEL_STACK_ARRAY_DECLARE(z_arm_sys_stack, + CONFIG_MP_MAX_NUM_CPUS, + CONFIG_ARMV7_SVC_STACK_SIZE); + +struct boot_params { + uint32_t mpid; + char *irq_sp; + char *fiq_sp; + char *abt_sp; + char *udf_sp; + char *svc_sp; + char *sys_sp; + arch_cpustart_t fn; + void *arg; + int cpu_num; +}; + +/* Offsets used in reset.S */ +BUILD_ASSERT(offsetof(struct boot_params, mpid) == BOOT_PARAM_MPID_OFFSET); +BUILD_ASSERT(offsetof(struct boot_params, irq_sp) == BOOT_PARAM_IRQ_SP_OFFSET); +BUILD_ASSERT(offsetof(struct boot_params, fiq_sp) == BOOT_PARAM_FIQ_SP_OFFSET); +BUILD_ASSERT(offsetof(struct boot_params, abt_sp) == BOOT_PARAM_ABT_SP_OFFSET); +BUILD_ASSERT(offsetof(struct boot_params, udf_sp) == BOOT_PARAM_UDF_SP_OFFSET); +BUILD_ASSERT(offsetof(struct boot_params, svc_sp) == BOOT_PARAM_SVC_SP_OFFSET); +BUILD_ASSERT(offsetof(struct boot_params, sys_sp) == BOOT_PARAM_SYS_SP_OFFSET); + +volatile struct boot_params arm_cpu_boot_params = { + .mpid = -1, + .irq_sp = (char *)(z_interrupt_stacks + CONFIG_ISR_STACK_SIZE), + .fiq_sp = (char *)(z_arm_fiq_stack + CONFIG_ARMV7_FIQ_STACK_SIZE), + .abt_sp = (char *)(z_arm_abort_stack + CONFIG_ARMV7_EXCEPTION_STACK_SIZE), + .udf_sp = (char *)(z_arm_undef_stack + CONFIG_ARMV7_EXCEPTION_STACK_SIZE), + .svc_sp = (char *)(z_arm_svc_stack + CONFIG_ARMV7_SVC_STACK_SIZE), + .sys_sp = (char *)(z_arm_sys_stack + CONFIG_ARMV7_SYS_STACK_SIZE), +}; + +static const uint32_t cpu_node_list[] = { + DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_PATH(cpus), DT_REG_ADDR, (,))}; + +/* cpu_map saves the maping of core id and mpid */ +static uint32_t cpu_map[CONFIG_MP_MAX_NUM_CPUS] = { + [0 ... (CONFIG_MP_MAX_NUM_CPUS - 1)] = INV_MPID +}; + +#ifdef CONFIG_ARM_MPU +extern void z_arm_mpu_init(void); +extern void z_arm_configure_static_mpu_regions(void); +#elif defined(CONFIG_ARM_AARCH32_MMU) +extern int z_arm_mmu_init(void); +#endif + +/* Called from Zephyr initialization */ +void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, arch_cpustart_t fn, void *arg) +{ + int cpu_count, i, j; + uint32_t cpu_mpid = 0; + uint32_t master_core_mpid; + + /* Now it is on master core */ + __ASSERT(arch_curr_cpu()->id == 0, ""); + master_core_mpid = MPIDR_TO_CORE(GET_MPIDR()); + + cpu_count = ARRAY_SIZE(cpu_node_list); + __ASSERT(cpu_count == CONFIG_MP_MAX_NUM_CPUS, + "The count of CPU Cores nodes in dts is not equal to CONFIG_MP_MAX_NUM_CPUS\n"); + + for (i = 0, j = 0; i < cpu_count; i++) { + if (cpu_node_list[i] == master_core_mpid) { + continue; + } + if (j == cpu_num - 1) { + cpu_mpid = cpu_node_list[i]; + break; + } + j++; + } + if (i == cpu_count) { + printk("Can't find CPU Core %d from dts and failed to boot it\n", cpu_num); + return; + } + + /* Pass stack address to secondary core */ + arm_cpu_boot_params.irq_sp = Z_KERNEL_STACK_BUFFER(stack) + sz; + arm_cpu_boot_params.fiq_sp = Z_KERNEL_STACK_BUFFER(z_arm_fiq_stack[cpu_num]) + + CONFIG_ARMV7_FIQ_STACK_SIZE; + arm_cpu_boot_params.abt_sp = Z_KERNEL_STACK_BUFFER(z_arm_abort_stack[cpu_num]) + + CONFIG_ARMV7_EXCEPTION_STACK_SIZE; + arm_cpu_boot_params.udf_sp = Z_KERNEL_STACK_BUFFER(z_arm_undef_stack[cpu_num]) + + CONFIG_ARMV7_EXCEPTION_STACK_SIZE; + arm_cpu_boot_params.svc_sp = Z_KERNEL_STACK_BUFFER(z_arm_svc_stack[cpu_num]) + + CONFIG_ARMV7_SVC_STACK_SIZE; + arm_cpu_boot_params.sys_sp = Z_KERNEL_STACK_BUFFER(z_arm_sys_stack[cpu_num]) + + CONFIG_ARMV7_SYS_STACK_SIZE; + + arm_cpu_boot_params.fn = fn; + arm_cpu_boot_params.arg = arg; + arm_cpu_boot_params.cpu_num = cpu_num; + + /* store mpid last as this is our synchronization point */ + arm_cpu_boot_params.mpid = cpu_mpid; + + barrier_dsync_fence_full(); + sys_cache_data_invd_range( + (void *)&arm_cpu_boot_params, + sizeof(arm_cpu_boot_params)); + + /*! TODO: Support PSCI + * \todo Support PSCI + */ + + /* Wait secondary cores up, see arch_secondary_cpu_init */ + while (arm_cpu_boot_params.fn) { + wfe(); + } + + cpu_map[cpu_num] = cpu_mpid; + + printk("Secondary CPU core %d (MPID:%#x) is up\n", cpu_num, cpu_mpid); +} + +/* the C entry of secondary cores */ +void arch_secondary_cpu_init(void) +{ + int cpu_num = arm_cpu_boot_params.cpu_num; + arch_cpustart_t fn; + void *arg; + + __ASSERT(arm_cpu_boot_params.mpid == MPIDR_TO_CORE(GET_MPIDR()), ""); + + /* Initialize tpidrro_el0 with our struct _cpu instance address */ + write_tpidruro((uintptr_t)&_kernel.cpus[cpu_num]); + +#ifdef CONFIG_ARM_MPU + + /*! TODO: Unify mpu and mmu initialization function + * \todo Unify mpu and mmu initialization function + */ + z_arm_mpu_init(); + z_arm_configure_static_mpu_regions(); +#elif defined(CONFIG_ARM_AARCH32_MMU) + z_arm_mmu_init(); +#endif + +#ifdef CONFIG_SMP + arm_gic_secondary_init(); + + irq_enable(SGI_SCHED_IPI); + + /*! TODO: FPU irq + * \todo FPU irq + */ +#endif + + fn = arm_cpu_boot_params.fn; + arg = arm_cpu_boot_params.arg; + barrier_dsync_fence_full(); + + /* + * Secondary core clears .fn to announce its presence. + * Primary core is polling for this. We no longer own + * arm_cpu_boot_params afterwards. + */ + arm_cpu_boot_params.fn = NULL; + barrier_dsync_fence_full(); + + sev(); + + fn(arg); +} + +#ifdef CONFIG_SMP + +static void broadcast_ipi(unsigned int ipi) +{ + uint32_t mpidr = MPIDR_TO_CORE(GET_MPIDR()); + + /* + * Send SGI to all cores except itself + */ + unsigned int num_cpus = arch_num_cpus(); + + for (int i = 0; i < num_cpus; i++) { + uint32_t target_mpidr = cpu_map[i]; + uint8_t aff0; + + if (mpidr == target_mpidr || mpidr == INV_MPID) { + continue; + } + + aff0 = MPIDR_AFFLVL(target_mpidr, 0); + gic_raise_sgi(ipi, (uint64_t)target_mpidr, 1 << aff0); + } +} + +void sched_ipi_handler(const void *unused) +{ + ARG_UNUSED(unused); + + z_sched_ipi(); +} + +/* arch implementation of sched_ipi */ +void arch_sched_ipi(void) +{ + broadcast_ipi(SGI_SCHED_IPI); +} + +int arch_smp_init(void) +{ + cpu_map[0] = MPIDR_TO_CORE(GET_MPIDR()); + + /* + * SGI0 is use for sched ipi, this might be changed to use Kconfig + * option + */ + IRQ_CONNECT(SGI_SCHED_IPI, IRQ_DEFAULT_PRIORITY, sched_ipi_handler, NULL, 0); + irq_enable(SGI_SCHED_IPI); + + return 0; +} + +SYS_INIT(arch_smp_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + +#endif diff --git a/arch/arm/core/cortex_a_r/stacks.c b/arch/arm/core/cortex_a_r/stacks.c index 29a5062e299952c..0691595c35961e6 100644 --- a/arch/arm/core/cortex_a_r/stacks.c +++ b/arch/arm/core/cortex_a_r/stacks.c @@ -4,16 +4,22 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "zephyr/kernel/thread_stack.h" #include #include #include #include -K_KERNEL_STACK_DEFINE(z_arm_fiq_stack, CONFIG_ARMV7_FIQ_STACK_SIZE); -K_KERNEL_STACK_DEFINE(z_arm_abort_stack, CONFIG_ARMV7_EXCEPTION_STACK_SIZE); -K_KERNEL_STACK_DEFINE(z_arm_undef_stack, CONFIG_ARMV7_EXCEPTION_STACK_SIZE); -K_KERNEL_STACK_DEFINE(z_arm_svc_stack, CONFIG_ARMV7_SVC_STACK_SIZE); -K_KERNEL_STACK_DEFINE(z_arm_sys_stack, CONFIG_ARMV7_SYS_STACK_SIZE); +K_KERNEL_STACK_ARRAY_DEFINE(z_arm_fiq_stack, CONFIG_MP_MAX_NUM_CPUS, + CONFIG_ARMV7_FIQ_STACK_SIZE); +K_KERNEL_STACK_ARRAY_DEFINE(z_arm_abort_stack, CONFIG_MP_MAX_NUM_CPUS, + CONFIG_ARMV7_EXCEPTION_STACK_SIZE); +K_KERNEL_STACK_ARRAY_DEFINE(z_arm_undef_stack, CONFIG_MP_MAX_NUM_CPUS, + CONFIG_ARMV7_EXCEPTION_STACK_SIZE); +K_KERNEL_STACK_ARRAY_DEFINE(z_arm_svc_stack, CONFIG_MP_MAX_NUM_CPUS, + CONFIG_ARMV7_SVC_STACK_SIZE); +K_KERNEL_STACK_ARRAY_DEFINE(z_arm_sys_stack, CONFIG_MP_MAX_NUM_CPUS, + CONFIG_ARMV7_SYS_STACK_SIZE); #if defined(CONFIG_INIT_STACKS) void z_arm_init_stacks(void) diff --git a/arch/arm/core/cortex_a_r/swap.c b/arch/arm/core/cortex_a_r/swap.c index 258999be7c7965a..2f7faba741a93de 100644 --- a/arch/arm/core/cortex_a_r/swap.c +++ b/arch/arm/core/cortex_a_r/swap.c @@ -7,7 +7,7 @@ #include #include -extern const int _k_neg_eagain; +#include /* The 'key' actually represents the BASEPRI register * prior to disabling interrupts via the BASEPRI mechanism. @@ -18,7 +18,7 @@ int arch_swap(unsigned int key) { /* store off key and return value */ _current->arch.basepri = key; - _current->arch.swap_return_value = _k_neg_eagain; + _current->arch.swap_return_value = -EAGAIN; z_arm_cortex_r_svc(); irq_unlock(key); diff --git a/arch/arm/core/cortex_a_r/swap_helper.S b/arch/arm/core/cortex_a_r/swap_helper.S index c646e70cc7e58e0..548bb446aa31953 100644 --- a/arch/arm/core/cortex_a_r/swap_helper.S +++ b/arch/arm/core/cortex_a_r/swap_helper.S @@ -20,6 +20,7 @@ #include #include #include +#include "macro_priv.inc" _ASM_FILE_PROLOGUE @@ -49,9 +50,9 @@ SECTION_FUNC(TEXT, z_arm_do_swap) pop {r0, lr} #endif /* CONFIG_INSTRUMENT_THREAD_SWITCHING */ - /* load _kernel into r1 and current k_thread into r2 */ - ldr r1, =_kernel - ldr r2, [r1, #_kernel_offset_to_current] + /* load current _cpu into r1 and current k_thread into r2 */ + get_cpu r1 + ldr r2, [r1, #___cpu_t_current_OFFSET] #if defined(CONFIG_ARM_STORE_EXC_RETURN) /* Store LSB of LR (EXC_RETURN) to the thread's 'mode' word. */ @@ -81,7 +82,7 @@ SECTION_FUNC(TEXT, z_arm_do_swap) * float registers have not been saved away, so write them to the * exception stack frame. */ - ldr r0, [r1, #_kernel_offset_to_fp_ctx] + ldr r0, [r1, #___cpu_t_fp_ctx_OFFSET] cmp r0, #0 beq out_store_thread_context @@ -106,13 +107,14 @@ out_fp_inactive: * frame, so zero out the global pointer to note this. */ mov r0, #0 - str r0, [r1, #_kernel_offset_to_fp_ctx] + str r0, [r1, #___cpu_t_fp_ctx_OFFSET] #endif /* CONFIG_FPU_SHARING */ /* fetch the thread to run from the ready queue cache */ - ldr r2, [r1, #_kernel_offset_to_ready_q_cache] + ldr r3, =_kernel + ldr r2, [r3, #_kernel_offset_to_ready_q_cache] - str r2, [r1, #_kernel_offset_to_current] + str r2, [r1, #___cpu_t_current_OFFSET] #if defined(CONFIG_THREAD_LOCAL_STORAGE) /* Grab the TLS pointer */ @@ -121,10 +123,10 @@ out_fp_inactive: ldr r0, [r4] /* Store TLS pointer in the "Process ID" register. - * This register is used as a base pointer to all + * TPIDRURW is used as a base pointer to all * thread variables with offsets added by toolchain. */ - mcr 15, 0, r0, cr13, cr0, 3 + mcr 15, 0, r0, c13, c0, 2 #endif #if defined(CONFIG_ARM_STORE_EXC_RETURN) @@ -139,11 +141,6 @@ out_fp_inactive: movs r3, #0 str r3, [r2, #_thread_offset_to_basepri] -_thread_irq_disabled: - /* load _kernel into r1 and current k_thread into r2 */ - ldr r1, =_kernel - ldr r2, [r1, #_kernel_offset_to_current] - /* addr of callee-saved regs in thread in r0 */ ldr r0, =_thread_offset_to_callee_saved add r0, r2 @@ -175,9 +172,9 @@ in_fp_inactive: /* r2 contains k_thread */ mov r0, r2 /* Re-program dynamic memory map */ - push {r2, lr} + push {r0, lr} bl z_arm_configure_dynamic_mpu_regions - pop {r2, lr} + pop {r0, lr} #endif #ifdef CONFIG_INSTRUMENT_THREAD_SWITCHING @@ -217,8 +214,8 @@ SECTION_FUNC(TEXT, z_arm_svc) cmp r0, #MODE_USR bne svc_system_thread - ldr r0, =_kernel - ldr r0, [r0, #_kernel_offset_to_current] + get_cpu r0 + ldr r0, [r0, #___cpu_t_current_OFFSET] /* Save away user stack pointer */ cps #MODE_SYS @@ -265,10 +262,10 @@ _vfp_not_enabled: * Mark where to store the floating context for the undefined * instruction handler */ - ldr r2, =_kernel - ldr r0, [r2, #_kernel_offset_to_fp_ctx] + get_cpu r2 + ldr r0, [r2, #___cpu_t_fp_ctx_OFFSET] cmp r0, #0 - streq sp, [r2, #_kernel_offset_to_fp_ctx] + streq sp, [r2, #___cpu_t_fp_ctx_OFFSET] #endif /* CONFIG_FPU_SHARING */ mov ip, sp @@ -282,15 +279,16 @@ _vfp_not_enabled: push {lr} /* Align stack at double-word boundary */ + /* TODO: Question, why push {r2, r3} here */ and r3, sp, #4 sub sp, sp, r3 push {r2, r3} /* Increment interrupt nesting count */ - ldr r2, =_kernel - ldr r0, [r2, #_kernel_offset_to_nested] + get_cpu r2 + ldr r0, [r2, #___cpu_t_nested_OFFSET] add r0, r0, #1 - str r0, [r2, #_kernel_offset_to_nested] + str r0, [r2, #___cpu_t_nested_OFFSET] /* Get SVC number */ mrs r0, spsr @@ -403,8 +401,8 @@ _do_syscall: ldr r6, =K_SYSCALL_BAD valid_syscall_id: - ldr r0, =_kernel - ldr r0, [r0, #_kernel_offset_to_current] + get_cpu r0 + ldr r0, [r0, #___cpu_t_current_OFFSET] ldr r1, [r0, #_thread_offset_to_mode] bic r1, #1 /* Store (privileged) mode in thread's mode state variable */ diff --git a/arch/arm/core/cortex_a_r/switch.S b/arch/arm/core/cortex_a_r/switch.S new file mode 100644 index 000000000000000..800d46bbf94ddd5 --- /dev/null +++ b/arch/arm/core/cortex_a_r/switch.S @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Thread context switching for ARM Cortex-A and Cortex-R (AArch32) + * + * This module implements the routines necessary for thread context switching + * on ARM Cortex-A and Cortex-R CPUs. + */ + +#include +#include +#include +#include +#include +#include "macro_priv.inc" + +_ASM_FILE_PROLOGUE + +GTEXT(z_arm_svc) +GTEXT(z_arm_context_switch) +GTEXT(z_do_kernel_oops) +GTEXT(z_arm_do_syscall) + +/* + * Routine to handle context switches + * + * This function is directly called either by _isr_wrapper() in case of + * preemption, or arch_switch() in case of cooperative switching. + * + * void z_arm_context_switch(struct k_thread *new, struct k_thread *old); + */ +SECTION_FUNC(TEXT, z_arm_context_switch) + + ldr r2, =_thread_offset_to_callee_saved + add r2, r1, r2 + + stm r2, {r4-r11, sp, lr} + + /* save current thread's exception depth */ + get_cpu r2 + ldrb r3, [r2, #_cpu_offset_to_exc_depth] + strb r3, [r1, #_thread_offset_to_exception_depth] + + /* retrieve next thread's exception depth */ + ldrb r3, [r0, #_thread_offset_to_exception_depth] + strb r3, [r2, #_cpu_offset_to_exc_depth] + + /* save old thread into switch handle which is required by + * z_sched_switch_spin(). + * + * Note that this step must be done after all relevant state is + * saved. + */ + dsb + str r1, [r1, #___thread_t_switch_handle_OFFSET] + +#if defined(CONFIG_THREAD_LOCAL_STORAGE) + /* Grab the TLS pointer */ + ldr r3, [r0, #_thread_offset_to_tls] + + /* Store TLS pointer in the "Process ID" register. + * This register is used as a base pointer to all + * thread variables with offsets added by toolchain. + */ + mcr 15, 0, r3, c13, c0, 2 +#endif + + ldr r2, =_thread_offset_to_callee_saved + add r2, r0, r2 + ldm r2, {r4-r11, sp, lr} + +#if defined (CONFIG_ARM_MPU) + /* Re-program dynamic memory map */ + push {r0, lr} + bl z_arm_configure_dynamic_mpu_regions + pop {r0, lr} +#endif + +#ifdef CONFIG_INSTRUMENT_THREAD_SWITCHING + push {lr} + bl z_thread_mark_switched_in + pop {lr} +#endif + + bx lr + +/** + * + * @brief Service call handler + * + * The service call (svc) is used in the following occasions: + * - Cooperative context switching + * - IRQ offloading + * - Kernel run-time exceptions + * + */ +SECTION_FUNC(TEXT, z_arm_svc) + z_arm_cortex_ar_enter_exc + + /* Get SVC number */ + cps #MODE_SVC + mrs r0, spsr + tst r0, #0x20 + ldreq r1, [lr, #-4] + biceq r1, #0xff000000 + beq demux + + ldr r1, [lr, #-2] + and r1, #0xff + + /* + * grab service call number: + * TODO 0: context switch + * 1: irq_offload (if configured) + * 2: kernel panic or oops (software generated fatal exception) + * TODO 3: system calls for memory protection + */ +demux: + cps #MODE_SYS + + cmp r1, #_SVC_CALL_RUNTIME_EXCEPT + beq _oops + +#ifdef CONFIG_IRQ_OFFLOAD + cmp r1, #_SVC_CALL_IRQ_OFFLOAD + beq offload + b inv +offload: + get_cpu r2 + ldr r3, [r2, #___cpu_t_nested_OFFSET] + add r3, r3, #1 + str r3, [r2, #___cpu_t_nested_OFFSET] + + /* If not nested: switch to IRQ stack and save current sp on it. */ + cmp r3, #1 + bhi 1f + mov r0, sp + cps #MODE_IRQ + push {r0} + +1: + blx z_irq_do_offload + b z_arm_cortex_ar_irq_done +#endif + b inv + +_oops: + /* + * Pass the exception frame to z_do_kernel_oops. r0 contains the + * exception reason. + */ + mov r0, sp + bl z_do_kernel_oops + +inv: + mov r0, #0 /* K_ERR_CPU_EXCEPTION */ + mov r1, sp + bl z_arm_fatal_error + + /* Return here only in case of recoverable error */ + b z_arm_cortex_ar_exit_exc diff --git a/arch/arm/core/cortex_a_r/thread.c b/arch/arm/core/cortex_a_r/thread.c index c5dbdc81ba623f4..9d57563f6bdea64 100644 --- a/arch/arm/core/cortex_a_r/thread.c +++ b/arch/arm/core/cortex_a_r/thread.c @@ -125,6 +125,13 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, * initial values in all other registers/thread entries are * irrelevant. */ +#if defined(CONFIG_USE_SWITCH) + extern void z_arm_cortex_ar_exit_exc(void); + thread->switch_handle = thread; + /* thread birth happens through the exception return path */ + thread->arch.exception_depth = 1; + thread->callee_saved.lr = (uint32_t)z_arm_cortex_ar_exit_exc; +#endif } #if defined(CONFIG_MPU_STACK_GUARD) && defined(CONFIG_FPU) \ diff --git a/arch/arm/core/cortex_a_r/vector_table.S b/arch/arm/core/cortex_a_r/vector_table.S index 971f90240c80a43..8c1060e61220ccc 100644 --- a/arch/arm/core/cortex_a_r/vector_table.S +++ b/arch/arm/core/cortex_a_r/vector_table.S @@ -13,6 +13,8 @@ #include #include #include "vector_table.h" +#include "offsets_short.h" +#include "macro_priv.inc" _ASM_FILE_PROLOGUE @@ -28,4 +30,28 @@ SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table) #else ldr pc, =z_irq_spurious #endif +#ifndef CONFIG_USE_SWITCH ldr pc, =z_arm_nmi /* FIQ offset 0x1c */ +#else + ldr pc,=z_irq_spurious +#endif + + +#ifdef CONFIG_USE_SWITCH +GTEXT(z_arm_cortex_ar_exit_exc) +SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, z_arm_cortex_ar_exit_exc) + + /* decrement exception depth */ + get_cpu r2 + ldrb r1, [r2, #_cpu_offset_to_exc_depth] + sub r1, r1, #1 + strb r1, [r2, #_cpu_offset_to_exc_depth] + + /* + * Restore r0-r3, r12, lr, lr_und and spsr_und from the exception stack + * and return to the current thread. + */ + ldmia sp, {r0-r3, r12, lr}^ + add sp, #24 + rfeia sp! +#endif diff --git a/arch/arm/core/cortex_a_r/vector_table.h b/arch/arm/core/cortex_a_r/vector_table.h index 7d2122b48287c79..449b6044d9c1e9a 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/CMakeLists.txt b/arch/arm/core/cortex_m/CMakeLists.txt index 7ec2441f12f010e..225d7111bdc9ff4 100644 --- a/arch/arm/core/cortex_m/CMakeLists.txt +++ b/arch/arm/core/cortex_m/CMakeLists.txt @@ -7,7 +7,6 @@ zephyr_library_sources( fault.c fault_s.S fpu.c - irq_init.c reset.S scb.c thread_abort.c @@ -20,6 +19,7 @@ zephyr_library_sources( cpu_idle.S ) +zephyr_library_sources_ifndef(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER irq_init.c) zephyr_library_sources_ifdef(CONFIG_GEN_SW_ISR_TABLE isr_wrapper.S) zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c) zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE __aeabi_read_tp.S) diff --git a/arch/arm/core/cortex_m/Kconfig b/arch/arm/core/cortex_m/Kconfig index 95e05604783d6f2..e2a0fbb42daf4f1 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 1d9feff2e525ed3..5090381fa317d48 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/irq_manage.c b/arch/arm/core/cortex_m/irq_manage.c index cd0c6f6e5bfb28b..3940d5246d4b5d2 100644 --- a/arch/arm/core/cortex_m/irq_manage.c +++ b/arch/arm/core/cortex_m/irq_manage.c @@ -32,6 +32,8 @@ extern void z_arm_reserved(void); #define REG_FROM_IRQ(irq) (irq / NUM_IRQS_PER_REG) #define BIT_FROM_IRQ(irq) (irq % NUM_IRQS_PER_REG) +#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + void arch_irq_enable(unsigned int irq) { NVIC_EnableIRQ((IRQn_Type)irq); @@ -90,6 +92,8 @@ void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags) NVIC_SetPriority((IRQn_Type)irq, prio); } +#endif /* !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) */ + void z_arm_fatal_error(unsigned int reason, const z_arch_esf_t *esf); /** diff --git a/arch/arm/core/cortex_m/isr_wrapper.S b/arch/arm/core/cortex_m/isr_wrapper.S index 78ad6cd1e83a778..f81b577804f53ba 100644 --- a/arch/arm/core/cortex_m/isr_wrapper.S +++ b/arch/arm/core/cortex_m/isr_wrapper.S @@ -97,13 +97,24 @@ _idle_state_cleared: #endif /* CONFIG_PM */ +#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + bl z_soc_irq_get_active +#else mrs r0, IPSR /* get exception number */ +#endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ + #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) ldr r1, =16 subs r0, r1 /* get IRQ number */ +#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + push {r0} +#endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ lsls r0, #3 /* table is 8-byte wide */ #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) sub r0, r0, #16 /* get IRQ number */ +#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + push {r0} +#endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ lsl r0, r0, #3 /* table is 8-byte wide */ #else #error Unknown ARM architecture @@ -116,6 +127,11 @@ _idle_state_cleared: ldm r1!,{r0,r3} /* arg in r0, ISR in r3 */ blx r3 /* call ISR */ +#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + pop {r0} + bl z_soc_irq_eoi +#endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ + #ifdef CONFIG_TRACING_ISR bl sys_trace_isr_exit #endif diff --git a/arch/arm/core/cortex_m/prep_c.c b/arch/arm/core/cortex_m/prep_c.c index ad166775ca478d3..422d45b57e14703 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) @@ -187,7 +187,12 @@ void z_arm_prep_c(void) #endif z_bss_zero(); z_data_copy(); +#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + /* Invoke SoC-specific interrupt controller initialization */ + z_soc_irq_init(); +#else z_arm_interrupt_init(); +#endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ z_cstart(); CODE_UNREACHABLE; } diff --git a/arch/arm/core/cortex_m/reset.S b/arch/arm/core/cortex_m/reset.S index 6c5599b9fb81225..332f1a60c1087ab 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 472c82424658c52..e3c35073ea310f2 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/swap.c b/arch/arm/core/cortex_m/swap.c index f41ae2e4e8466e7..9a597ef219d62ec 100644 --- a/arch/arm/core/cortex_m/swap.c +++ b/arch/arm/core/cortex_m/swap.c @@ -7,7 +7,7 @@ #include #include -extern const int _k_neg_eagain; +#include /* The 'key' actually represents the BASEPRI register * prior to disabling interrupts via the BASEPRI mechanism. @@ -34,7 +34,7 @@ int arch_swap(unsigned int key) { /* store off key and return value */ _current->arch.basepri = key; - _current->arch.swap_return_value = _k_neg_eagain; + _current->arch.swap_return_value = -EAGAIN; /* set pending bit to make sure we will take a PendSV exception */ SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; diff --git a/arch/arm/core/cortex_m/tz/CMakeLists.txt b/arch/arm/core/cortex_m/tz/CMakeLists.txt index 67f7e0ab3671a76..19c67476e40ee05 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 8371a08bfef9ac1..000000000000000 --- 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 f79765aefbfbbbe..a10663b4821b4f6 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/elf.c b/arch/arm/core/elf.c index 0a7aa6544794841..e16af6199e63ef9 100644 --- a/arch/arm/core/elf.c +++ b/arch/arm/core/elf.c @@ -20,7 +20,7 @@ LOG_MODULE_REGISTER(elf, CONFIG_LLEXT_LOG_LEVEL); * The relocation codes for arm are well documented * https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst#relocation */ -void arch_elf_relocate(elf_rel_t *rel, uintptr_t opaddr, uintptr_t opval) +void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval) { elf_word reloc_type = ELF32_R_TYPE(rel->r_info); diff --git a/arch/arm/core/fatal.c b/arch/arm/core/fatal.c index c053bb53e4a80ce..c5adebf8ee7fb87 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 000000000000000..5386cfa619f1af5 --- /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 5281d265cd0efb9..f37b4354d4660fc 100644 --- a/arch/arm/core/mmu/arm_mmu.c +++ b/arch/arm/core/mmu/arm_mmu.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include @@ -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}, @@ -861,7 +868,7 @@ int z_arm_mmu_init(void) * @param phys 32-bit physical address. * @param size Size (in bytes) of the memory area to map. * @param flags Memory attributes & permissions. Comp. K_MEM_... - * flags in sys/mem_manage.h. + * flags in kernel/mm.h. * @retval 0 on success, -EINVAL if an invalid parameter is detected. */ static int __arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) @@ -939,7 +946,7 @@ static int __arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flag * @param phys 32-bit physical address. * @param size Size (in bytes) of the memory area to map. * @param flags Memory attributes & permissions. Comp. K_MEM_... - * flags in sys/mem_manage.h. + * flags in kernel/mm.h. */ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) { diff --git a/arch/arm/core/mpu/CMakeLists.txt b/arch/arm/core/mpu/CMakeLists.txt index 8344f4db6dfb8d2..1df6561ee528d46 100644 --- a/arch/arm/core/mpu/CMakeLists.txt +++ b/arch/arm/core/mpu/CMakeLists.txt @@ -6,6 +6,11 @@ zephyr_library_sources( arm_core_mpu.c) zephyr_library_sources_ifdef(CONFIG_CPU_HAS_ARM_MPU arm_mpu.c) zephyr_library_sources_ifdef(CONFIG_CPU_HAS_NXP_MPU nxp_mpu.c) +if(CONFIG_CPU_CORTEX_M AND NOT CONFIG_CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS) + zephyr_library_sources_ifdef(CONFIG_CPU_HAS_ARM_MPU arm_mpu_regions.c) + zephyr_library_sources_ifdef(CONFIG_CPU_HAS_NXP_MPU nxp_mpu_regions.c) +endif() + if (CONFIG_CPU_AARCH32_CORTEX_R) zephyr_library_include_directories(cortex_a_r) elseif (CONFIG_CPU_CORTEX_M) diff --git a/arch/arm/core/mpu/arm_core_mpu_dev.h b/arch/arm/core/mpu/arm_core_mpu_dev.h index ec0126e6e9b13ea..fd56131d7dc1bf1 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 9b2feffe5eea3b9..cd4c8ccd7a07f5d 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/soc/arm/common/cortex_m/arm_mpu_regions.c b/arch/arm/core/mpu/arm_mpu_regions.c similarity index 100% rename from soc/arm/common/cortex_m/arm_mpu_regions.c rename to arch/arm/core/mpu/arm_mpu_regions.c diff --git a/arch/arm/core/mpu/arm_mpu_v7_internal.h b/arch/arm/core/mpu/arm_mpu_v7_internal.h index 508d1b676004758..1fe3417901ee99b 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 1f7cb04839e2540..751786d5a4c9909 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 a0f7d174436eaf6..636bce50fae5c45 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 337f7ac365748fb..297eb38bf65610f 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/mpu/nxp_mpu.c b/arch/arm/core/mpu/nxp_mpu.c index f3d3bd715aefa8c..39d7cde6f8f52c4 100644 --- a/arch/arm/core/mpu/nxp_mpu.c +++ b/arch/arm/core/mpu/nxp_mpu.c @@ -37,8 +37,10 @@ static uint8_t static_regions_num; /* Global MPU configuration at system initialization. */ static void mpu_init(void) { +#if defined(CONFIG_SOC_FAMILY_KINETIS) /* Enable clock for the Memory Protection Unit (MPU). */ CLOCK_EnableClock(kCLOCK_Sysmpu0); +#endif } /** diff --git a/arch/arm/core/offsets/offsets_aarch32.c b/arch/arm/core/offsets/offsets_aarch32.c index 1eb63bec54f60cc..4399377134de0bd 100644 --- a/arch/arm/core/offsets/offsets_aarch32.c +++ b/arch/arm/core/offsets/offsets_aarch32.c @@ -32,6 +32,11 @@ GEN_OFFSET_SYM(_thread_arch_t, basepri); GEN_OFFSET_SYM(_thread_arch_t, swap_return_value); +#if defined(CONFIG_CPU_AARCH32_CORTEX_A) || defined(CONFIG_CPU_AARCH32_CORTEX_R) +GEN_OFFSET_SYM(_thread_arch_t, exception_depth); +GEN_OFFSET_SYM(_cpu_arch_t, exc_depth); +#endif + #if defined(CONFIG_ARM_STORE_EXC_RETURN) || defined(CONFIG_USERSPACE) GEN_OFFSET_SYM(_thread_arch_t, mode); #endif diff --git a/arch/arm/core/userspace.S b/arch/arm/core/userspace.S index bf89c7d663d26c6..3594940078da339 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/include/cortex_a_r/exc.h b/arch/arm/include/cortex_a_r/exc.h deleted file mode 100644 index b77febbc047cefb..000000000000000 --- a/arch/arm/include/cortex_a_r/exc.h +++ /dev/null @@ -1,65 +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 (_kernel.cpus[0].nested != 0U); -} - -static ALWAYS_INLINE bool arch_is_in_nested_exception(const z_arch_esf_t *esf) -{ - return (_kernel.cpus[0].nested > 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 - -extern void z_arm_cortex_r_svc(void); - -#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 000000000000000..7519016176c5efb --- /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_a_r/kernel_arch_func.h b/arch/arm/include/cortex_a_r/kernel_arch_func.h index 5bca1214da17bbb..88f631ff4b487af 100644 --- a/arch/arm/include/cortex_a_r/kernel_arch_func.h +++ b/arch/arm/include/cortex_a_r/kernel_arch_func.h @@ -25,37 +25,35 @@ extern "C" { #endif #ifndef _ASMLANGUAGE -#ifdef CONFIG_ARM_MPU -extern void z_arm_configure_static_mpu_regions(void); -extern int z_arm_mpu_init(void); -#endif /* CONFIG_ARM_MPU */ -#ifdef CONFIG_ARM_AARCH32_MMU -extern int z_arm_mmu_init(void); -#endif /* CONFIG_ARM_AARCH32_MMU */ static ALWAYS_INLINE void arch_kernel_init(void) { -#if defined(CONFIG_ARM_MPU) - z_arm_mpu_init(); - /* Configure static memory map. This will program MPU regions, - * to set up access permissions for fixed memory sections, such - * as Application Memory or No-Cacheable SRAM area. - * - * This function is invoked once, upon system initialization. - */ - z_arm_configure_static_mpu_regions(); -#endif /* CONFIG_ARM_MPU */ -#if defined(CONFIG_ARM_AARCH32_MMU) - z_arm_mmu_init(); -#endif /* CONFIG_ARM_AARCH32_MMU */ } +#ifndef CONFIG_USE_SWITCH + static ALWAYS_INLINE void arch_thread_return_value_set(struct k_thread *thread, unsigned int value) { thread->arch.swap_return_value = value; } +#else + +static ALWAYS_INLINE void arch_switch(void *switch_to, void **switched_from) +{ + extern void z_arm_context_switch(struct k_thread *new, + struct k_thread *old); + + struct k_thread *new = switch_to; + struct k_thread *old = CONTAINER_OF(switched_from, struct k_thread, + switch_handle); + + z_arm_context_switch(new, old); +} + +#endif + extern FUNC_NORETURN void z_arm_userspace_enter(k_thread_entry_t user_entry, void *p1, void *p2, void *p3, uint32_t stack_end, diff --git a/arch/arm/include/cortex_m/exc.h b/arch/arm/include/cortex_m/exc.h deleted file mode 100644 index b46e74341a92fdd..000000000000000 --- 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 000000000000000..bf86abd77c70f50 --- /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 0262376469e55df..000000000000000 --- 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 6ae5f643341d6f0..5ad19db8f84b850 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/arm/include/offsets_short_arch.h b/arch/arm/include/offsets_short_arch.h index 78a2607655c8834..4ceb1fc3f7aec30 100644 --- a/arch/arm/include/offsets_short_arch.h +++ b/arch/arm/include/offsets_short_arch.h @@ -23,6 +23,14 @@ #define _thread_offset_to_preempt_float \ (___thread_t_arch_OFFSET + ___thread_arch_t_preempt_float_OFFSET) +#if defined(CONFIG_CPU_AARCH32_CORTEX_A) || defined(CONFIG_CPU_AARCH32_CORTEX_R) +#define _thread_offset_to_exception_depth \ + (___thread_t_arch_OFFSET + ___thread_arch_t_exception_depth_OFFSET) + +#define _cpu_offset_to_exc_depth \ + (___cpu_t_arch_OFFSET + ___cpu_arch_t_exc_depth_OFFSET) +#endif + #if defined(CONFIG_USERSPACE) || defined(CONFIG_FPU_SHARING) #define _thread_offset_to_mode \ (___thread_t_arch_OFFSET + ___thread_arch_t_mode_OFFSET) diff --git a/arch/arm64/core/Kconfig b/arch/arm64/core/Kconfig index fd74a5264161a12..8f09d49a04c0f42 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/boot.h b/arch/arm64/core/boot.h index aa9e4526bba740e..d3f8e28eca3acae 100644 --- a/arch/arm64/core/boot.h +++ b/arch/arm64/core/boot.h @@ -20,7 +20,8 @@ extern void __start(void); #endif /* _ASMLANGUAGE */ /* Offsets into the boot_params structure */ -#define BOOT_PARAM_MPID_OFFSET 0 -#define BOOT_PARAM_SP_OFFSET 8 +#define BOOT_PARAM_MPID_OFFSET 0 +#define BOOT_PARAM_SP_OFFSET 8 +#define BOOT_PARAM_VOTING_OFFSET 16 #endif /* _BOOT_H_ */ diff --git a/arch/arm64/core/fatal.c b/arch/arm64/core/fatal.c index 1139a818e1f387f..dbf0c4cdae17c9e 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 74a32b8009c8676..0133eed2dcaaf6c 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 26f88aa77e6bede..1d5e3c829b88eb0 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/macro_priv.inc b/arch/arm64/core/macro_priv.inc index 616e705f47b385a..22cefe235fef6f3 100644 --- a/arch/arm64/core/macro_priv.inc +++ b/arch/arm64/core/macro_priv.inc @@ -21,6 +21,27 @@ ubfx \xreg0, \xreg0, #0, #24 .endm +/* + * Get CPU logic id by looking up cpu_node_list + * returns + * xreg0: MPID + * xreg1: logic id (0 ~ CONFIG_MP_MAX_NUM_CPUS - 1) + * clobbers: xreg0, xreg1, xreg2, xreg3 + */ +.macro get_cpu_logic_id xreg0, xreg1, xreg2, xreg3 + get_cpu_id \xreg0 + ldr \xreg3, =cpu_node_list + mov \xreg1, 0 +1: ldr \xreg2, [\xreg3, \xreg1, lsl 3] + cmp \xreg2, \xreg0 + beq 2f + add \xreg1, \xreg1, 1 + cmp \xreg1, #CONFIG_MP_MAX_NUM_CPUS + bne 1b + b . +2: +.endm + /* * Get CPU pointer * Note: keep in sync with `arch_curr_cpu` in include/zephyr/arch/arm64/arch_inlines.h diff --git a/arch/arm64/core/mmu.c b/arch/arm64/core/mmu.c index 7d5670da0f238fe..2260d22c101f73d 100644 --- a/arch/arm64/core/mmu.c +++ b/arch/arm64/core/mmu.c @@ -731,6 +731,14 @@ static inline void add_arm_mmu_region(struct arm_mmu_ptables *ptables, static inline void inv_dcache_after_map_helper(void *virt, size_t size, uint32_t attrs) { + /* + * DC IVAC instruction requires write access permission to the VA, + * otherwise it can generate a permission fault + */ + if ((attrs & MT_RW) != MT_RW) { + return; + } + if (MT_TYPE(attrs) == MT_NORMAL || MT_TYPE(attrs) == MT_NORMAL_WT) { sys_cache_data_invd_range(virt, size); } @@ -987,6 +995,7 @@ void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) case K_MEM_CACHE_WB: case K_MEM_CACHE_WT: mem_flags = (mem_flags == K_MEM_CACHE_WB) ? MT_NORMAL : MT_NORMAL_WT; + mem_flags |= (flags & K_MEM_PERM_RW) ? MT_RW : 0; inv_dcache_after_map_helper(virt, size, mem_flags); default: break; diff --git a/arch/arm64/core/prep_c.c b/arch/arm64/core/prep_c.c index c12d5e7d1c439b7..bfd3b7c1eaa90ec 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 9b3b4462e851abf..cfcffec4ce7a5ce 100644 --- a/arch/arm64/core/reset.S +++ b/arch/arm64/core/reset.S @@ -121,38 +121,75 @@ resetwait: #if CONFIG_MP_MAX_NUM_CPUS > 1 + /* + * Deal with multi core booting simultaneously to race for being the primary core. + * Use voting lock[1] with reasonable but minimal requirements on the memory system + * to make sure only one core wins at last. + * + * [1] kernel.org/doc/html/next/arch/arm/vlocks.html + */ ldr x0, =arm64_cpu_boot_params - get_cpu_id x1 /* - * If the cores start up at the same time, we should atomically load and - * store the mpid into arm64_cpu_boot_params. + * Get the "logic" id defined by cpu_node_list statically for voting lock self-identify. + * It is worth noting that this is NOT the final logic id (arch_curr_cpu()->id) */ - ldaxr x2, [x0, #BOOT_PARAM_MPID_OFFSET] - cmp x2, #-1 - bne 1f - /* try to store x1 (mpid) */ - stlxr w3, x1, [x0] - /* If succeed, go to primary_core */ - cbz w3, primary_core + get_cpu_logic_id x1, x2, x3, x4 //x1: MPID, x2: logic id + + add x4, x0, #BOOT_PARAM_VOTING_OFFSET + + /* signal our desire to vote */ + mov w5, #1 + strb w5, [x4, x2] + ldr x3, [x0, #BOOT_PARAM_MPID_OFFSET] + cmn x3, #1 + beq 1f + + /* some core already won, release */ + strb wzr, [x4, x2] + b secondary_core + + /* suggest current core then release */ +1: str x1, [x0, #BOOT_PARAM_MPID_OFFSET] + strb wzr, [x4, x2] + dmb ish + + /* then wait until every core else is done voting */ + mov x5, #0 +2: ldrb w3, [x4, x5] + tst w3, #255 + /* wait */ + bne 2b + add x5, x5, #1 + cmp x5, #CONFIG_MP_MAX_NUM_CPUS + bne 2b + + + /* check if current core won */ + dmb ish + ldr x3, [x0, #BOOT_PARAM_MPID_OFFSET] + cmp x3, x1 + beq primary_core + /* fallthrough secondary */ /* loop until our turn comes */ -1: dmb ld +secondary_core: + dmb ish ldr x2, [x0, #BOOT_PARAM_MPID_OFFSET] cmp x1, x2 - bne 1b + bne secondary_core /* we can now load our stack pointer value and move on */ ldr x24, [x0, #BOOT_PARAM_SP_OFFSET] ldr x25, =z_arm64_secondary_prep_c - b 2f + b boot primary_core: #endif /* load primary stack and entry point */ ldr x24, =(z_interrupt_stacks + __z_interrupt_stack_SIZEOF) - ldr x25, =z_arm64_prep_c -2: + ldr x25, =z_prep_c +boot: /* Prepare for calling C code */ bl __reset_prep_c @@ -211,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/reset.c b/arch/arm64/core/reset.c index bd78555de547165..f96783318f40cca 100644 --- a/arch/arm64/core/reset.c +++ b/arch/arm64/core/reset.c @@ -125,6 +125,12 @@ void z_arm64_el2_init(void) write_sctlr_el2(reg); reg = read_hcr_el2(); + /* when EL2 is enable in current security status: + * Clear TGE bit: All exceptions that would not be routed to EL2; + * Clear AMO bit: Physical SError interrupts are not taken to EL2 and EL3. + * Clear IMO bit: Physical IRQ interrupts are not taken to EL2 and EL3. + */ + reg &= ~(HCR_IMO_BIT | HCR_AMO_BIT | HCR_TGE_BIT); reg |= HCR_RW_BIT; /* EL1 Execution state is AArch64 */ write_hcr_el2(reg); diff --git a/arch/arm64/core/smp.c b/arch/arm64/core/smp.c index 6d21e5e9d7b6d15..97fd60b42363396 100644 --- a/arch/arm64/core/smp.c +++ b/arch/arm64/core/smp.c @@ -35,6 +35,7 @@ struct boot_params { uint64_t mpid; char *sp; + uint8_t voting[CONFIG_MP_MAX_NUM_CPUS]; arch_cpustart_t fn; void *arg; int cpu_num; @@ -43,12 +44,13 @@ struct boot_params { /* Offsets used in reset.S */ BUILD_ASSERT(offsetof(struct boot_params, mpid) == BOOT_PARAM_MPID_OFFSET); BUILD_ASSERT(offsetof(struct boot_params, sp) == BOOT_PARAM_SP_OFFSET); +BUILD_ASSERT(offsetof(struct boot_params, voting) == BOOT_PARAM_VOTING_OFFSET); volatile struct boot_params __aligned(L1_CACHE_BYTES) arm64_cpu_boot_params = { .mpid = -1, }; -static const uint64_t cpu_node_list[] = { +const uint64_t cpu_node_list[] = { DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_PATH(cpus), DT_REG_ADDR, (,)) }; @@ -99,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)) { @@ -120,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(); } @@ -131,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; @@ -240,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; @@ -270,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()); @@ -300,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/include/exc.h b/arch/arm64/include/exc.h deleted file mode 100644 index 03dacc7c51dc536..000000000000000 --- 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 000000000000000..6ab6bbbfeff44d4 --- /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 0b2d878537f0ba7..ec781fc902dd528 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 3b028b10b3772b3..a5c3d59d87a6ff6 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 8056ad5d95d80ea..1a89ba9c13aa86c 100644 --- a/arch/common/CMakeLists.txt +++ b/arch/common/CMakeLists.txt @@ -2,12 +2,24 @@ zephyr_library() +zephyr_library_include_directories(include) + # Library may be empty due to kconfigs zephyr_library_property(ALLOW_EMPTY TRUE) +if(CONFIG_GEN_ISR_TABLES) + zephyr_library_sources( + sw_isr_common.c + ) + zephyr_library_sources_ifdef( + CONFIG_DYNAMIC_INTERRUPTS + dynamic_isr.c + ) +endif() + zephyr_library_sources_ifdef( - CONFIG_GEN_ISR_TABLES - sw_isr_common.c + CONFIG_MULTI_LEVEL_INTERRUPTS + multilevel_irq.c ) zephyr_library_sources_ifdef(CONFIG_SHARED_INTERRUPTS shared_irq.c) diff --git a/arch/common/dynamic_isr.c b/arch/common/dynamic_isr.c new file mode 100644 index 000000000000000..9f56977f2599847 --- /dev/null +++ b/arch/common/dynamic_isr.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sw_isr_common.h" +#include +#include +#include + +void __weak z_isr_install(unsigned int irq, void (*routine)(const void *), + const void *param) +{ + unsigned int table_idx; + + /* + * Do not assert on the IRQ enable status for ARM GIC since the SGI + * type interrupts are always enabled and attempting to install an ISR + * for them will cause the assertion to fail. + */ +#ifndef CONFIG_GIC + __ASSERT(!irq_is_enabled(irq), "IRQ %d is enabled", irq); +#endif /* !CONFIG_GIC */ + + table_idx = z_get_sw_isr_table_idx(irq); + + /* If dynamic IRQs are enabled, then the _sw_isr_table is in RAM and + * can be modified + */ + _sw_isr_table[table_idx].arg = param; + _sw_isr_table[table_idx].isr = routine; +} + +/* Some architectures don't/can't interpret flags or priority and have + * no more processing to do than this. Provide a generic fallback. + */ +int __weak arch_irq_connect_dynamic(unsigned int irq, + unsigned int priority, + void (*routine)(const void *), + const void *parameter, + uint32_t flags) +{ + ARG_UNUSED(flags); + ARG_UNUSED(priority); + + z_isr_install(irq, routine, parameter); + return irq; +} diff --git a/arch/common/include/sw_isr_common.h b/arch/common/include/sw_isr_common.h new file mode 100644 index 000000000000000..223c9ba2442a2f3 --- /dev/null +++ b/arch/common/include/sw_isr_common.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Private header for the software-managed ISR table's functions + */ + +#ifndef ZEPHYR_ARCH_COMMON_INCLUDE_SW_ISR_COMMON_H_ +#define ZEPHYR_ARCH_COMMON_INCLUDE_SW_ISR_COMMON_H_ + +#if !defined(_ASMLANGUAGE) +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Helper function used to compute the index in _sw_isr_table + * based on passed IRQ. + * + * @param irq IRQ number in its zephyr format + * + * @return corresponding index in _sw_isr_table + */ +unsigned int z_get_sw_isr_table_idx(unsigned int irq); + +/** + * @brief Helper function used to get the parent interrupt controller device based on passed IRQ. + * + * @param irq IRQ number in its zephyr format + * + * @return corresponding interrupt controller device in _sw_isr_table + */ +const struct device *z_get_sw_isr_device_from_irq(unsigned int irq); + +/** + * @brief Helper function used to get the IRQN of the passed in parent interrupt + * controller device. + * + * @param dev parent interrupt controller device + * + * @return IRQN of the interrupt controller + */ +unsigned int z_get_sw_isr_irq_from_device(const struct device *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_ARCH_COMMON_INCLUDE_SW_ISR_COMMON_H_ */ diff --git a/arch/common/multilevel_irq.c b/arch/common/multilevel_irq.c new file mode 100644 index 000000000000000..53f8e03a4d84934 --- /dev/null +++ b/arch/common/multilevel_irq.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * Copyright (c) 2023 Meta. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#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 + */ +#define Z_IF_DT_IS_INTC(node_id, code) \ + 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` + */ +#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)) + +/** + * 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` + */ +#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), + +#define INIT_IRQ_PARENT_OFFSET(d, i, o) { \ + INTC_DEVICE_INIT(d) \ + .irq = i, \ + .offset = o, \ +} + +#define IRQ_INDEX_TO_OFFSET(i, base) (base + i * CONFIG_MAX_IRQ_PER_AGGREGATOR) + +#define CAT_2ND_LVL_LIST(i, base) \ + INIT_IRQ_PARENT_OFFSET(INTC_DT_IRQN_GET(CONFIG_2ND_LVL_INTR_0##i##_OFFSET), \ + CONFIG_2ND_LVL_INTR_0##i##_OFFSET, IRQ_INDEX_TO_OFFSET(i, base)) +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)) + +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) }; + +#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ + +static const struct _irq_parent_entry *get_parent_entry(unsigned int parent_irq, + const struct _irq_parent_entry list[], + unsigned int length) +{ + unsigned int i; + const struct _irq_parent_entry *entry = NULL; + + for (i = 0U; i < length; ++i) { + if (list[i].irq == parent_irq) { + entry = &list[i]; + break; + } + } + + __ASSERT(i != length, "Invalid argument: %i", parent_irq); + + return entry; +} + +const struct device *z_get_sw_isr_device_from_irq(unsigned int irq) +{ + const struct device *dev = NULL; + unsigned int level, parent_irq; + const struct _irq_parent_entry *entry = NULL; + + level = irq_get_level(irq); + + if (level == 2U) { + parent_irq = irq_parent_level_2(irq); + entry = get_parent_entry(parent_irq, + _lvl2_irq_list, + CONFIG_NUM_2ND_LEVEL_AGGREGATORS); + } +#ifdef CONFIG_3RD_LEVEL_INTERRUPTS + else if (level == 3U) { + parent_irq = irq_parent_level_3(irq); + entry = get_parent_entry(parent_irq, + _lvl3_irq_list, + CONFIG_NUM_3RD_LEVEL_AGGREGATORS); + } +#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ + dev = entry != NULL ? entry->dev : NULL; + + return dev; +} + +unsigned int z_get_sw_isr_irq_from_device(const struct device *dev) +{ + for (size_t i = 0U; i < CONFIG_NUM_2ND_LEVEL_AGGREGATORS; ++i) { + if (_lvl2_irq_list[i].dev == dev) { + return _lvl2_irq_list[i].irq; + } + } + +#ifdef CONFIG_3RD_LEVEL_INTERRUPTS + for (size_t i = 0U; i < CONFIG_NUM_3RD_LEVEL_AGGREGATORS; ++i) { + if (_lvl3_irq_list[i].dev == dev) { + return _lvl3_irq_list[i].irq; + } + } +#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ + + return 0; +} + +unsigned int z_get_sw_isr_table_idx(unsigned int irq) +{ + 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 + 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 + local_irq; + } +#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ + else { + table_idx = 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 744aece2fd7ca65..68641cb2bb0d1ae 100644 --- a/arch/common/shared_irq.c +++ b/arch/common/shared_irq.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "sw_isr_common.h" + #include #include diff --git a/arch/common/sw_isr_common.c b/arch/common/sw_isr_common.c index a5262e7fa83d5a2..43395cd59163c8a 100644 --- a/arch/common/sw_isr_common.c +++ b/arch/common/sw_isr_common.c @@ -4,147 +4,20 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "sw_isr_common.h" #include -#include #include #include + /* * Common code for arches that use software ISR tables (CONFIG_GEN_ISR_TABLES) */ -#ifdef CONFIG_DYNAMIC_INTERRUPTS - -#ifdef CONFIG_MULTI_LEVEL_INTERRUPTS - -struct irq_parent_offset { - unsigned int irq; - unsigned int offset; -}; - -#define INIT_IRQ_PARENT_OFFSET(i, o) { \ - .irq = i, \ - .offset = o, \ -} - -#define IRQ_INDEX_TO_OFFSET(i, base) (base + i * CONFIG_MAX_IRQ_PER_AGGREGATOR) - -#ifdef CONFIG_2ND_LEVEL_INTERRUPTS - -#define CAT_2ND_LVL_LIST(i, base) \ - INIT_IRQ_PARENT_OFFSET(CONFIG_2ND_LVL_INTR_0##i##_OFFSET, \ - IRQ_INDEX_TO_OFFSET(i, base)) -static struct irq_parent_offset lvl2_irq_list[CONFIG_NUM_2ND_LEVEL_AGGREGATORS] - = { LISTIFY(CONFIG_NUM_2ND_LEVEL_AGGREGATORS, CAT_2ND_LVL_LIST, (,), - CONFIG_2ND_LVL_ISR_TBL_OFFSET) }; - -#endif/* CONFIG_2ND_LEVEL_INTERRUPTS */ - -#ifdef CONFIG_3RD_LEVEL_INTERRUPTS - -#define CAT_3RD_LVL_LIST(i, base) \ - INIT_IRQ_PARENT_OFFSET(CONFIG_3RD_LVL_INTR_0##i##_OFFSET, \ - IRQ_INDEX_TO_OFFSET(i, base)) -static struct irq_parent_offset lvl3_irq_list[CONFIG_NUM_3RD_LEVEL_AGGREGATORS] - = { LISTIFY(CONFIG_NUM_3RD_LEVEL_AGGREGATORS, CAT_3RD_LVL_LIST, (,), - CONFIG_3RD_LVL_ISR_TBL_OFFSET) }; - -#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ - -unsigned int get_parent_offset(unsigned int parent_irq, - struct irq_parent_offset list[], - unsigned int length) +unsigned int __weak z_get_sw_isr_table_idx(unsigned int irq) { - unsigned int i; - unsigned int offset = 0U; - - for (i = 0U; i < length; ++i) { - if (list[i].irq == parent_irq) { - offset = list[i].offset; - break; - } - } + unsigned int table_idx = irq - CONFIG_GEN_IRQ_START_VECTOR; - __ASSERT(i != length, "Invalid argument: %i", parent_irq); - - return offset; -} - -#endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ - -unsigned int z_get_sw_isr_table_idx(unsigned int irq) -{ - unsigned int table_idx; - -#ifdef CONFIG_MULTI_LEVEL_INTERRUPTS - unsigned int level, parent_irq, parent_offset; - - level = irq_get_level(irq); - - if (level == 2U) { - parent_irq = irq_parent_level_2(irq); - parent_offset = get_parent_offset(parent_irq, - lvl2_irq_list, - CONFIG_NUM_2ND_LEVEL_AGGREGATORS); - table_idx = parent_offset + irq_from_level_2(irq); - } -#ifdef CONFIG_3RD_LEVEL_INTERRUPTS - else if (level == 3U) { - parent_irq = irq_parent_level_3(irq); - parent_offset = get_parent_offset(parent_irq, - lvl3_irq_list, - CONFIG_NUM_3RD_LEVEL_AGGREGATORS); - table_idx = parent_offset + irq_from_level_3(irq); - } -#endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ - else { - table_idx = irq; - } - - table_idx -= CONFIG_GEN_IRQ_START_VECTOR; -#else - table_idx = irq - CONFIG_GEN_IRQ_START_VECTOR; -#endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ + __ASSERT_NO_MSG(table_idx < IRQ_TABLE_SIZE); return table_idx; } - -void __weak z_isr_install(unsigned int irq, void (*routine)(const void *), - const void *param) -{ - unsigned int table_idx; - - /* - * Do not assert on the IRQ enable status for ARM GIC since the SGI - * type interrupts are always enabled and attempting to install an ISR - * for them will cause the assertion to fail. - */ -#ifndef CONFIG_GIC - __ASSERT(!irq_is_enabled(irq), "IRQ %d is enabled", irq); -#endif /* !CONFIG_GIC */ - - table_idx = z_get_sw_isr_table_idx(irq); - - /* If dynamic IRQs are enabled, then the _sw_isr_table is in RAM and - * can be modified - */ - _sw_isr_table[table_idx].arg = param; - _sw_isr_table[table_idx].isr = routine; -} - -/* Some architectures don't/can't interpret flags or priority and have - * no more processing to do than this. Provide a generic fallback. - */ -int __weak arch_irq_connect_dynamic(unsigned int irq, - unsigned int priority, - void (*routine)(const void *), - const void *parameter, - uint32_t flags) -{ - ARG_UNUSED(flags); - ARG_UNUSED(priority); - - z_isr_install(irq, routine, parameter); - return irq; -} - -#endif /* CONFIG_DYNAMIC_INTERRUPTS */ diff --git a/arch/mips/core/fatal.c b/arch/mips/core/fatal.c index 48234680a6a89d5..16011241666ab28 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 6f72699cc5bf56f..19673273b8a7e18 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 8daebf85d4ab9a9..eec75bc031b3ef0 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 8ecb37fe926669e..2f708bf26f4af2b 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 9ccb4f3fd924503..ac64b5bc309447e 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 da8fcd9d4bc6420..74a3454af48ce00 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 86cf051ccdef1ac..2ec433ad5cb9703 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") @@ -94,14 +100,18 @@ elseif (CONFIG_NATIVE_LIBRARY) # Do not use the C library from this compiler/host, # but still use the basic compiler headers - # -fno-builtin to avoid the compiler using builtin replacements for std library functions + # no_builtin to avoid the compiler using builtin replacements for std library functions zephyr_compile_options( -nostdinc -isystem ${COMPILER_OWN_INCLUDE_PATH} $ - -fno-builtin + $ ) 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 3cf83c9fdda86e4..12ec5261635c165 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 cd338ca1e4f2114..eccf419efb1bbe0 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 88a68b9fd490c1d..770dab9aac605a3 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 a1cefcbdf43a20a..2e55d446a752e53 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 0c7f5f3dac781b6..0d8e4fedeb2fcce 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 171497ff0cac021..36457a23de7f99d 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 293a5bc613fcb2c..da5d07b31464043 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 88fafd34904964e..bf0b6684a5df1ca 100644 --- a/arch/riscv/core/irq_manage.c +++ b/arch/riscv/core/irq_manage.c @@ -8,6 +8,11 @@ #include #include #include +#include + +#ifdef CONFIG_RISCV_HAS_PLIC +#include +#endif LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -19,13 +24,15 @@ 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) { - LOG_ERR("PLIC interrupt line causing the IRQ: %d", - riscv_plic_get_irq()); + if (mcause == RISCV_IRQ_MEXT) { + unsigned int save_irq = riscv_plic_get_irq(); + const struct device *save_dev = riscv_plic_get_dev(); + + LOG_ERR("PLIC interrupt line causing the IRQ: %d (%p)", save_irq, save_dev); } #endif z_riscv_fatal_error(K_ERR_SPURIOUS_IRQ, NULL); @@ -36,17 +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) { - irq = irq_from_level_2(irq); - - 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 ab90d2b1d1e50d9..422c2ce23bf9177 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) * @@ -187,10 +195,23 @@ SECTION_FUNC(exception.entry, _isr_wrapper) 1: #endif andi t0, t2, 0x7f /* keep only the opcode bits */ + /* + * Major FP opcodes: + * 0000111 = LOAD-FP + * 0100111 = STORE-FP + * 1000011 = MADD + * 1000111 = MSUB + * 1001011 = NMSUB + * 1001111 = NMADD + * 1010011 = OP-FP + */ xori t1, t0, 0b1010011 /* OP-FP */ beqz t1, is_fp - ori t0, t0, 0b0100000 - xori t1, t0, 0b0100111 /* LOAD-FP / STORE-FP */ + ori t1, t0, 0b0100000 + xori t1, t1, 0b0100111 /* LOAD-FP / STORE-FP */ + beqz t1, is_fp + ori t1, t0, 0b0001100 + xori t1, t1, 0b1001111 /* MADD / MSUB / NMSUB / NMADD */ beqz t1, is_fp /* * The FRCSR, FSCSR, FRRM, FSRM, FSRMI, FRFLAGS, FSFLAGS and FSFLAGSI @@ -270,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 @@ -281,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 */ @@ -508,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 /* @@ -544,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 7730138a3769140..96982341b1a7235 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/pmp.c b/arch/riscv/core/pmp.c index 7a3cb02cf52cff1..bfeb1c025cd26d1 100644 --- a/arch/riscv/core/pmp.c +++ b/arch/riscv/core/pmp.c @@ -161,8 +161,8 @@ static bool set_pmp_entry(unsigned int *index_p, uint8_t perm, unsigned int index = *index_p; bool ok = true; - __ASSERT((start & 0x3) == 0, "misaligned start address"); - __ASSERT((size & 0x3) == 0, "misaligned size"); + __ASSERT((start & (CONFIG_PMP_GRANULARITY - 1)) == 0, "misaligned start address"); + __ASSERT((size & (CONFIG_PMP_GRANULARITY - 1)) == 0, "misaligned size"); if (index >= index_limit) { LOG_ERR("out of PMP slots"); diff --git a/arch/riscv/core/prep_c.c b/arch/riscv/core/prep_c.c index 8b9b118b24cd75d..b0fdd3a0569c0fa 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 094e51b91836e1e..e9424e7a8e2af26 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,24 +86,32 @@ 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 + la t0, riscv_cpu_wake_flag + li t1, -1 + sr t1, 0(t0) + la t0, riscv_cpu_boot_flag + sr zero, 0(t0) + +wait_secondary_wake_flag: la t0, riscv_cpu_wake_flag lr t0, 0(t0) - bne a0, t0, boot_secondary_core + bne a0, t0, wait_secondary_wake_flag /* Set up stack */ la t0, riscv_cpu_sp lr sp, 0(t0) - la t0, riscv_cpu_wake_flag - sr zero, 0(t0) - j z_riscv_secondary_cpu_init + la t0, riscv_cpu_boot_flag + li t1, 1 + sr t1, 0(t0) + 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 0815920e8e6bdf0..54de29c05515f62 100644 --- a/arch/riscv/core/smp.c +++ b/arch/riscv/core/smp.c @@ -9,15 +9,24 @@ #include #include #include +#include +#include volatile struct { arch_cpustart_t fn; void *arg; } riscv_cpu_init[CONFIG_MP_MAX_NUM_CPUS]; -volatile uintptr_t riscv_cpu_wake_flag; +volatile uintptr_t __noinit riscv_cpu_wake_flag; +volatile uintptr_t riscv_cpu_boot_flag; 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) { @@ -25,14 +34,21 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, riscv_cpu_init[cpu_num].arg = arg; riscv_cpu_sp = Z_KERNEL_STACK_BUFFER(stack) + sz; - riscv_cpu_wake_flag = _kernel.cpus[cpu_num].arch.hartid; + riscv_cpu_boot_flag = 0U; - while (riscv_cpu_wake_flag != 0U) { - ; +#ifdef CONFIG_PM_CPU_OPS + if (pm_cpu_on(cpu_num, (uintptr_t)&__start)) { + printk("Failed to boot secondary CPU %d\n", cpu_num); + return; + } +#endif + + while (riscv_cpu_boot_flag == 0U) { + riscv_cpu_wake_flag = _kernel.cpus[cpu_num].arch.hartid; } } -void z_riscv_secondary_cpu_init(int hartid) +void arch_secondary_cpu_init(int hartid) { unsigned int i; unsigned int cpu_num = 0; @@ -56,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 @@ -86,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); @@ -109,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. @@ -133,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 fdd39eb8a688746..b639f09c6c6899d 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 ef92fa69f91bbaa..55100606b9242fc 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 6858b2fb1fbc404..9ad3955a19026a2 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 66b5aafcf2639d9..dd4046c47bcdd46 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/sparc/core/window_trap.S b/arch/sparc/core/window_trap.S index ea810e1d6dde9b3..5a9edfd37c22b2a 100644 --- a/arch/sparc/core/window_trap.S +++ b/arch/sparc/core/window_trap.S @@ -83,60 +83,85 @@ SECTION_FUNC(TEXT, __sparc_trap_window_underflow) * "By executing a type 3 trap, a process asks the system to flush all its * register windows to the stack." * - * This implementation uses the window overflow trap handler to perform the - * actual window flush. - * * On entry: * %l0: psr * %l1: pc * %l2: npc */ SECTION_FUNC(TEXT, __sparc_trap_flush_windows) - /* push a few registers which are needed later to the stack */ - sub %sp, 0x10, %sp - std %l0, [%sp + 0x40 + 0x00] - st %l2, [%sp + 0x40 + 0x08] - st %g2, [%sp + 0x40 + 0x0c] - - restore - /* In window where we trapped from. This window will not be flushed. */ - - /* Set highest processor interrupt level and enable traps. */ - rd %psr, %g2 - or %g2, PSR_PIL, %g2 - wr %g2, PSR_ET, %psr - nop - nop + /* Save global registers used by the routine */ + mov %g3, %l3 + mov %g4, %l4 + mov %g5, %l5 + mov %g1, %l6 + mov %g2, %l7 - /* Execute "save" NWINDOWS-1 times. */ - set CONFIG_SPARC_NWIN-2, %g2 -1: - save - cmp %g2, %g0 - bne 1b - sub %g2, 1, %g2 + /* Uses g3=psr, g4=1, g2=wim, g1,g5=scratch */ + mov %l0, %g3 + set 1, %g4 + rd %wim, %g2 - /* Execute "restore" NWINDOWS-1 times. */ - set CONFIG_SPARC_NWIN-2, %g2 -2: - restore - cmp %g2, %g0 - bne 2b - sub %g2, 1, %g2 + /* + * We can always restore the previous window. Check if we can restore + * the window after that. + */ + and %l0, PSR_CWP, %g1 + add %g1, 2, %g1 + ba .LcheckNextWindow + restore - save + /* Flush window to stack */ +.LflushWindow: + std %l0, [%sp + 0x00] + std %l2, [%sp + 0x08] + std %l4, [%sp + 0x10] + std %l6, [%sp + 0x18] + std %i0, [%sp + 0x20] + std %i2, [%sp + 0x28] + std %i4, [%sp + 0x30] + std %i6, [%sp + 0x38] - /* pop registers from stack which are used for the trap return */ - ldd [%sp + 0x40 + 0x00], %l0 - ld [%sp + 0x40 + 0x08], %l2 - ld [%sp + 0x40 + 0x0c], %g2 - add %sp, 0x10, %sp + /* + * Check if next window is invalid by comparing + * (1 << ((cwp + 1) % NWIN)) with WIM + */ +.LcheckNextWindow: + set CONFIG_SPARC_NWIN, %g5 + cmp %g1, %g5 + bge,a .Lnowrap + sub %g1, %g5, %g1 +.Lnowrap: + sll %g4, %g1, %g5 + cmp %g5, %g2 + be .LflushWindowDone + inc %g1 - /* Restore %psr as it was on trap entry. */ - wr %l0, %psr - nop - nop - nop + /* We need to flush the next window */ + ba .LflushWindow + restore + /* + * All used windows have been flushed. Set WIM to cause trap for CWP+2. + * When we return from this trap it will be CWP+1 that will trap, that + * is, the next restore or rett. + */ +.LflushWindowDone: + /* We can not restore %psr from %l0 because we may be in any window. */ + wr %g3, %psr + and %g3, PSR_CWP, %g1 + add %g1, 2, %g1 + set CONFIG_SPARC_NWIN, %g5 + /* We are now back in the trap window. */ + cmp %g1, %g5 + bge,a .Lnowrap2 + sub %g1, %g5, %g1 +.Lnowrap2: + sll %g4, %g1, %g1 + wr %g1, %wim + mov %l3, %g3 + mov %l4, %g4 + mov %l5, %g5 + mov %l6, %g1 + mov %l7, %g2 jmp %l2 rett %l2 + 4 diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index d7ccfca7ecdc56c..ae7fdef2f77cdbb 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/acpi.c b/arch/x86/core/acpi.c deleted file mode 100644 index e304a54627ff198..000000000000000 --- a/arch/x86/core/acpi.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (c) 2020 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include - -static struct acpi_rsdp *rsdp; -static bool is_rsdp_searched; - -static struct acpi_dmar *dmar; -static bool is_dmar_searched; - -static bool check_sum(struct acpi_sdt *t) -{ - uint8_t sum = 0U, *p = (uint8_t *)t; - - for (int i = 0; i < t->length; i++) { - sum += p[i]; - } - - return sum == 0U; -} - -static void find_rsdp(void) -{ - uint8_t *bda_seg, *zero_page_base; - uint64_t *search; - uintptr_t search_phys, rsdp_phys; - size_t search_length = 0U, rsdp_length; - - if (is_rsdp_searched) { - /* Looking up for RSDP has already been done */ - return; - } - - /* Let's first get it from EFI, if enabled */ - if (IS_ENABLED(CONFIG_X86_EFI)) { - rsdp_phys = (uintptr_t)efi_get_acpi_rsdp(); - if (rsdp_phys != 0UL) { - /* See at found label why this is required */ - search_length = sizeof(struct acpi_rsdp); - z_phys_map((uint8_t **)&search, rsdp_phys, search_length, 0); - rsdp = (struct acpi_rsdp *)search; - - goto found; - } - } - - /* We never identity map the NULL page, so need to map it before - * it can be accessed. - */ - z_phys_map(&zero_page_base, 0, 4096, 0); - - /* Physical (real mode!) address 0000:040e stores a (real - * mode!!) segment descriptor pointing to the 1kb Extended - * BIOS Data Area. - * - * We had to memory map this segment descriptor since it is in - * the NULL page. The remaining structures (EBDA etc) are identity - * mapped somewhere within the minefield of reserved regions in the - * first megabyte and are directly accessible. - */ - bda_seg = 0x040e + zero_page_base; - search_phys = (long)(((int)*(uint16_t *)bda_seg) << 4); - - /* Unmap after use */ - z_phys_unmap(zero_page_base, 4096); - - /* Might be nothing there, check before we inspect. - * Note that EBDA usually is in 0x80000 to 0x100000. - */ - if ((POINTER_TO_UINT(search_phys) >= 0x80000UL) && - (POINTER_TO_UINT(search_phys) < 0x100000UL)) { - search_length = 1024; - z_phys_map((uint8_t **)&search, search_phys, search_length, 0); - - for (int i = 0; i < 1024/8; i++) { - if (search[i] == ACPI_RSDP_SIGNATURE) { - rsdp_phys = search_phys + i * 8; - rsdp = (void *)&search[i]; - goto found; - } - } - - z_phys_unmap((uint8_t *)search, search_length); - } - - /* If it's not there, then look for it in the last 128kb of - * real mode memory. - */ - search_phys = 0xe0000; - search_length = 128 * 1024; - z_phys_map((uint8_t **)&search, search_phys, search_length, 0); - - for (int i = 0; i < 128*1024/8; i++) { - if (search[i] == ACPI_RSDP_SIGNATURE) { - rsdp_phys = search_phys + i * 8; - rsdp = (void *)&search[i]; - goto found; - } - } - - z_phys_unmap((uint8_t *)search, search_length); - - rsdp = NULL; - - is_rsdp_searched = true; - - return; - -found: - /* Determine length of RSDP table. - * ACPI v2 and above uses the length field. - * Otherwise, just the size of struct itself. - */ - if (rsdp->revision < 2) { - rsdp_length = sizeof(*rsdp); - } else { - rsdp_length = rsdp->length; - } - - /* Need to unmap search since it is still mapped */ - if (search_length != 0U) { - z_phys_unmap((uint8_t *)search, search_length); - } - - /* Now map the RSDP */ - z_phys_map((uint8_t **)&rsdp, rsdp_phys, rsdp_length, 0); - - is_rsdp_searched = true; -} - -void *z_acpi_find_table(uint32_t signature) -{ - uint8_t *mapped_tbl; - uint32_t length; - struct acpi_rsdt *rsdt; - struct acpi_xsdt *xsdt; - struct acpi_sdt *t; - uintptr_t t_phys; - bool tbl_found; - - find_rsdp(); - - if (!rsdp) { - return NULL; - } - - if (rsdp->rsdt_ptr != 0U) { - z_phys_map((uint8_t **)&rsdt, rsdp->rsdt_ptr, sizeof(*rsdt), 0); - tbl_found = false; - - if (check_sum(&rsdt->sdt)) { - /* Remap the memory to the indicated length of RSDT */ - length = rsdt->sdt.length; - z_phys_unmap((uint8_t *)rsdt, sizeof(*rsdt)); - z_phys_map((uint8_t **)&rsdt, rsdp->rsdt_ptr, length, 0); - - uint32_t *end = (uint32_t *)((char *)rsdt + rsdt->sdt.length); - - /* Extra indirection required to avoid - * -Waddress-of-packed-member - */ - void *table_ptrs = &rsdt->table_ptrs[0]; - - for (uint32_t *tp = table_ptrs; tp < end; tp++) { - t_phys = (long)*tp; - z_phys_map(&mapped_tbl, t_phys, sizeof(*t), 0); - t = (void *)mapped_tbl; - - if (t->signature == signature && check_sum(t)) { - tbl_found = true; - break; - } - - z_phys_unmap(mapped_tbl, sizeof(*t)); - } - } - - z_phys_unmap((uint8_t *)rsdt, sizeof(*rsdt)); - - if (tbl_found) { - goto found; - } - } - - if (rsdp->revision < 2) { - return NULL; - } - - if (rsdp->xsdt_ptr != 0ULL) { - z_phys_map((uint8_t **)&xsdt, rsdp->xsdt_ptr, sizeof(*xsdt), 0); - - tbl_found = false; - if (check_sum(&xsdt->sdt)) { - /* Remap the memory to the indicated length of RSDT */ - length = xsdt->sdt.length; - z_phys_unmap((uint8_t *)xsdt, sizeof(*xsdt)); - z_phys_map((uint8_t **)&xsdt, rsdp->xsdt_ptr, length, 0); - - uint64_t *end = (uint64_t *)((char *)xsdt + xsdt->sdt.length); - - /* Extra indirection required to avoid - * -Waddress-of-packed-member - */ - void *table_ptrs = &xsdt->table_ptrs[0]; - - for (uint64_t *tp = table_ptrs; tp < end; tp++) { - t_phys = (long)*tp; - z_phys_map(&mapped_tbl, t_phys, sizeof(*t), 0); - t = (void *)mapped_tbl; - - if (t->signature == signature && check_sum(t)) { - tbl_found = true; - break; - } - - z_phys_unmap(mapped_tbl, sizeof(*t)); - } - } - - z_phys_unmap((uint8_t *)xsdt, sizeof(*xsdt)); - - if (tbl_found) { - goto found; - } - } - - return NULL; - -found: - /* Remap to indicated length of the table */ - length = t->length; - z_phys_unmap(mapped_tbl, sizeof(*t)); - z_phys_map(&mapped_tbl, t_phys, length, 0); - t = (void *)mapped_tbl; - - return t; -} - -/* - * Return the 'n'th CPU entry from the ACPI MADT, or NULL if not available. - */ - -struct acpi_cpu *z_acpi_get_cpu(int n) -{ - struct acpi_madt *madt = z_acpi_find_table(ACPI_MADT_SIGNATURE); - uintptr_t base = POINTER_TO_UINT(madt); - uintptr_t offset; - - if (!madt) { - return NULL; - } - - offset = POINTER_TO_UINT(madt->entries) - base; - - while (offset < madt->sdt.length) { - struct acpi_madt_entry *entry; - - entry = (struct acpi_madt_entry *)(offset + base); - if (entry->type == ACPI_MADT_ENTRY_CPU) { - struct acpi_cpu *cpu = (struct acpi_cpu *)entry; - - if ((cpu->flags & ACPI_CPU_FLAGS_ENABLED) != 0) { - if (n == 0) { - return cpu; - } - - --n; - } - } - - offset += entry->length; - } - - return NULL; -} - -static void find_dmar(void) -{ - if (is_dmar_searched) { - return; - } - - dmar = z_acpi_find_table(ACPI_DMAR_SIGNATURE); - is_dmar_searched = true; -} - -struct acpi_dmar *z_acpi_find_dmar(void) -{ - find_dmar(); - return dmar; -} - -struct acpi_drhd *z_acpi_find_drhds(int *n) -{ - struct acpi_drhd *drhds = NULL; - uintptr_t offset; - uintptr_t base; - - find_dmar(); - - if (dmar == NULL) { - return NULL; - } - - *n = 0; - base = POINTER_TO_UINT(dmar); - - offset = POINTER_TO_UINT(dmar->remap_entries) - base; - while (offset < dmar->sdt.length) { - struct acpi_dmar_entry *entry; - - entry = (struct acpi_dmar_entry *)(offset + base); - if (entry->type == ACPI_DMAR_TYPE_DRHD) { - if (*n == 0) { - drhds = (struct acpi_drhd *)entry; - } - - (*n)++; - } else { - /* DMAR entries are found packed by type so - * if type is not DRHD, we will not encounter one, - * anymore. - */ - break; - } - - offset += entry->length; - } - - return drhds; -} - -struct acpi_dmar_dev_scope *z_acpi_get_drhd_dev_scopes(struct acpi_drhd *drhd, - int *n) -{ - uintptr_t offset; - uintptr_t base; - - if (drhd->entry.length <= ACPI_DRHD_MIN_SIZE) { - return NULL; - } - - *n = 0; - base = POINTER_TO_UINT(drhd); - - offset = POINTER_TO_UINT(drhd->device_scope) - base; - while (offset < drhd->entry.length) { - struct acpi_dmar_dev_scope *dev_scope; - - dev_scope = (struct acpi_dmar_dev_scope *)(offset + base); - - (*n)++; - - offset += dev_scope->length; - } - - return (*n == 0) ? NULL : drhd->device_scope; -} - -struct acpi_dmar_dev_path * -z_acpi_get_dev_scope_paths(struct acpi_dmar_dev_scope *dev_scope, int *n) -{ - switch (dev_scope->type) { - case ACPI_DRHD_DEV_SCOPE_PCI_EPD: - /* Fall through */ - case ACPI_DRHD_DEV_SCOPE_PCI_SUB_H: - /* Fall through */ - case ACPI_DRHD_DEV_SCOPE_IOAPIC: - if (dev_scope->length < (ACPI_DMAR_DEV_SCOPE_MIN_SIZE + - ACPI_DMAR_DEV_PATH_SIZE)) { - return NULL; - } - - break; - case ACPI_DRHD_DEV_SCOPE_MSI_CAP_HPET: - /* Fall through */ - case ACPI_DRHD_DEV_SCOPE_NAMESPACE_DEV: - if (dev_scope->length != (ACPI_DMAR_DEV_SCOPE_MIN_SIZE + - ACPI_DMAR_DEV_PATH_SIZE)) { - return NULL; - } - - break; - default: - return NULL; - } - - *n = (dev_scope->length - ACPI_DMAR_DEV_SCOPE_MIN_SIZE) / - ACPI_DMAR_DEV_PATH_SIZE; - - return dev_scope->path; -} - -uint16_t z_acpi_get_dev_id_from_dmar(uint8_t dev_scope_type) -{ - struct acpi_drhd *drhd; - int n_drhd; - - find_dmar(); - - if (dmar == NULL) { - return USHRT_MAX; - } - - drhd = z_acpi_find_drhds(&n_drhd); - - for (; n_drhd > 0; n_drhd--) { - struct acpi_dmar_dev_scope *dev_scope; - int n_ds; - - dev_scope = z_acpi_get_drhd_dev_scopes(drhd, &n_ds); - for (; n_ds > 0; n_ds--) { - if (dev_scope->type == dev_scope_type) { - struct acpi_dmar_dev_path *path; - int n_path; - - path = z_acpi_get_dev_scope_paths(dev_scope, - &n_path); - if (n_path > 0) { - union acpi_dmar_id id; - - /* Let's over simplify for now: - * we don't look for secondary bus - * and extra paths. We just stop here. - */ - - id.bits.bus = dev_scope->start_bus_num; - id.bits.device = path->device; - id.bits.function = path->function; - - return id.raw; - } - } - - dev_scope = (struct acpi_dmar_dev_scope *)( - POINTER_TO_UINT(dev_scope) + dev_scope->length); - } - - drhd = (struct acpi_drhd *)(POINTER_TO_UINT(drhd) + - drhd->entry.length); - } - - return USHRT_MAX; -} diff --git a/arch/x86/core/cache.c b/arch/x86/core/cache.c index cd0bbb8e16d4fae..e80cb6d1dbf44e1 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 856ae7b2e0e86fc..1f390df42fbbfbf 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 572b71cf5a03b29..3a0bc7465e1ff1d 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/efi.c b/arch/x86/core/efi.c index 00bcff8d47c4bef..425b0dcde86f2fb 100644 --- a/arch/x86/core/efi.c +++ b/arch/x86/core/efi.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include "../zefi/efi.h" /* ZEFI not on include path */ #include #include diff --git a/arch/x86/core/ia32/crt0.S b/arch/x86/core/ia32/crt0.S index d42a99d5f5683cd..32513a957903769 100644 --- a/arch/x86/core/ia32/crt0.S +++ b/arch/x86/core/ia32/crt0.S @@ -21,14 +21,14 @@ #include #include #include -#include +#include /* exports (private APIs) */ 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/fatal.c b/arch/x86/core/ia32/fatal.c index 9c9ab5f3a63b6ab..38cf180e0bcd025 100644 --- a/arch/x86/core/ia32/fatal.c +++ b/arch/x86/core/ia32/fatal.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); diff --git a/arch/x86/core/ia32/gdbstub.c b/arch/x86/core/ia32/gdbstub.c index afda9b5a7e27656..692ea78baf41cb6 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/ia32/userspace.S b/arch/x86/core/ia32/userspace.S index adba32c78b2d25b..bf21a0cc1a22746 100644 --- a/arch/x86/core/ia32/userspace.S +++ b/arch/x86/core/ia32/userspace.S @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include /* Exports */ diff --git a/arch/x86/core/intel64.cmake b/arch/x86/core/intel64.cmake index cd37d5c497e4515..1cb25ebe220e580 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 6afcec2a0170d02..2a845960b87b912 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 @@ -141,17 +141,18 @@ struct x86_cpuboot x86_cpuboot[] = { void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, arch_cpustart_t fn, void *arg) { +#if CONFIG_MP_MAX_NUM_CPUS > 1 uint8_t vector = ((unsigned long) x86_ap_start) >> 12; uint8_t apic_id; -#ifdef CONFIG_ACPI - struct acpi_madt_local_apic *lapic = acpi_local_apic_get(cpu_num); + IF_ENABLED(CONFIG_ACPI, ({ + ACPI_MADT_LOCAL_APIC *lapic = acpi_local_apic_get(cpu_num); - if (lapic != NULL) { - /* We update the apic_id, __start will need it. */ - x86_cpu_loapics[cpu_num] = lapic->Id; - } -#endif + if (lapic != NULL) { + /* We update the apic_id, __start will need it. */ + x86_cpu_loapics[cpu_num] = lapic->Id; + } + })); apic_id = x86_cpu_loapics[cpu_num]; @@ -166,9 +167,16 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, while (x86_cpuboot[cpu_num].ready == 0) { } +#else + ARG_UNUSED(cpu_num); + ARG_UNUSED(stack); + ARG_UNUSED(sz); + ARG_UNUSED(fn); + ARG_UNUSED(arg); +#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) @@ -200,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 a730427174629c5..f8e251b804613c6 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 000000000000000..0146321f7d9d99a --- /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/locore.S b/arch/x86/core/intel64/locore.S index f69545cc64ac7e7..dd541921742a78e 100644 --- a/arch/x86/core/intel64/locore.S +++ b/arch/x86/core/intel64/locore.S @@ -13,7 +13,7 @@ #include #include #include -#include +#include /* * Definitions/macros for enabling paging diff --git a/arch/x86/core/intel64/smp.c b/arch/x86/core/intel64/smp.c new file mode 100644 index 000000000000000..a73ba9c8f38c363 --- /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/intel64/userspace.S b/arch/x86/core/intel64/userspace.S index 747c6183c3ccbce..ab09381c7af9cc7 100644 --- a/arch/x86/core/intel64/userspace.S +++ b/arch/x86/core/intel64/userspace.S @@ -8,7 +8,7 @@ #include #include #include -#include +#include #ifdef CONFIG_X86_KPTI /* Copy interrupt return stack context to the trampoline stack, switch back diff --git a/arch/x86/core/pcie.c b/arch/x86/core/pcie.c index 5c1e83725bbda91..878e6886d7b8f73 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 ee095efe33d15d5..17a4a7f74734337 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 d0876749575098a..9380c14d005b839 100644 --- a/arch/x86/core/userspace.c +++ b/arch/x86/core/userspace.c @@ -6,11 +6,15 @@ #include #include -#include +#include #include #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_mmu.c b/arch/x86/core/x86_mmu.c index 119179b72ae8efa..71aafe5cad9b978 100644 --- a/arch/x86/core/x86_mmu.c +++ b/arch/x86/core/x86_mmu.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/x86/include/kernel_arch_func.h b/arch/x86/include/kernel_arch_func.h index 7c080b8e25bcd61..00b411978ec65cd 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/x86/include/x86_mmu.h b/arch/x86/include/x86_mmu.h index 14c5b053c6513c1..b5b319a64e41a90 100644 --- a/arch/x86/include/x86_mmu.h +++ b/arch/x86/include/x86_mmu.h @@ -14,7 +14,7 @@ #include #include -#include +#include #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) #define XD_SUPPORTED diff --git a/arch/xtensa/CMakeLists.txt b/arch/xtensa/CMakeLists.txt index 133d74331d8e667..21de223d4ec2015 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 6095a7046d7c720..aa888e8331a945a 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" @@ -50,18 +36,6 @@ config XTENSA_ENABLE_BACKTRACE help Enable this config option to print backtrace on panic exception -config XTENSA_CPU_IDLE_SPIN - bool "Use busy loop for k_cpu_idle" - help - Use a spin loop instead of WAITI for the CPU idle state. - -config XTENSA_WAITI_BUG - bool "Workaround sequence for WAITI bug on LX6" - help - SOF traditionally contains this workaround on its ADSP - platforms which prefixes a WAITI entry with 128 NOP - instructions followed by an ISYNC and EXTW. - config XTENSA_SMALL_VECTOR_TABLE_ENTRY bool "Workaround for small vector table entries" help @@ -123,53 +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 3bf29e88b6499fe..f1f82dc3834e19d 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,14 +22,21 @@ 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 + mem_manage.c +) 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 @@ -52,6 +60,7 @@ 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> ${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 000000000000000..499a251cdf2f2f4 --- /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 26060dea8c34204..a2eec6207743c27 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/cpu_idle.c b/arch/xtensa/core/cpu_idle.c index fa9384d8445a8e8..dae79f023ff7a37 100644 --- a/arch/xtensa/core/cpu_idle.c +++ b/arch/xtensa/core/cpu_idle.c @@ -6,48 +6,13 @@ #include #include -/* xt-clang removes any NOPs more than 8. So we need to set - * no optimization to avoid those NOPs from being removed. - * - * This function is simply enough and full of hand written - * assembly that optimization is not really meaningful - * anyway. So we can skip optimization unconditionally. - * Re-evalulate its use and add #ifdef if this assumption - * is no longer valid. - */ -__no_optimization +#ifndef CONFIG_ARCH_CPU_IDLE_CUSTOM void arch_cpu_idle(void) { sys_trace_idle(); - - /* Just spin forever with interrupts unmasked, for platforms - * where WAITI can't be used or where its behavior is - * complicated (Intel DSPs will power gate on idle entry under - * some circumstances) - */ - if (IS_ENABLED(CONFIG_XTENSA_CPU_IDLE_SPIN)) { - __asm__ volatile("rsil a0, 0"); - __asm__ volatile("loop_forever: j loop_forever"); - return; - } - - /* Cribbed from SOF: workaround for a bug in some versions of - * the LX6 IP. Preprocessor ugliness avoids the need to - * figure out how to get the compiler to unroll a loop. - */ - if (IS_ENABLED(CONFIG_XTENSA_WAITI_BUG)) { -#define NOP4 __asm__ volatile("nop; nop; nop; nop"); -#define NOP32 NOP4 NOP4 NOP4 NOP4 NOP4 NOP4 NOP4 NOP4 -#define NOP128() NOP32 NOP32 NOP32 NOP32 - NOP128(); -#undef NOP128 -#undef NOP32 -#undef NOP4 - __asm__ volatile("isync; extw"); - } - __asm__ volatile ("waiti 0"); } +#endif void arch_cpu_atomic_idle(unsigned int key) { diff --git a/arch/xtensa/core/crt1.S b/arch/xtensa/core/crt1.S index 1f9cc148ab5a9f7..c616b0889d7198e 100644 --- a/arch/xtensa/core/crt1.S +++ b/arch/xtensa/core/crt1.S @@ -23,11 +23,6 @@ .global __start .type z_cstart, @function -.type z_mp_entry, @function - -#ifdef CONFIG_XTENSA_MMU -.type z_xtensa_mmu_init, @function -#endif /* Macros to abstract away ABI differences */ @@ -193,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 8d895ba39ddd52f..3dacc1a4587f512 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 000000000000000..976be9f794a115f --- /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 e693937f99bfd52..faf6c38a33f26a6 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,33 @@ FUNC_NORETURN void z_system_halt(unsigned int reason) CODE_UNREACHABLE; } #endif + +FUNC_NORETURN void arch_syscall_oops(void *ssf) +{ + ARG_UNUSED(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 034b3532866b4de..4df72f0d355c760 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 8d052f4891d70fa..0e3069a4c450d41 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,26 @@ # -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("--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", "FLUSH"] +if args.mmu: + NEEDED += ["MMU_0", "MMU_1", "DBLEXC"] + +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 7519c1b6010649f..000000000000000 --- 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 1c592734084d80d..576eb6e62bb1ad4 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 new file mode 100644 index 000000000000000..e43bf4b75d6dfba --- /dev/null +++ b/arch/xtensa/core/mem_manage.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#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); + + valid = ((phys >= CONFIG_SRAM_BASE_ADDRESS) && + (phys < (CONFIG_SRAM_BASE_ADDRESS + (CONFIG_SRAM_SIZE * 1024UL)))); + + valid |= ((cached >= CONFIG_SRAM_BASE_ADDRESS) && + (cached < (CONFIG_SRAM_BASE_ADDRESS + (CONFIG_SRAM_SIZE * 1024UL)))); + + return valid; +} + +__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); + + valid = ((addr >= CONFIG_KERNEL_VM_BASE) && + (addr < (CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_SIZE))); + + valid |= ((cached >= CONFIG_KERNEL_VM_BASE) && + (cached < (CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_SIZE))); + + return valid; +} diff --git a/arch/xtensa/core/mmu.c b/arch/xtensa/core/mmu.c new file mode 100644 index 000000000000000..294a66dbc224552 --- /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 860a12eb408909b..8fca6962d3d3d82 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 000000000000000..ec8295f6144e73f --- /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 (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 | XTENSA_MMU_CACHED_WB, shared); + } 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, 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 (arch_xtensa_is_ptr_cached(va)) { + vaddr = va; + vaddr_uc = arch_xtensa_uncached_ptr(va); + } else { + vaddr = arch_xtensa_cached_ptr(va); + vaddr_uc = va; + } + + if (arch_xtensa_is_ptr_cached((void *)pa)) { + paddr = pa; + paddr_uc = (uintptr_t)arch_xtensa_uncached_ptr((void *)pa); + } else { + paddr = (uintptr_t)arch_xtensa_cached_ptr((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 (arch_xtensa_is_ptr_cached(va)) { + vaddr = va; + vaddr_uc = arch_xtensa_uncached_ptr(va); + } else { + vaddr = arch_xtensa_cached_ptr(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 (arch_xtensa_is_ptr_cached((void *)start)) { + va = start; + va_uc = (uintptr_t)arch_xtensa_uncached_ptr((void *)start); + } else { + va = (uintptr_t)arch_xtensa_cached_ptr((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 000000000000000..ffd08ab805c29e3 --- /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 de30172ced2a92b..fc17c5cd990ac3c 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 000000000000000..f8fb7ec903ec3e1 --- /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 000000000000000..4ba0150f7054928 --- /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 000000000000000..f385d7223ea8dc5 --- /dev/null +++ b/arch/xtensa/core/userspace.S @@ -0,0 +1,327 @@ +/* + * 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 + + addi a1, a1, 28 + + /* 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 000000000000000..3334af67b7bb510 --- /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); +} + +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); + } + +#ifdef CONFIG_USERSPACE + LOG_ERR(" ** THREADPTR %p", (void *)bsa->threadptr); +#endif /* CONFIG_USERSPACE */ + + 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 a63923cbd6fc2dd..90eba495bde809b 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 d7ba88aaffc397c..000000000000000 --- 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 c2371ac8f55d6a3..000000000000000 --- 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 000000000000000..5dabb39ea3a21f4 --- /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 e0abe09049b9abe..5871a10c48f5667 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 c84d01b8337abbb..000000000000000 --- 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 6427b306e623190..f303a8a0c3ae330 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 34a4a5842cf753a..f19750dc0ac8b96 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 f691dbc6cad9b14..000000000000000 --- 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 25fbb2980ab2e6b..000000000000000 --- 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 000000000000000..c075d42c3f09435 --- /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 2963836a4c648a6..069bdcb41ca594a 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 000000000000000..b97c109a994dae2 --- /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 000000000000000..631760f03cb1891 --- /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/Kconfig b/boards/Kconfig index fbab1e97d984e6b..f56c2cab04ef9ac 100644 --- a/boards/Kconfig +++ b/boards/Kconfig @@ -111,6 +111,15 @@ config QEMU_GDBSERVER_LISTEN_DEV as the `QEMU_EXTRA_FLAGS` environment variable. Refer to application development doc and/or QEMU invocation doc for more info. +config QEMU_EXTRA_FLAGS + string "QEMU extra flags" + depends on QEMU_TARGET + default "" + help + This option is to pass onto QEMU an extra list of parameters + to setup devices, for example to allocate interface for Zephyr + GDBstub over serial with `-serial tcp:127.0.0.1:5678,server` + # There might not be any board options, hence the optional source osource "$(BOARD_DIR)/Kconfig" endmenu diff --git a/boards/arc/emsdp/emsdp.yaml b/boards/arc/emsdp/emsdp.yaml index b6fa38fb5153d64..c5a9afc8da410c2 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 a146eb72bff46cb..9be5bbca31b830e 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 d0117790975a736..80cbc08e0661529 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 2584fb8a953ee50..ce15754d7be645e 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 57f78c3c7e766e4..e3591d300f54401 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 e3387d647988be1..2b8cc296bb893a5 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 7bdf0340232be42..f20f29d18d01126 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/doc/index.rst b/boards/arc/nsim/doc/index.rst index 64f6f4666f43a36..4e7054fc43b0a4f 100644 --- a/boards/arc/nsim/doc/index.rst +++ b/boards/arc/nsim/doc/index.rst @@ -34,7 +34,7 @@ available configurations are listed below: * ``nsim_hs5x`` - 32-bit ARCv3 HS core with rich set of options * ``nsim_hs6x`` - 64-bit ARCv3 HS core with rich set of options * ``nsim_hs5x_smp_12cores`` - SMP 12 cores 32-bit ARCv3 HS platform -* ``nsim_hs5x_smp_12cores`` - SMP 12 cores 64-bit ARCv3 HS platform +* ``nsim_hs6x_smp_12cores`` - SMP 12 cores 64-bit ARCv3 HS platform .. _board_arc_nsim_prop_args_files: diff --git a/boards/arc/nsim/haps_arcv3_init.c b/boards/arc/nsim/haps_arcv3_init.c index 78dfc37f6c7dbe9..c29392643f8c955 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 49b4b4be58dec93..494ff760838e637 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 036e9b37baef299..bd2069c83590192 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 6f44addd50b7edb..0a6d7ad5e4cca39 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 f55dce205176a3a..263c5b27af53565 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 92ca6763a598e3e..eddd5076c65d235 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 f87e1dfdcba0725..03c5f678869097c 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 416dcd2133db0b8..f7f9fa1ec7201e1 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 0f327874e5be902..c27e5d81edeac7b 100644 --- a/boards/arc/nsim/nsim_hs5x_smp_12cores_defconfig +++ b/boards/arc/nsim/nsim_hs5x_smp_12cores_defconfig @@ -12,6 +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 f4b6288b106c218..ac6baba1858c701 100644 --- a/boards/arc/nsim/nsim_hs5x_smp_defconfig +++ b/boards/arc/nsim/nsim_hs5x_smp_defconfig @@ -12,6 +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 4db6e16b61e459a..dfb41bf22156256 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 3113b84e8d69938..9abea29aabc83e5 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 453f4782d72a5b7..2e14a87ed40d0f5 100644 --- a/boards/arc/nsim/nsim_hs6x_smp_12cores_defconfig +++ b/boards/arc/nsim/nsim_hs6x_smp_12cores_defconfig @@ -12,6 +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 6cb2b160e1d379e..c34a380d1d03452 100644 --- a/boards/arc/nsim/nsim_hs6x_smp_defconfig +++ b/boards/arc/nsim/nsim_hs6x_smp_defconfig @@ -12,6 +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 92ca6763a598e3e..eddd5076c65d235 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 02da85f586408c3..eabe0c9cd846aa4 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 bc6104c8a12694f..e4124a3ed69e22c 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 33b9af526d661b9..4f57122f208a1ae 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 24b1914760b0a4f..1b0d663da8db0bd 100644 --- a/boards/arc/nsim/nsim_hs_smp_defconfig +++ b/boards/arc/nsim/nsim_hs_smp_defconfig @@ -11,6 +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 7a99a91ceff4169..cfbf02d60238841 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 9b60f760e62d479..8c4032b20547393 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 2ec15d063f545a7..c6be9e45d58dc8b 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 45949212a00220a..13a48179fd5efb1 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 56e4a729daf427a..4f846b18d61a7ad 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 4107bf940ee4111..83fdaa12a7df72d 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 5346dbc12510d32..ed5425cc5654f90 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 829045078d26645..4f7b9cee45d3c78 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 4a4e8672f7ff1ae..dd5f8d8a89592f8 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/96b_aerocore2/doc/index.rst b/boards/arm/96b_aerocore2/doc/index.rst index 79bac17ad279bd2..6d56911c2f1acf0 100644 --- a/boards/arm/96b_aerocore2/doc/index.rst +++ b/boards/arm/96b_aerocore2/doc/index.rst @@ -330,7 +330,7 @@ Replace :code:`` with the port where the board 96Boards Aerocore2 can be found. For example, under Linux, :code:`/dev/ttyUSB0`. The ``-b`` option sets baud rate ignoring the value from config. -Press the Reset button and you should see the the following message in your +Press the Reset button and you should see the following message in your terminal: .. code-block:: console diff --git a/boards/arm/96b_carbon/doc/index.rst b/boards/arm/96b_carbon/doc/index.rst index b4a37cc985d4438..7b63bb20de95410 100644 --- a/boards/arm/96b_carbon/doc/index.rst +++ b/boards/arm/96b_carbon/doc/index.rst @@ -318,7 +318,7 @@ Replace :code:`` with the port where the board 96Boards Carbon can be found. For example, under Linux, :code:`/dev/ttyUSB0`. The ``-b`` option sets baud rate ignoring the value from config. -Press the Reset button and you should see the the following message in your +Press the Reset button and you should see the following message in your terminal: .. code-block:: console diff --git a/boards/arm/96b_nitrogen/doc/index.rst b/boards/arm/96b_nitrogen/doc/index.rst index 86e08e96ccff855..ea971f093a89521 100644 --- a/boards/arm/96b_nitrogen/doc/index.rst +++ b/boards/arm/96b_nitrogen/doc/index.rst @@ -292,7 +292,7 @@ Replace :code:`` with the port where the board 96Boards Nitrogen can be found. For example, under Linux, :code:`/dev/ttyACM0`. The ``-b`` option sets baud rate ignoring the value from config. -Press the Reset button and you should see the the following message in your +Press the Reset button and you should see the following message in your terminal: .. code-block:: console diff --git a/boards/arm/adafruit_feather_nrf52840/adafruit_feather_nrf52840.dts b/boards/arm/adafruit_feather_nrf52840/adafruit_feather_nrf52840.dts index 284a4d245424347..2333e5becbeda1b 100644 --- a/boards/arm/adafruit_feather_nrf52840/adafruit_feather_nrf52840.dts +++ b/boards/arm/adafruit_feather_nrf52840/adafruit_feather_nrf52840.dts @@ -47,6 +47,13 @@ }; }; + vbatt { + compatible = "voltage-divider"; + io-channels = <&adc 5>; + output-ohms = <100000>; + full-ohms = <(100000 + 100000)>; + }; + /* These aliases are provided for compatibility with samples */ aliases { led0 = &led0; diff --git a/boards/arm/adafruit_feather_nrf52840/doc/index.rst b/boards/arm/adafruit_feather_nrf52840/doc/index.rst index a36bbdd7e3a6f89..6d4af8ca296b187 100644 --- a/boards/arm/adafruit_feather_nrf52840/doc/index.rst +++ b/boards/arm/adafruit_feather_nrf52840/doc/index.rst @@ -129,7 +129,7 @@ Flash the image. :goals: flash :compact: -You should see the the red LED blink. +You should see the red LED blink. References ********** 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 000000000000000..4ca7a7126972b4d --- /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 000000000000000..72266e97bac6978 --- /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 000000000000000..6dcd448bebd5324 --- /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 000000000000000..5cc038332b1fff1 --- /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 000000000000000..0afd44c0af8302a --- /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 000000000000000..b5bfafe5b18c54d --- /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 000000000000000..c5e25934fa5991c --- /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 000000000000000..33e0a97394acd07 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 000000000000000..a5dba70f6173778 --- /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 000000000000000..f3f767cf79df048 --- /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_itsybitsy_m4_express/doc/index.rst b/boards/arm/adafruit_itsybitsy_m4_express/doc/index.rst index aca89603ff56a23..401e28d6669529c 100644 --- a/boards/arm/adafruit_itsybitsy_m4_express/doc/index.rst +++ b/boards/arm/adafruit_itsybitsy_m4_express/doc/index.rst @@ -179,7 +179,8 @@ debugged using a SWD probe such as the Segger J-Link. .. zephyr-app-commands:: :zephyr-app: samples/hello_world :board: adafruit_itsybitsy_m4_express - :goals: flash -r openocd + :goals: flash + :flash-args: -r openocd :compact: #. Start debugging: diff --git a/boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi b/boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi index 5ae00a45cdebebf..cf1289acedc34c7 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 2d9c815f5781956..c17700aa8fa1141 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 51dd75d58d930ef..40511a776330876 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 735148fbce238da..6ce0691032d226f 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 98c2bacf9e31358..09d5bfb096011e2 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 000000000000000..f2c8db2c34163bc --- /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 000000000000000..705a49ac152364a --- /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 000000000000000..d2e84ae41f8637e --- /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 000000000000000..7e8448aec0ac2cb --- /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 000000000000000..2348e9cec55c285 --- /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 000000000000000..d0987d6025f5185 --- /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 000000000000000..affc290a869d67e --- /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 000000000000000..c1a7ab1dc28c42c 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 000000000000000..19b5a832223a583 --- /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 000000000000000..69e21b54c12ee24 --- /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_sdp_k1/Kconfig.board b/boards/arm/adi_sdp_k1/Kconfig.board new file mode 100644 index 000000000000000..8aa4b969d613cde --- /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 000000000000000..03e3bd4cdeb3cba --- /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 000000000000000..91aea8c60dfdcd3 --- /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 000000000000000..800bedab7de41fb --- /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 000000000000000..94a8f52809e7ec3 --- /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 000000000000000..53c9a87117382b0 --- /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 000000000000000..8a8885e9a95f838 --- /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 000000000000000..ea8add4d7d765c2 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 000000000000000..a3729bcf6f4089a 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 000000000000000..5712fb6f595fc52 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 000000000000000..177f7bf3550219c --- /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 000000000000000..b82df11ae6a9dda --- /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 000000000000000..d1426b667d5a664 --- /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/am62x_m4/am62x_m4_phyboard_lyra.dts b/boards/arm/am62x_m4/am62x_m4_phyboard_lyra.dts index 3fac130ee9068dc..ba370240340c272 100644 --- a/boards/arm/am62x_m4/am62x_m4_phyboard_lyra.dts +++ b/boards/arm/am62x_m4/am62x_m4_phyboard_lyra.dts @@ -20,6 +20,10 @@ zephyr,sram1 = &ddr0; }; + aliases { + led0 = &heartbeat_led; + }; + cpus { cpu@0 { status = "okay"; @@ -32,6 +36,14 @@ reg = <0x9CC00000 DT_SIZE_K(4)>; zephyr,memory-region = "DDR"; }; + + leds: leds { + compatible = "gpio-leds"; + heartbeat_led: led_0 { + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + label = "Heartbeat LED"; + }; + }; }; &pinctrl { @@ -41,6 +53,9 @@ mcu_uart0_tx_default: mcu_uart0_tx_default { pinmux = ; }; + mcu_gpio0_led_default: mcu_gpio0_led_default { + pinmux = ; + }; }; &uart0 { @@ -49,3 +64,9 @@ pinctrl-names = "default"; status = "okay"; }; + +&gpio0 { + pinctrl-0 = <&mcu_gpio0_led_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/arm/am62x_m4/am62x_m4_phyboard_lyra_defconfig b/boards/arm/am62x_m4/am62x_m4_phyboard_lyra_defconfig index 15d2b0f5b28d77a..822222a8900fedb 100644 --- a/boards/arm/am62x_m4/am62x_m4_phyboard_lyra_defconfig +++ b/boards/arm/am62x_m4/am62x_m4_phyboard_lyra_defconfig @@ -20,6 +20,9 @@ CONFIG_PINCTRL=y # Serial Driver CONFIG_SERIAL=y +# GPIO Driver +CONFIG_GPIO=y + # Enable Console CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y diff --git a/boards/arm/apollo4p_blue_kxr_evb/Kconfig.defconfig b/boards/arm/apollo4p_blue_kxr_evb/Kconfig.defconfig index f14c801d3b31244..1edc7b5581bb34c 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-pinctrl.dtsi b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb-pinctrl.dtsi index 4d8f6cb0525e5a0..0622157b2d033c4 100644 --- a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb-pinctrl.dtsi +++ b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb-pinctrl.dtsi @@ -192,4 +192,17 @@ ambiq,iom-nce-module = <36>; }; }; + + xo32m_default: xo32m_default { + group1 { + pinmux = ; + drive-strength = "0.1"; + }; + }; + xo32k_default: xo32k_default { + group1 { + pinmux = ; + drive-strength = "0.1"; + }; + }; }; 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 1eca9ae225e43df..f9aa3c11c31c112 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; @@ -13,11 +14,45 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; 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 { @@ -47,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"; }; @@ -56,3 +97,48 @@ pinctrl-names = "default"; status = "okay"; }; + +&flash0 { + erase-block-size = <2048>; + write-block-size = <16>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 16KB of storage at the end of the 1952KB of flash */ + storage_partition: partition@1e4000 { + label = "storage"; + reg = <0x001e4000 0x4000>; + }; + }; +}; + +&xo32m { + pinctrl-0 = <&xo32m_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&xo32k { + pinctrl-0 = <&xo32k_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_blue_kxr_evb/apollo4p_blue_kxr_evb.yaml b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.yaml index bbdf0477a36f1ef..d9e9f244d861aa4 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 35592c0b911d435..75aa74ac34e58f7 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 abc9f9c9c548164..b7b285d6ad81ab5 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 059b880388d4bd4..8b87f96ac68f19b 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 b2c0ecd954b3ef0..1aa0fbf75d4b24b 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 000000000000000..e083db991e24db0 --- /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 21b967893e1dffa..42f0f3603296131 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/Kconfig.defconfig b/boards/arm/arduino_giga_r1/Kconfig.defconfig index 5880f88f7e0447e..e72fb499055f5ac 100644 --- a/boards/arm/arduino_giga_r1/Kconfig.defconfig +++ b/boards/arm/arduino_giga_r1/Kconfig.defconfig @@ -9,7 +9,7 @@ config BOARD if BT -choice CYW43XXX_PART +choice AIROC_PART default CYW4343W endchoice 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 ef3544ef9587561..9cc042ff0d3e38e 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>; }; diff --git a/boards/arm/arduino_giga_r1/board.cmake b/boards/arm/arduino_giga_r1/board.cmake index 74efbc124115605..849f9f933f1fa6f 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 000000000000000..ddceef92cb19195 --- /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 000000000000000..75d441d1809269c --- /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 200db7f94c7a11e..3d31ede313fea1f 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_nano_33_ble/doc/index.rst b/boards/arm/arduino_nano_33_ble/doc/index.rst index ede09b859799023..05c0605b4645068 100644 --- a/boards/arm/arduino_nano_33_ble/doc/index.rst +++ b/boards/arm/arduino_nano_33_ble/doc/index.rst @@ -126,7 +126,7 @@ and there should be a pulsing orange LED near the USB port. Then, you can flash the image using the above script. -You should see the the red LED blink. +You should see the red LED blink. Debugging ========= diff --git a/boards/arm/arduino_nano_33_iot/doc/index.rst b/boards/arm/arduino_nano_33_iot/doc/index.rst index dfcf2a6bbcb5c61..62353ecbe1eb9aa 100644 --- a/boards/arm/arduino_nano_33_iot/doc/index.rst +++ b/boards/arm/arduino_nano_33_iot/doc/index.rst @@ -6,7 +6,7 @@ Arduino Nano 33 IOT Overview ******** -The Arduino Nano 33 IOT is a a small form factor development board with USB, +The Arduino Nano 33 IOT is a small form factor development board with USB, Wifi, Bluetooth, a 6 axis IMU, and secure element. .. image:: img/nano_33_iot.jpg diff --git a/boards/arm/arduino_opta_m4/Kconfig.board b/boards/arm/arduino_opta_m4/Kconfig.board new file mode 100644 index 000000000000000..cce1cd6337add60 --- /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 000000000000000..be17c009555e0ec --- /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 000000000000000..bc74a2691f428e0 --- /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 000000000000000..4030cb402f66712 --- /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 000000000000000..bcf01ccabfbe7c5 --- /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 000000000000000..029ae806f4d2baa --- /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 000000000000000..4b3a8e54d574740 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 000000000000000..90f9497db33a446 --- /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 653812e3e6ada9b..87d85f2726352dc 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/Kconfig.board b/boards/arm/arduino_uno_r4/Kconfig.board new file mode 100644 index 000000000000000..d56eff75387fa91 --- /dev/null +++ b/boards/arm/arduino_uno_r4/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ARDUINO_UNO_R4_MINIMA + bool "Arduino Uno R4 Minima board" + depends on SOC_R7FA4M1AB3CFM diff --git a/boards/arm/arduino_uno_r4/Kconfig.defconfig b/boards/arm/arduino_uno_r4/Kconfig.defconfig new file mode 100644 index 000000000000000..2d483f3bb384ba6 --- /dev/null +++ b/boards/arm/arduino_uno_r4/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_ARDUINO_UNO_R4_MINIMA + +config BOARD + default "arduino_uno_r4_minima" if BOARD_ARDUINO_UNO_R4_MINIMA + +endif # BOARD_ARDUINO_UNO_R4_MINIMA diff --git a/boards/arm/arduino_uno_r4/arduino_uno_r4_common.dtsi b/boards/arm/arduino_uno_r4/arduino_uno_r4_common.dtsi new file mode 100644 index 000000000000000..472e1092f5f8153 --- /dev/null +++ b/boards/arm/arduino_uno_r4/arduino_uno_r4_common.dtsi @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include + +/ { + model = "Arduino Uno R4 Board"; + compatible = "renesas,r7fa4m1aB3cfm"; +}; diff --git a/boards/arm/arduino_uno_r4/arduino_uno_r4_minima-pinctrl.dtsi b/boards/arm/arduino_uno_r4/arduino_uno_r4_minima-pinctrl.dtsi new file mode 100644 index 000000000000000..c9538829a480b37 --- /dev/null +++ b/boards/arm/arduino_uno_r4/arduino_uno_r4_minima-pinctrl.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + sci2_default: sci2_default { + group1 { + pinmux = , ; + }; + }; +}; diff --git a/boards/arm/arduino_uno_r4/arduino_uno_r4_minima.dts b/boards/arm/arduino_uno_r4/arduino_uno_r4_minima.dts new file mode 100644 index 000000000000000..18b1aea120c0b7d --- /dev/null +++ b/boards/arm/arduino_uno_r4/arduino_uno_r4_minima.dts @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +#include "arduino_uno_r4_common.dtsi" +#include "arduino_uno_r4_minima-pinctrl.dtsi" + +/ { + model = "Arduino Uno R4 Minima"; + + chosen { + zephyr,console = &uart2; + zephyr,shell-uart = &uart2; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &code_partition; + }; + + leds { + compatible = "gpio-leds"; + led: led { + gpios = <&ioport1 11 GPIO_ACTIVE_HIGH>; + }; + }; + + aliases { + led0 = &led; + }; +}; + +&sci2 { + status = "okay"; + pinctrl-0 = <&sci2_default>; + pinctrl-names = "default"; + uart2: uart { + current-speed = <115200>; + status = "okay"; + }; +}; + +&ioport1 { + status = "okay"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "bootloader"; + reg = <0x00000000 0x4000>; + read-only; + }; + + code_partition: partition@4000 { + label = "code"; + reg = <0x4000 0x3C000>; + read-only; + }; + }; +}; + +&fcu { + status = "okay"; +}; + +&hoco { + status = "okay"; + clock-frequency = <48000000>; +}; + +&cgc { + clock-source = <&hoco>; + iclk-div = <1>; + pclka-div = <1>; + pclkb-div = <2>; + pclkc-div = <1>; + pclkd-div = <1>; + fclk-div = <2>; +}; diff --git a/boards/arm/arduino_uno_r4/arduino_uno_r4_minima.yaml b/boards/arm/arduino_uno_r4/arduino_uno_r4_minima.yaml new file mode 100644 index 000000000000000..81f3a94866a7a5f --- /dev/null +++ b/boards/arm/arduino_uno_r4/arduino_uno_r4_minima.yaml @@ -0,0 +1,12 @@ +identifier: arduino_uno_r4_minima +name: Arduino Uno R4 Minima +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 32 +supported: + - gpio + - uart diff --git a/boards/arm/arduino_uno_r4/arduino_uno_r4_minima_defconfig b/boards/arm/arduino_uno_r4/arduino_uno_r4_minima_defconfig new file mode 100644 index 000000000000000..57abb9349989408 --- /dev/null +++ b/boards/arm/arduino_uno_r4/arduino_uno_r4_minima_defconfig @@ -0,0 +1,26 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_RA4M1=y +CONFIG_SOC_R7FA4M1AB3CFM=y + +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=48000000 + +CONFIG_BUILD_OUTPUT_HEX=y + +# enable uart driver +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# enable GPIO +CONFIG_GPIO=y + +CONFIG_PINCTRL=y + +CONFIG_CLOCK_CONTROL=y + +CONFIG_USE_DT_CODE_PARTITION=y diff --git a/boards/arm/arduino_uno_r4/board.cmake b/boards/arm/arduino_uno_r4/board.cmake new file mode 100644 index 000000000000000..a034dd9dcdfa40d --- /dev/null +++ b/boards/arm/arduino_uno_r4/board.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(pyocd "--target=r7fa4m1ab") + +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/arduino_uno_r4/doc/index.rst b/boards/arm/arduino_uno_r4/doc/index.rst new file mode 100644 index 000000000000000..e94c4c78902d0ba --- /dev/null +++ b/boards/arm/arduino_uno_r4/doc/index.rst @@ -0,0 +1,64 @@ +.. _arduino_uno_r4: + +Arduino UNO R4 Minima +##################### + +Overview +******** + +The Arduino UNO R4 Minima is a development board featuring the Renesas RA4M1 SoC +in the Arduino form factor and is compatible with traditional Arduino. + +Programming and debugging +************************* + +Building & Flashing +=================== + +You can build and flash an application in the usual way (See +:ref:`build_an_application` and +:ref:`application_run` for more details). + +Here is an example for building and flashing the :zephyr:code-sample:`blinky` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: arduino_uno_r4_minima + :goals: build flash + +Debugging +========= + +Debugging also can be done in the usual way. +The following command is debugging the :zephyr:code-sample:`blinky` application. +Also, see the instructions specific to the debug server that you use. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: arduino_uno_r4_minima + :maybe-skip-config: + :goals: debug + + +Using pyOCD +----------- + +Various debug adapters, including cmsis-dap probes, can debug the Arduino UNO R4 with pyOCD. +The default configuration uses the pyOCD for debugging. +You must install CMSIS-Pack when flashing or debugging Arduino UNO R4 Minima with pyOCD. +If not installed yet, execute the following command to install CMSIS-Pack for Arduino UNO R4. + +.. code-block:: console + + pyocd pack install r7fa4m1ab + + +Restoring Arduino Bootloader +============================ + +If you corrupt the Arduino bootloader, you can restore it with the following command. + +.. code-block:: console + + wget https://raw.githubusercontent.com/arduino/ArduinoCore-renesas/main/bootloaders/UNO_R4/dfu_minima.hex + pyocd flash -e sector -a 0x0 -t r7fa4m1ab dfu_minima.hex diff --git a/boards/arm/arty/arty_a7_arm_designstart_m3.dts b/boards/arm/arty/arty_a7_arm_designstart_m3.dts index 59a5ed88fa8dcbe..4191febff6e9c0a 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 6a0e696b39bfe02..62278d4421327d1 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 bb060fe32a46ce9..e7d7d2d58525cdb 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/atsamd20_xpro/atsamd20_xpro.yaml b/boards/arm/atsamd20_xpro/atsamd20_xpro.yaml index d0a541196fb6bc8..4138e137100292b 100644 --- a/boards/arm/atsamd20_xpro/atsamd20_xpro.yaml +++ b/boards/arm/atsamd20_xpro/atsamd20_xpro.yaml @@ -10,6 +10,7 @@ toolchain: - xtools supported: - adc + - flash - gpio - i2c - spi diff --git a/boards/arm/atsamd21_xpro/atsamd21_xpro.dts b/boards/arm/atsamd21_xpro/atsamd21_xpro.dts index e48e5afd46771d8..d65d773a66fe86b 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 9732c84d6fbf215..78ed6da63ffebd9 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/atsame54_xpro/atsame54_xpro.dts b/boards/arm/atsame54_xpro/atsame54_xpro.dts index b5f9ab19b3902ba..a9bc92ad8a703bf 100644 --- a/boards/arm/atsame54_xpro/atsame54_xpro.dts +++ b/boards/arm/atsame54_xpro/atsame54_xpro.dts @@ -138,3 +138,21 @@ zephyr_udc0: &usb0 { reg = <0>; }; }; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * The final 16 KiB is reserved for the application. + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@fc000 { + label = "storage"; + reg = <0x000fc000 0x00004000>; + }; + }; +}; diff --git a/boards/arm/atsame54_xpro/atsame54_xpro.yaml b/boards/arm/atsame54_xpro/atsame54_xpro.yaml index 272389591313785..f23ef379363119d 100644 --- a/boards/arm/atsame54_xpro/atsame54_xpro.yaml +++ b/boards/arm/atsame54_xpro/atsame54_xpro.yaml @@ -12,6 +12,7 @@ toolchain: - xtools supported: - adc + - flash - gpio - pwm - spi diff --git a/boards/arm/atsaml21_xpro/atsaml21_xpro-pinctrl.dtsi b/boards/arm/atsaml21_xpro/atsaml21_xpro-pinctrl.dtsi index eb96b72e3393d03..102e6b2253ea1ac 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 0e03a7e96f4043d..ee800d7ae9525a9 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 2051b9efa189096..5c55f23d5874e72 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/atsamr21_xpro.dts b/boards/arm/atsamr21_xpro/atsamr21_xpro.dts index 9dd7f6f91d654fa..86981d86cfecc71 100644 --- a/boards/arm/atsamr21_xpro/atsamr21_xpro.dts +++ b/boards/arm/atsamr21_xpro/atsamr21_xpro.dts @@ -207,3 +207,21 @@ ext2_spi: &sercom5 { ext2_i2c: &sercom1 { }; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * The final 16 KiB is reserved for the application. + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@3c000 { + label = "storage"; + reg = <0x0003c000 0x00004000>; + }; + }; +}; diff --git a/boards/arm/atsamr21_xpro/atsamr21_xpro.yaml b/boards/arm/atsamr21_xpro/atsamr21_xpro.yaml index 5ecfcb166c2ba7e..04608ed2afbabfc 100644 --- a/boards/arm/atsamr21_xpro/atsamr21_xpro.yaml +++ b/boards/arm/atsamr21_xpro/atsamr21_xpro.yaml @@ -13,6 +13,7 @@ toolchain: - xtools supported: - adc + - flash - gpio - i2c - netif diff --git a/boards/arm/atsamr21_xpro/doc/index.rst b/boards/arm/atsamr21_xpro/doc/index.rst index da9cb14a4370979..60d2c36ea3226b5 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 81cfb6a7bca2a5c..e7e01a22536cfe0 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 aba04a1b3e6ab63..fe0ae80ae35ccde 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 051245c5d392a67..6347b50dedbd673 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 13b641719ee0108..4c77535ce212004 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 d5dc048b48ae7cf..1eb84827718ec49 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 1959ab6ad6802e4..75d99572fbf24e4 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 61d4c1167ad7eeb..059f36907a28c5e 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 da66cb53adaaeb8..c51161814327db5 100644 --- a/boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts +++ b/boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts @@ -148,15 +148,16 @@ 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>; + spi-max-frequency = ; + spi-hold-cs; }; wifi0: ism43362@1 { diff --git a/boards/arm/b_l4s5i_iot01a/doc/index.rst b/boards/arm/b_l4s5i_iot01a/doc/index.rst index 14d9480707b0117..d5b11c8b30b3ab9 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 dde73804665192d..f6ca91f1a73b492 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 93748d0dcf2af81..bc10deca7a21fb8 100644 --- a/boards/arm/b_u585i_iot02a/Kconfig.defconfig +++ b/boards/arm/b_u585i_iot02a/Kconfig.defconfig @@ -16,8 +16,23 @@ config SPI_STM32_INTERRUPT config USE_DT_CODE_PARTITION default y if TRUSTED_EXECUTION_NONSECURE -# LPTIM clocked by LSE, force tick freq to 4096 for tick accuracy -config SYS_CLOCK_TICKS_PER_SEC - default 4096 if STM32_LPTIM_TIMER +if BUILD_WITH_TFM + +# Initial Attestation key provisioned by the BL1 bootloader +config TFM_INITIAL_ATTESTATION_KEY + default y + +config TFM_DUMMY_PROVISIONING + default n + +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 b9b07348f3c6d5b..f2dd82f9ad12600 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"; diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts index f8a826b1b6ed401..33093d701b78dbc 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.yaml b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.yaml index 9faefebf0bcd874..27ba601cae56dbb 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a.yaml +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.yaml @@ -22,4 +22,5 @@ supported: - backup_sram - pwm - counter + - i2c vendor: st diff --git a/boards/arm/b_u585i_iot02a/doc/index.rst b/boards/arm/b_u585i_iot02a/doc/index.rst index 3c794b4de792635..3121cfc54710f02 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 000000000000000..812d18cdf6c5380 --- /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 5bf0c28c9cfd1ba..17decdb0abe5060 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 a91c7674688ad64..d61a30d944bef97 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 d802907c9737f25..f123d003217e685 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 3f6fcafaa218718..9f8c84df95601cf 100644 --- a/boards/arm/beagle_bcf/beagleconnect_freedom.dts +++ b/boards/arm/beagle_bcf/beagleconnect_freedom.dts @@ -59,7 +59,7 @@ sens_i2c: sensor-switch { status = "okay"; - compatible = "ti,ts5a2066"; + compatible = "gpio-i2c-switch"; #address-cells = <1>; #size-cells = <0>; controller = <&i2c0>; diff --git a/boards/arm/beagle_bcf/beagleconnect_freedom_defconfig b/boards/arm/beagle_bcf/beagleconnect_freedom_defconfig index af58105267c9571..a2c05f40f32331f 100644 --- a/boards/arm/beagle_bcf/beagleconnect_freedom_defconfig +++ b/boards/arm/beagle_bcf/beagleconnect_freedom_defconfig @@ -20,3 +20,11 @@ CONFIG_CC13X2_CC26X2_BOOTLOADER_BACKDOOR_PIN=15 # Enable MPU and hardware stack protection CONFIG_ARM_MPU=y CONFIG_HW_STACK_PROTECTION=y + +# Enable default uart console +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Adjust for oscillator capacitors +CONFIG_CC13X2_CC26X2_XOSC_CAPARRAY_DELTA=0x02 diff --git a/boards/arm/beagle_bcf/board.cmake b/boards/arm/beagle_bcf/board.cmake index 84d7457e7b1b34e..480bb68aaa30715 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 c208d41e43121c5..43a237d03177532 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 541334195dd1977..863c8bb599e060e 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 b/boards/arm/bl5340_dvk/Kconfig index 4be3f3971b0f45c..365da6269e1334e 100644 --- a/boards/arm/bl5340_dvk/Kconfig +++ b/boards/arm/bl5340_dvk/Kconfig @@ -44,7 +44,7 @@ config DOMAIN_CPUNET_BOARD 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_rpmsg on the bl5340_dvk_cpunet for + another board. For example hci_ipc on the bl5340_dvk_cpunet for Bluetooth applications. endif # BOARD_BL5340_DVK_CPUAPP || BOARD_BL5340_DVK_CPUAPP_NS diff --git a/boards/arm/bl5340_dvk/Kconfig.defconfig b/boards/arm/bl5340_dvk/Kconfig.defconfig index 38a06c8b91dced2..d87d6d75f37dcf6 100644 --- a/boards/arm/bl5340_dvk/Kconfig.defconfig +++ b/boards/arm/bl5340_dvk/Kconfig.defconfig @@ -13,21 +13,6 @@ config BOARD config I2C default GPIO || DAC -# By default, if we build for a Non-Secure version of the board, -# enable building with TF-M as the Secure Execution Environment. -config BUILD_WITH_TFM - default y if BOARD_BL5340_DVK_CPUAPP_NS - -if BUILD_WITH_TFM - -# By default, if we build with TF-M, instruct build system to -# flash the combined TF-M (Secure) & Zephyr (Non Secure) image -config TFM_FLASH_MERGED_BINARY - bool - default y - -endif # BUILD_WITH_TFM - # Code Partition: # # For the secure version of the board the firmware is linked at the beginning @@ -90,11 +75,12 @@ config MBOX_NRFX_IPC if BOARD_BL5340_DVK_CPUAPP || BOARD_BL5340_DVK_CPUAPP_NS choice BT_HCI_BUS_TYPE - default BT_RPMSG if BT + default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE - default 4096 if BT_RPMSG +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 4096 if BT_HCI_IPC config BT_HCI_VS default y if BT 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 5020c9a7af9e47b..a5d9b72b62eaf34 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 4fd2c3510138a99..04039294b7626dc 100644 --- a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi +++ b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi @@ -15,7 +15,7 @@ zephyr,bt-mon-uart = &uart0; zephyr,bt-c2h-uart = &uart0; zephyr,display = &ili9340; - zephyr,bt-hci-rpmsg-ipc = &ipc0; + zephyr,bt-hci-ipc = &ipc0; }; /* Main LEDs and buttons are on an I2C TCA9538 GPIO port expander */ @@ -244,6 +244,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 b943c5bdfbf3e81..9fdcba5f0e30bd1 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/bl5340_dvk/bl5340_dvk_cpunet.dts b/boards/arm/bl5340_dvk/bl5340_dvk_cpunet.dts index 7e6b6022e7a2ecb..2b3eb053283e6cb 100644 --- a/boards/arm/bl5340_dvk/bl5340_dvk_cpunet.dts +++ b/boards/arm/bl5340_dvk/bl5340_dvk_cpunet.dts @@ -22,7 +22,7 @@ zephyr,sram = &sram1; zephyr,flash = &flash1; zephyr,code-partition = &slot0_partition; - zephyr,bt-hci-rpmsg-ipc = &ipc0; + zephyr,bt-hci-ipc = &ipc0; }; aliases { diff --git a/boards/arm/bl5340_dvk/doc/index.rst b/boards/arm/bl5340_dvk/doc/index.rst index 4a9fe7b12075972..544250baa8420c0 100644 --- a/boards/arm/bl5340_dvk/doc/index.rst +++ b/boards/arm/bl5340_dvk/doc/index.rst @@ -290,7 +290,7 @@ described below. .. note:: - By default the the Secure image for BL5340's application core is + By default the Secure image for BL5340's application core is built using TF-M. Building the Secure firmware with TF-M diff --git a/boards/arm/bl653_dvk/bl653_dvk.dts b/boards/arm/bl653_dvk/bl653_dvk.dts index ba8fa3658d248f7..4c536eb45125506 100644 --- a/boards/arm/bl653_dvk/bl653_dvk.dts +++ b/boards/arm/bl653_dvk/bl653_dvk.dts @@ -148,7 +148,7 @@ &spi1 { compatible = "nordic,nrf-spi"; status = "okay"; - cs-gpios = <&gpio1 23 0>; + cs-gpios = <&gpio0 23 GPIO_ACTIVE_LOW>; pinctrl-0 = <&spi1_default>; pinctrl-1 = <&spi1_sleep>; pinctrl-names = "default", "sleep"; diff --git a/boards/arm/bl654_usb/bl654_usb.dts b/boards/arm/bl654_usb/bl654_usb.dts index 80600290dbff241..fa814f4b80e421f 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 489401a5fb3dc44..c6b9bad9910ac88 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/cc1352p1_launchxl/doc/index.rst b/boards/arm/cc1352p1_launchxl/doc/index.rst index 5e9690fefbd06dd..a5f88cc19ffd6cc 100644 --- a/boards/arm/cc1352p1_launchxl/doc/index.rst +++ b/boards/arm/cc1352p1_launchxl/doc/index.rst @@ -133,7 +133,7 @@ Programming and Debugging ************************* Before flashing or debugging ensure the RESET, TMS, TCK, TDO, and TDI jumpers -are in place. Also place jumpers on the the TXD and RXD signals for a serial +are in place. Also place jumpers on the TXD and RXD signals for a serial console using the XDS110 application serial port. Prerequisites: diff --git a/boards/arm/cc1352r1_launchxl/doc/index.rst b/boards/arm/cc1352r1_launchxl/doc/index.rst index b3c999a1494f269..0002b1e1c6f7995 100644 --- a/boards/arm/cc1352r1_launchxl/doc/index.rst +++ b/boards/arm/cc1352r1_launchxl/doc/index.rst @@ -132,7 +132,7 @@ Programming and Debugging ************************* Before flashing or debugging ensure the RESET, TMS, TCK, TDO, and TDI jumpers -are in place. Also place jumpers on the the TXD and RXD signals for a serial +are in place. Also place jumpers on the TXD and RXD signals for a serial console using the XDS110 application serial port. Prerequisites: diff --git a/boards/arm/cc26x2r1_launchxl/doc/index.rst b/boards/arm/cc26x2r1_launchxl/doc/index.rst index 89bdb035a31891a..8177df13ae3aa3a 100644 --- a/boards/arm/cc26x2r1_launchxl/doc/index.rst +++ b/boards/arm/cc26x2r1_launchxl/doc/index.rst @@ -138,7 +138,7 @@ Programming and Debugging ************************* Before flashing or debugging ensure the RESET, TMS, TCK, TDO, and TDI jumpers -are in place. Also place jumpers on the the TXD and RXD signals for a serial +are in place. Also place jumpers on the TXD and RXD signals for a serial console using the XDS110 application serial port. Prerequisites: diff --git a/boards/arm/cc3220sf_launchxl/doc/index.rst b/boards/arm/cc3220sf_launchxl/doc/index.rst index 8b88133ccbd7e59..4e941cef91ed1f5 100644 --- a/boards/arm/cc3220sf_launchxl/doc/index.rst +++ b/boards/arm/cc3220sf_launchxl/doc/index.rst @@ -172,7 +172,7 @@ Prerequisites: to the paths of the OpenOCD binary and its scripts, before including the common openocd.board.cmake file: - .. code-block:: none + .. code-block:: cmake set(OPENOCD "/usr/local/bin/openocd" CACHE FILEPATH "" FORCE) set(OPENOCD_DEFAULT_PATH /usr/local/share/openocd/scripts) diff --git a/boards/arm/cc3235sf_launchxl/doc/index.rst b/boards/arm/cc3235sf_launchxl/doc/index.rst index 71d8a44a8fb3efc..80a4fb3c0e9fa8e 100644 --- a/boards/arm/cc3235sf_launchxl/doc/index.rst +++ b/boards/arm/cc3235sf_launchxl/doc/index.rst @@ -172,7 +172,7 @@ Prerequisites: to the paths of the OpenOCD binary and its scripts, before including the common openocd.board.cmake file: - .. code-block:: none + .. code-block:: cmake set(OPENOCD "/usr/local/bin/openocd" CACHE FILEPATH "" FORCE) set(OPENOCD_DEFAULT_PATH /usr/local/share/openocd/scripts) diff --git a/boards/arm/circuitdojo_feather_nrf9160/circuitdojo_feather_nrf9160_common.dtsi b/boards/arm/circuitdojo_feather_nrf9160/circuitdojo_feather_nrf9160_common.dtsi index 33fdba4d865f7d3..00ce5dcf6c00cf6 100644 --- a/boards/arm/circuitdojo_feather_nrf9160/circuitdojo_feather_nrf9160_common.dtsi +++ b/boards/arm/circuitdojo_feather_nrf9160/circuitdojo_feather_nrf9160_common.dtsi @@ -187,22 +187,19 @@ slot0_partition: partition@10000 { label = "image-0"; }; - slot0_ns_partition: partition@40000 { + slot0_ns_partition: partition@50000 { label = "image-0-nonsecure"; }; slot1_partition: partition@80000 { label = "image-1"; }; - slot1_ns_partition: partition@b0000 { + slot1_ns_partition: partition@c0000 { label = "image-1-nonsecure"; }; - scratch_partition: partition@f0000 { - label = "image-scratch"; - reg = <0x000f0000 0xa000>; - }; - storage_partition: partition@fa000 { + /* 0xf0000 to 0xf7fff reserved for TF-M partitions */ + storage_partition: partition@f8000 { label = "storage"; - reg = <0x000fa000 0x00006000>; + reg = <0x000f8000 0x00008000>; }; }; }; diff --git a/boards/arm/circuitdojo_feather_nrf9160/circuitdojo_feather_nrf9160_ns.yaml b/boards/arm/circuitdojo_feather_nrf9160/circuitdojo_feather_nrf9160_ns.yaml index c358a1d87fe77ad..56905972e9f2c1b 100644 --- a/boards/arm/circuitdojo_feather_nrf9160/circuitdojo_feather_nrf9160_ns.yaml +++ b/boards/arm/circuitdojo_feather_nrf9160/circuitdojo_feather_nrf9160_ns.yaml @@ -7,7 +7,7 @@ toolchain: - xtools - zephyr ram: 128 -flash: 256 +flash: 192 supported: - i2c - pwm diff --git a/boards/arm/circuitdojo_feather_nrf9160/circuitdojo_feather_nrf9160_partition_conf.dtsi b/boards/arm/circuitdojo_feather_nrf9160/circuitdojo_feather_nrf9160_partition_conf.dtsi index e8cb6fc586e2370..007975132d6dc52 100644 --- a/boards/arm/circuitdojo_feather_nrf9160/circuitdojo_feather_nrf9160_partition_conf.dtsi +++ b/boards/arm/circuitdojo_feather_nrf9160/circuitdojo_feather_nrf9160_partition_conf.dtsi @@ -23,19 +23,19 @@ */ &slot0_partition { - reg = <0x00010000 0x30000>; + reg = <0x00010000 0x40000>; }; &slot0_ns_partition { - reg = <0x00040000 0x40000>; + reg = <0x00050000 0x30000>; }; &slot1_partition { - reg = <0x00080000 0x30000>; + reg = <0x00080000 0x40000>; }; &slot1_ns_partition { - reg = <0x000b0000 0x40000>; + reg = <0x000c0000 0x30000>; }; /* Default SRAM planning when building for nRF9160 with diff --git a/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig b/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig index 14c47a06e584d0c..0ed2d3728356330 100644 --- a/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig +++ b/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig @@ -10,8 +10,8 @@ config BOARD if WIFI || BT -# Select CYW43XXX part and module -choice CYW43XXX_PART +# Select AIROC part and module +choice AIROC_PART default CYW4343W endchoice @@ -21,6 +21,16 @@ endchoice endif # WIFI || BT +if WIFI + +config WIFI_AIROC + default y + +# Enable L2 Ethernet +config NET_L2_ETHERNET + default y + +endif # WIFI if BT @@ -38,4 +48,10 @@ endchoice endif # BT +# Heap Pool Size +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 15000 if WIFI + default 4096 + endif # BOARD_CY8CPROTO_062_4343W diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-common.dtsi b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-common.dtsi index 3676cdbb471e398..75012f88ffc7a52 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-common.dtsi +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-common.dtsi @@ -34,6 +34,10 @@ status = "okay"; }; +&gpio_prt2 { + status = "okay"; +}; + &gpio_prt3 { status = "okay"; }; diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi index d86f9b67bfa7566..fcf6655e5d6709a 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Rtone. + * Copyright (c) 2023 Cypress Semiconductor Corporation. * SPDX-License-Identifier: Apache-2.0 */ @@ -28,3 +28,53 @@ &p5_0_scb5_uart_rx { input-enable; }; + +/* Configure pin control bias mode for i2c3 pins */ +&p6_0_scb3_i2c_scl { + drive-open-drain; + input-enable; +}; + +&p6_1_scb3_i2c_sda { + drive-open-drain; + input-enable; +}; + +&pinctrl { + /* Configure pin control bias mode for SDIO */ + p2_5_sdio_clk: p2_5_sdio_clk { + pinmux = ; + drive-push-pull; + input-enable; + }; + + p2_4_sdio_cmd: p2_4_sdio_cmd { + pinmux = ; + drive-push-pull; + input-enable; + }; + + p2_0_sdio_data0: p2_0_sdio_data0 { + pinmux = ; + drive-push-pull; + input-enable; + }; + + p2_1_sdio_data1: p2_1_sdio_data1 { + pinmux = ; + drive-push-pull; + input-enable; + }; + + p2_2_sdio_data2: p2_2_sdio_data2 { + pinmux = ; + drive-push-pull; + input-enable; + }; + + p2_3_sdio_data3: p2_3_sdio_data3 { + pinmux = ; + drive-push-pull; + input-enable; + }; +}; diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.dts b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.dts index 4d9149b198aaf74..cc793184b143e63 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.dts +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.dts @@ -17,6 +17,7 @@ uart-5 = &uart5; i2c-0 = &i2c3; watchdog0 = &watchdog0; + sdhc0 = &sdhc0; }; chosen { @@ -50,7 +51,7 @@ uart2: &scb2 { current-speed = <115200>; - /* HCI-UART pins*/ + /* HCI-UART pins */ pinctrl-0 = <&p3_1_scb2_uart_tx &p3_0_scb2_uart_rx &p3_2_scb2_uart_rts &p3_3_scb2_uart_cts>; pinctrl-names = "default"; @@ -68,6 +69,25 @@ uart2: &scb2 { }; }; +&sdhc0 { + status = "okay"; + + /* SDIO pins */ + pinctrl-0 = <&p2_4_sdio_cmd &p2_5_sdio_clk &p2_0_sdio_data0 + &p2_1_sdio_data1 &p2_2_sdio_data2 &p2_3_sdio_data3>; + pinctrl-names = "default"; + + /* Wi-Fi configuration */ + airoc-wifi { + status = "okay"; + compatible = "infineon,airoc-wifi"; + + /* Wi-Fi control gpios */ + wifi-reg-on-gpios = <&gpio_prt2 6 GPIO_ACTIVE_HIGH>; + wifi-host-wake-gpios = <&gpio_prt0 4 GPIO_ACTIVE_HIGH>; + }; +}; + /* System clock configuration */ &fll0 { status = "okay"; diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml index 36d08b2a4d0576f..8300a160c5a9857 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml @@ -7,13 +7,17 @@ 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 - gnuarmemb supported: - adc + - bluetooth + - wifi + - airoc + - cyw4343w - counter - gpio - uart diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w_defconfig b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w_defconfig index c36ce13e1a878f7..3dd8e0eac78a017 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w_defconfig +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w_defconfig @@ -29,3 +29,6 @@ CONFIG_GPIO=y # Enable clock controller CONFIG_CLOCK_CONTROL=y + +# Main Stack Size +CONFIG_MAIN_STACK_SIZE=2048 diff --git a/boards/arm/da14695_dk_usb/Kconfig b/boards/arm/da14695_dk_usb/Kconfig new file mode 100644 index 000000000000000..38ccd8265071a4d --- /dev/null +++ b/boards/arm/da14695_dk_usb/Kconfig @@ -0,0 +1,4 @@ +# DA14695 Development Kit USB board configuration + +# Copyright (c) 2023 Renesas Electronics Corporation and/or its affiliates +# SPDX-License-Identifier: Apache-2.0 diff --git a/boards/arm/da14695_dk_usb/Kconfig.board b/boards/arm/da14695_dk_usb/Kconfig.board new file mode 100644 index 000000000000000..67dbe731ffa5384 --- /dev/null +++ b/boards/arm/da14695_dk_usb/Kconfig.board @@ -0,0 +1,8 @@ +# DA14695 Development Kit USB board configuration + +# Copyright (c) 2023 Renesas Electronics Corporation and/or its affiliates +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_DA14695_DK_USB + bool "DA14695 Development Kit USB board" + depends on SOC_SERIES_DA1469X diff --git a/boards/arm/da14695_dk_usb/Kconfig.defconfig b/boards/arm/da14695_dk_usb/Kconfig.defconfig new file mode 100644 index 000000000000000..8208a705bd83917 --- /dev/null +++ b/boards/arm/da14695_dk_usb/Kconfig.defconfig @@ -0,0 +1,11 @@ +# DA14695 Development Kit USB board configuration + +# Copyright (c) 2023 Renesas Electronics Corporation and/or its affiliates +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_DA14695_DK_USB + +config BOARD + default "da14695_dk_usb" + +endif # BOARD_DA14695_DK_USB diff --git a/boards/arm/da14695_dk_usb/board.cmake b/boards/arm/da14695_dk_usb/board.cmake new file mode 100644 index 000000000000000..fc5981bb3911380 --- /dev/null +++ b/boards/arm/da14695_dk_usb/board.cmake @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023 Renesas Electronics Corporation and/or its affiliates +# +# SPDX-License-Identifier: Apache-2.0 +# + +board_runner_args(ezflashcli) +board_runner_args(jlink --device=DA14695) +include(${ZEPHYR_BASE}/boards/common/ezflashcli.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/da14695_dk_usb/da14695_dk_usb-pinctrl.dtsi b/boards/arm/da14695_dk_usb/da14695_dk_usb-pinctrl.dtsi new file mode 100644 index 000000000000000..d16ad945fa855c6 --- /dev/null +++ b/boards/arm/da14695_dk_usb/da14695_dk_usb-pinctrl.dtsi @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + uart_default: uart_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + uart2_default: uart2_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + uart3_default: uart3_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + i2c_default: i2c_default { + group1 { + pinmux = , + ; + bias-pull-up; + }; + }; + + i2c2_default: i2c2_default { + group1 { + pinmux = , + ; + bias-pull-up; + }; + }; + + spi_controller: spi_controller { + group1 { + pinmux = < SMARTBOND_PINMUX(SPI_CLK, 0, 21) >, + ; + output-enable; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + spi2_controller: spi2_controller { + group1 { + pinmux = < SMARTBOND_PINMUX(SPI2_CLK, 1, 3) >, + ; + output-enable; + }; + group2 { + pinmux = ; + input-enable; + }; + }; +}; diff --git a/boards/arm/da14695_dk_usb/da14695_dk_usb.dts b/boards/arm/da14695_dk_usb/da14695_dk_usb.dts new file mode 100644 index 000000000000000..eff5299dcff60bd --- /dev/null +++ b/boards/arm/da14695_dk_usb/da14695_dk_usb.dts @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "da14695_dk_usb-pinctrl.dtsi" +#include + +/ { + model = "DA14695 series Development Kit USB"; + compatible = "renesas,da14695_dk_usb"; + #address-cells = <1>; + #size-cells = <1>; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &uart; + zephyr,shell-uart = &uart; + zephyr,code-partition = &slot0_partition; + }; + + leds { + compatible = "gpio-leds"; + red_led: led_0 { + gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 6 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; + label = "Push button switch K1"; + zephyr,code = ; + }; + }; + + mikrobus_header{ + mikrobus-connector-1 { + compatible = "mikro-bus"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 25 0>, /* AN */ + /* Not a GPIO*/ /* RST */ + <2 0 &gpio1 2 0>, /* CS */ + <3 0 &gpio1 3 0>, /* SCK */ + <4 0 &gpio1 4 0>, /* MISO */ + <5 0 &gpio1 5 0>, /* MOSI */ + /* +3.3V */ + /* GND */ + <6 0 &gpio1 6 0>, /* PWM */ + <7 0 &gpio1 7 0>, /* INT */ + <8 0 &gpio1 8 0>, /* RX */ + <9 0 &gpio0 17 0>, /* TX */ + <10 0 &gpio0 18 0>, /* SCL */ + <11 0 &gpio0 19 0>; /* SDA */ + /* +5V */ + /* GND */ + }; + mikrobus-connector-2 { + compatible = "mikro-bus"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio1 9 0>, /* AN */ + /* Not a GPIO*/ /* RST */ + <2 0 &gpio0 20 0>, /* CS */ + <3 0 &gpio0 21 0>, /* SCK */ + <4 0 &gpio0 24 0>, /* MISO */ + <5 0 &gpio0 26 0>, /* MOSI */ + /* +3.3V */ + /* GND */ + <6 0 &gpio1 1 0>, /* PWM */ + <7 0 &gpio0 27 0>, /* INT */ + <8 0 &gpio0 28 0>, /* RX */ + <9 0 &gpio0 29 0>, /* TX */ + <10 0 &gpio0 30 0>, /* SCL */ + <11 0 &gpio0 31 0>; /* SDA */ + /* +5V */ + /* GND */ + }; + }; + + aliases { + led0 = &red_led; + watchdog0 = &wdog; + }; + + sysclk: system-clock { + compatible = "fixed-clock"; + clock-frequency = <32000000>; + #clock-cells = <0>; + }; +}; + +&flash0 { + reg = <0x16000000 DT_SIZE_M(1)>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * Flash area from 0x0000 to 0x2400 is reserved + * for product header added by flasher. + */ + + boot_partition: partition@2400 { + label = "mcuboot"; + reg = <0x000002400 0x00009c00>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000c000 0x00076000>; + }; + slot1_partition: partition@80000 { + label = "image-1"; + reg = <0x00082000 0x00076000>; + }; + storage_partition: partition@f8000 { + label = "storage"; + reg = <0x000f8000 0x00008000>; + }; + }; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&uart { + current-speed = <115200>; + status = "okay"; + pinctrl-0 = <&uart_default>; + pinctrl-names = "default"; +}; + +&uart2 { + current-speed = <115200>; + status = "okay"; + pinctrl-0 = <&uart2_default>; + pinctrl-names = "default"; +}; + +&uart3 { + current-speed = <115200>; + status = "okay"; + pinctrl-0 = <&uart3_default>; + pinctrl-names = "default"; +}; + +zephyr_udc0: &usbd { + compatible = "renesas,smartbond-usbd"; + status = "okay"; +}; + +&rc32m { + status = "disabled"; +}; + +&xtal32m { + status = "okay"; +}; + +&xtal32k { + status = "okay"; +}; + +&lp_clk { + clock-src = <&xtal32k>; +}; + +&sys_clk { + clock-src = <&xtal32m>; +}; + +&pll { + status = "okay"; +}; +&i2c { + status = "okay"; + pinctrl-0 = <&i2c_default>; + pinctrl-names = "default"; +}; + +&i2c2 { + status = "okay"; + pinctrl-0 = <&i2c2_default>; + pinctrl-names = "default"; +}; + +&spi { + status = "okay"; + pinctrl-0 = <&spi_controller>; + pinctrl-names = "default"; +}; + +&spi2 { + status = "okay"; + pinctrl-0 = <&spi2_controller>; + pinctrl-names = "default"; +}; + +mikrobus_1_i2c: &i2c {}; + +mikrobus_1_spi: &spi {}; + +mikrobus_1_uart: &uart2 {}; + +mikrobus_2_i2c: &i2c2 {}; + +mikrobus_2_spi: &spi2 {}; + +mikrobus_2_uart: &uart3 {}; diff --git a/boards/arm/da14695_dk_usb/da14695_dk_usb.yaml b/boards/arm/da14695_dk_usb/da14695_dk_usb.yaml new file mode 100644 index 000000000000000..bc55d5ada4dcde3 --- /dev/null +++ b/boards/arm/da14695_dk_usb/da14695_dk_usb.yaml @@ -0,0 +1,17 @@ +identifier: da14695_dk_usb +name: DA14695_DK_USB +type: mcu +arch: arm +ram: 512 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - arduino_gpio + - gpio + - hwinfo + - watchdog + - i2c + - spi + - usb_device diff --git a/boards/arm/da14695_dk_usb/da14695_dk_usb_defconfig b/boards/arm/da14695_dk_usb/da14695_dk_usb_defconfig new file mode 100644 index 000000000000000..d0a672430343df6 --- /dev/null +++ b/boards/arm/da14695_dk_usb/da14695_dk_usb_defconfig @@ -0,0 +1,22 @@ +# +# Copyright (c) 2023 Renesas Electronics Corporation and/or its affiliates +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SOC_SERIES_DA1469X=y +CONFIG_SOC_DA14695=y +CONFIG_BOARD_DA14695_DK_USB=y + +CONFIG_HW_STACK_PROTECTION=y + +CONFIG_GPIO=y + +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y + +CONFIG_BUILD_OUTPUT_HEX=n + +CONFIG_I2C=y +CONFIG_I2C_CALLBACK=y diff --git a/boards/arm/da14695_dk_usb/doc/da14695-00hqdevkt-u-usb-board.jpg b/boards/arm/da14695_dk_usb/doc/da14695-00hqdevkt-u-usb-board.jpg new file mode 100644 index 000000000000000..1f0c6021e763af1 Binary files /dev/null and b/boards/arm/da14695_dk_usb/doc/da14695-00hqdevkt-u-usb-board.jpg differ diff --git a/boards/arm/da14695_dk_usb/doc/index.rst b/boards/arm/da14695_dk_usb/doc/index.rst new file mode 100644 index 000000000000000..84f5c772d8ace1e --- /dev/null +++ b/boards/arm/da14695_dk_usb/doc/index.rst @@ -0,0 +1,116 @@ +.. _da14695_dk_usb: + +DA14695 Development Kit USB +########################### + +Overview +******** + +The DA14695 Development Kit USB is a low cost development board for DA14695. +The development kit comes with an integrated debugger and an USB hub +to have both the on-chip USB and the J-Link connected via a single port. + +.. figure:: da14695-00hqdevkt-u-usb-board.jpg + :width: 442px + :align: center + :alt: DA14695 Development Kit USB + + DA14695 Development Kit USB (Credit: Renesas Electronics Corporation) + +Hardware +******** + +DA14695 Development Kit USB has two external oscillators. The frequency of +the sleep clock is 32768 Hz. The frequency of the system clock is 32 MHz. + +Supported Features +================== + +The _da14695_dk_usb board configuration supports the following +hardware features: + ++-----------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+======================+ +| FLASH | on-chip | flash | ++-----------+------------+----------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+----------------------+ +| MPU | on-chip | arch/arm | ++-----------+------------+----------------------+ +| NVIC | on-chip | arch/arm | ++-----------+------------+----------------------+ +| RTT | Segger | console | ++-----------+------------+----------------------+ +| UART | on-chip | serial | ++-----------+------------+----------------------+ +| SPI | on-chip | spi | ++-----------+------------+----------------------+ + +Other hardware features, including the Configurable MAC (CMAC) controller, +are currently not supported by the port. + +For more information about the DA14695 Development Kit see: + +- `DA14695 DK USB website`_ + +System Clock +============ + +The DA14695 Development Kit USB is configured to use the 32 MHz external oscillator +on the board. + +Connections and IOs +=================== + +The DA14695 Development Kit USB has one LED and one push button which can be used +by applications. The UART is connected to on-board serial converter and accessible +via USB1 port on motherboard. + +The pin connections are as follows: + +* LED (red), = P1.01 +* BUTTON, labeled k1 = P0.06 +* UART RX, connected to J-Link serial = P0.08 +* UART TX, connected to J-Link serial = P0.09 + +Programming and Debugging +************************* + +Applications for the ``da14695_dk_usb`` board configuration 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 +======== + +The DA14695 boots from an external flash connected to QSPI interface. The image +written to flash has to have proper header prepended. The process is simplified +by using dedicated `eZFlashCLI`_ tool that takes care of writing header and can +handle different types of flash chips connected to DA1469x MCU. Follow instructions +on `ezFlashCLI`_ to install the tool. Once installed, flashing can be done in the +usual way. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: da14695_dk_usb + :goals: build flash + +Debugging +========= + +The DA14695 Development Kit USB includes a `J-Link`_ adaptor built-in +which provides both debugging interface and serial port. +Application can be debugged in the usual way once DA14695 Development Kit USB +is connected to PC via USB. + +References +********** + +.. target-notes:: + +.. _DA14695 DK USB website: https://www.renesas.com/us/en/products/wireless-connectivity/bluetooth-low-energy/da14695-00hqdevkt-u-smartbond-da14695-bluetooth-low-energy-52-usb-development-kit +.. _DA1469x Datasheet: https://www.renesas.com/eu/en/document/dst/da1469x-datasheet +.. _J-Link: https://www.segger.com/jlink-debug-probes.html +.. _ezFlashCLI: https://github.com/ezflash/ezFlashCLI/ diff --git a/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml b/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml index 10687f70eae7a27..4d35304c62205eb 100644 --- a/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml +++ b/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml @@ -11,8 +11,12 @@ supported: - arduino_gpio - counter - gpio + - hwinfo - watchdog - i2c - spi - usb_device + - rtc + - crypto + - dma vendor: renesas diff --git a/boards/arm/disco_l475_iot1/Kconfig.defconfig b/boards/arm/disco_l475_iot1/Kconfig.defconfig index 8bf75fa6f7c2e14..3a53147decf6415 100644 --- a/boards/arm/disco_l475_iot1/Kconfig.defconfig +++ b/boards/arm/disco_l475_iot1/Kconfig.defconfig @@ -8,10 +8,6 @@ if BOARD_DISCO_L475_IOT1 config BOARD default "disco_l475_iot1" -# LPTIM clocked by LSE, force tick freq to 4096 for tick accuracy -config SYS_CLOCK_TICKS_PER_SEC - default 4096 if STM32_LPTIM_TIMER - config SPI_STM32_INTERRUPT default y depends on SPI @@ -38,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/board.cmake b/boards/arm/disco_l475_iot1/board.cmake index e38b92214d99fe6..7e6faf6c3833ecc 100644 --- a/boards/arm/disco_l475_iot1/board.cmake +++ b/boards/arm/disco_l475_iot1/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=STM32L475VG" "--speed=4000") include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) diff --git a/boards/arm/disco_l475_iot1/disco_l475_iot1.dts b/boards/arm/disco_l475_iot1/disco_l475_iot1.dts index 8505b05656f217e..9ae6399e62ea68a 100644 --- a/boards/arm/disco_l475_iot1/disco_l475_iot1.dts +++ b/boards/arm/disco_l475_iot1/disco_l475_iot1.dts @@ -187,15 +187,16 @@ 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>; + spi-max-frequency = ; + spi-hold-cs; }; wifi0: ism43362@1 { @@ -260,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"; diff --git a/boards/arm/dragino_lsn50/doc/index.rst b/boards/arm/dragino_lsn50/doc/index.rst index 7931d8f9db879e4..732e0ec1394b2f8 100644 --- a/boards/arm/dragino_lsn50/doc/index.rst +++ b/boards/arm/dragino_lsn50/doc/index.rst @@ -85,7 +85,7 @@ More information about STM32L072CZ can be found here: Supported Features ================== -The Zephyr Dragino LSN50 Board board configuration supports the following hardware features: +The Zephyr Dragino LSN50 board configuration supports the following hardware features: +-----------+------------+-------------------------------------+ | Interface | Controller | Driver/Component | diff --git a/boards/arm/dragino_nbsn95/doc/index.rst b/boards/arm/dragino_nbsn95/doc/index.rst index 71e9f2c9711b785..ca0b3d8cc1d31db 100644 --- a/boards/arm/dragino_nbsn95/doc/index.rst +++ b/boards/arm/dragino_nbsn95/doc/index.rst @@ -84,7 +84,7 @@ More information about STM32L072CZ can be found here: Supported Features ================== -The Zephyr Dragino NBSN95 Board board configuration supports the following hardware features: +The Zephyr Dragino NBSN95 board configuration supports the following hardware features: +-----------+------------+-------------------------------------+ | Interface | Controller | Driver/Component | 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 000000000000000..71d2020569185f7 --- /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 1ff034899dbbff6..5dcae30fbee99e5 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/efm32gg_slwstk6121a/efm32gg_slwstk6121a-pinctrl.dtsi b/boards/arm/efm32gg_slwstk6121a/efm32gg_slwstk6121a-pinctrl.dtsi new file mode 100644 index 000000000000000..ade31fddfd824b9 --- /dev/null +++ b/boards/arm/efm32gg_slwstk6121a/efm32gg_slwstk6121a-pinctrl.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 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_slwstk6121a/efm32gg_slwstk6121a.dts b/boards/arm/efm32gg_slwstk6121a/efm32gg_slwstk6121a.dts index a45d13f7183c26e..10912535b2d197c 100644 --- a/boards/arm/efm32gg_slwstk6121a/efm32gg_slwstk6121a.dts +++ b/boards/arm/efm32gg_slwstk6121a/efm32gg_slwstk6121a.dts @@ -9,6 +9,7 @@ /dts-v1/; #include #include +#include "efm32gg_slwstk6121a-pinctrl.dtsi" / { model = "Silicon Labs EFM32GG SLWSTK6121A board"; @@ -62,8 +63,8 @@ /* Connected to the WSTK VCOM */ &usart0 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a-pinctrl.dtsi b/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a-pinctrl.dtsi new file mode 100644 index 000000000000000..8bb7025f4b2ab88 --- /dev/null +++ b/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a-pinctrl.dtsi @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + /* configuration for usart0 device, default state - operating as UART */ + usart0_default: usart0_default { + group1 { + psels = , + , + , + ; + }; + }; + + usart4_default: usart4_default { + group1 { + psels = , + , + , + ; + }; + }; +}; diff --git a/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a.dts b/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a.dts index 970cbafa1a2411b..1c457890f9105ba 100644 --- a/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a.dts +++ b/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a.dts @@ -8,6 +8,7 @@ /dts-v1/; #include #include +#include "efm32gg_stk3701a-pinctrl.dtsi" / { model = "Silicon Labs EFM32GG STK3701A board"; @@ -60,15 +61,15 @@ &usart0 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; status = "okay"; }; &usart4 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart4_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 000000000000000..24b51c33612b1f0 --- /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 cb0209f8e4a4a88..6611bee4956d091 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/CMakeLists.txt b/boards/arm/efr32_radio/CMakeLists.txt deleted file mode 100644 index 77a7880c491c312..000000000000000 --- a/boards/arm/efr32_radio/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -zephyr_include_directories(.) diff --git a/boards/arm/efr32_radio/Kconfig.board b/boards/arm/efr32_radio/Kconfig.board index 6104a3884f00c34..bbae554ae698f47 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 39c4b9ff695f1fa..b91aa627b706121 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 95eaa403fcbc1f1..d684946143e7297 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 000000000000000..f51d54b5f3dbce1 --- /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 000000000000000..eb912df1e3084d2 Binary files /dev/null and b/boards/arm/efr32_radio/doc/efr32mg12-slwrb4161a.jpeg differ diff --git a/boards/arm/efr32_radio/efr32_radio-pinctrl.dtsi b/boards/arm/efr32_radio/efr32_radio-pinctrl.dtsi new file mode 100644 index 000000000000000..ade31fddfd824b9 --- /dev/null +++ b/boards/arm/efr32_radio/efr32_radio-pinctrl.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 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/efr32_radio/efr32_radio.dtsi b/boards/arm/efr32_radio/efr32_radio.dtsi index a82081de469652d..361b66b72df389d 100644 --- a/boards/arm/efr32_radio/efr32_radio.dtsi +++ b/boards/arm/efr32_radio/efr32_radio.dtsi @@ -5,6 +5,7 @@ */ #include +#include "efr32_radio-pinctrl.dtsi" / { chosen { @@ -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/efr32_radio/efr32_radio_brd4161a.dts b/boards/arm/efr32_radio/efr32_radio_brd4161a.dts new file mode 100644 index 000000000000000..6f1cba19b5c0426 --- /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 000000000000000..108d6f16c0f7115 --- /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 000000000000000..fbf7cf383256d06 --- /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 000000000000000..74723695d8647ac --- /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 0687b206adb93fa..43f4290ff842979 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_brd4180a_defconfig b/boards/arm/efr32_radio/efr32_radio_brd4180a_defconfig index 79da19d546218d7..0db69e5d9e1fec0 100644 --- a/boards/arm/efr32_radio/efr32_radio_brd4180a_defconfig +++ b/boards/arm/efr32_radio/efr32_radio_brd4180a_defconfig @@ -9,3 +9,4 @@ CONFIG_SERIAL=y CONFIG_GPIO=y CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=38400000 CONFIG_CMU_HFCLK_HFXO=y +CONFIG_PINCTRL=y 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 000000000000000..0ea520ce13f5b63 --- /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 1f065fb15b1154a..6e8703fabbeae3c 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/efr32_radio/efr32_radio_brd4187c_defconfig b/boards/arm/efr32_radio/efr32_radio_brd4187c_defconfig index ce32a6638c3e73a..046f8acfaeda9fc 100644 --- a/boards/arm/efr32_radio/efr32_radio_brd4187c_defconfig +++ b/boards/arm/efr32_radio/efr32_radio_brd4187c_defconfig @@ -10,6 +10,7 @@ CONFIG_GPIO=y CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=78000000 CONFIG_SOC_GECKO_EMU_DCDC=y CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y +CONFIG_PINCTRL=y # Use BURTC as system clock source CONFIG_GECKO_BURTC_TIMER=y diff --git a/boards/arm/efr32_radio/sl_device_init_hfxo_config.h b/boards/arm/efr32_radio/sl_device_init_hfxo_config.h deleted file mode 100644 index c410e7c40935523..000000000000000 --- a/boards/arm/efr32_radio/sl_device_init_hfxo_config.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2023 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef SL_DEVICE_INIT_HFXO_CONFIG_H -#define SL_DEVICE_INIT_HFXO_CONFIG_H - -#ifdef CONFIG_BOARD_EFR32_RADIO_BRD4187C - -#define SL_DEVICE_INIT_HFXO_MODE cmuHfxoOscMode_Crystal -#define SL_DEVICE_INIT_HFXO_FREQ 39000000 -#define SL_DEVICE_INIT_HFXO_CTUNE 140 - -#endif /* CONFIG_BOARD_EFR32_RADIO_BRD4187C */ - -#endif /* SL_DEVICE_INIT_HFXO_CONFIG_H */ diff --git a/boards/arm/efr32_thunderboard/CMakeLists.txt b/boards/arm/efr32_thunderboard/CMakeLists.txt index 17faf560addbbd6..ca93e65ac913abb 100644 --- a/boards/arm/efr32_thunderboard/CMakeLists.txt +++ b/boards/arm/efr32_thunderboard/CMakeLists.txt @@ -5,5 +5,3 @@ if(CONFIG_UART_GECKO) zephyr_library() zephyr_library_sources(board.c) endif() - -zephyr_include_directories(.) diff --git a/boards/arm/efr32_thunderboard/sl_device_init_hfxo_config.h b/boards/arm/efr32_thunderboard/sl_device_init_hfxo_config.h deleted file mode 100644 index 1b803c74f3d6154..000000000000000 --- a/boards/arm/efr32_thunderboard/sl_device_init_hfxo_config.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2022 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef SL_DEVICE_INIT_HFXO_CONFIG_H -#define SL_DEVICE_INIT_HFXO_CONFIG_H - -#define SL_DEVICE_INIT_HFXO_MODE cmuHfxoOscMode_Crystal -#define SL_DEVICE_INIT_HFXO_FREQ 38400000 -#define SL_DEVICE_INIT_HFXO_CTUNE 120 - -#endif /* SL_DEVICE_INIT_HFXO_CONFIG_H */ diff --git a/boards/arm/efr32_thunderboard/thunderboard.dtsi b/boards/arm/efr32_thunderboard/thunderboard.dtsi index 31387b876098ca4..be2401138ada690 100644 --- a/boards/arm/efr32_thunderboard/thunderboard.dtsi +++ b/boards/arm/efr32_thunderboard/thunderboard.dtsi @@ -5,6 +5,7 @@ */ #include +#include / { chosen { diff --git a/boards/arm/efr32xg24_dk2601b/CMakeLists.txt b/boards/arm/efr32xg24_dk2601b/CMakeLists.txt deleted file mode 100644 index 7997d6923796dee..000000000000000 --- a/boards/arm/efr32xg24_dk2601b/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2021 Sateesh Kotapati -# SPDX-License-Identifier: Apache-2.0 - -zephyr_library() -zephyr_library_sources(board.c) diff --git a/boards/arm/efr32xg24_dk2601b/sl_device_init_hfxo_config.h b/boards/arm/efr32xg24_dk2601b/sl_device_init_hfxo_config.h deleted file mode 100644 index 7f9e211748ee1a0..000000000000000 --- a/boards/arm/efr32xg24_dk2601b/sl_device_init_hfxo_config.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2023 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef SL_DEVICE_INIT_HFXO_CONFIG_H -#define SL_DEVICE_INIT_HFXO_CONFIG_H - -#define SL_DEVICE_INIT_HFXO_MODE cmuHfxoOscMode_Crystal -#define SL_DEVICE_INIT_HFXO_FREQ 39000000 -#define SL_DEVICE_INIT_HFXO_CTUNE 140 - -#endif /* SL_DEVICE_INIT_HFXO_CONFIG_H */ diff --git a/boards/arm/ev11l78a/ev11l78a_defconfig b/boards/arm/ev11l78a/ev11l78a_defconfig index 51b5780ea701a75..5d9a8a9d651ede4 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/faze/doc/index.rst b/boards/arm/faze/doc/index.rst index ed432753fd7cde1..1d61d997cd08585 100644 --- a/boards/arm/faze/doc/index.rst +++ b/boards/arm/faze/doc/index.rst @@ -31,7 +31,7 @@ Hardware - External devices connected to the NXP LPC11U67 MCU: - ASMedia ASM2364 USB-to-PCIe bridge (I2C master on port O). - - 6 RGB LEDs connected connected to a TI LP5030 LED controller (I2C device on + - 6 RGB LEDs connected to a TI LP5030 LED controller (I2C device on port 1). - 1 white LED (SSD activity blinking). diff --git a/boards/arm/fk7b0m1_vbt6/Kconfig.board b/boards/arm/fk7b0m1_vbt6/Kconfig.board new file mode 100644 index 000000000000000..0b46551e95eae45 --- /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 000000000000000..39de99eb5f8caba --- /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 000000000000000..f709513c7114638 --- /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 000000000000000..68faf96b85951cc 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 000000000000000..5a67a58fcbd3a61 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 000000000000000..2af182bc041428b --- /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 000000000000000..536c7b6e7808a7d --- /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 000000000000000..f847d49f4506b35 --- /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 000000000000000..72587a3a897a8d7 --- /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 000000000000000..ce4f15c9979a8f7 --- /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 6249cc554dfd80d..14d6fe7d021bf4b 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 7804af1056d2db3..e11db24edfcc182 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 a7302350a26d2db..d2fafeb4a0059e1 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 6d9c86a571486c4..acbf22605613c02 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 000000000000000..9dfc07e9b080893 --- /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 5ac35405bdd94e3..70af2305ce8df18 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 5b0e26fb03975fe..a5affc02797a6c3 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 a9e99911776a3ef..b4de8b219e1075c 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 d09e5bcaa37147e..41fd7d9d2101fa4 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 a60a32d01d8a2a4..53eed0cd28b5bee 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 7f7a37db23f18e8..d711b305325cc46 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 333f686f640337a..22261a26e57ce6c 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 925aaf7fafe52ff..d4326c422a228a0 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 2377304c5c193d2..af7cbf8f26eda41 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 72c7cb4abf39848..63cffff2786761e 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.dts b/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.dts new file mode 100644 index 000000000000000..cdc0a933ba373f2 --- /dev/null +++ b/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.dts @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include "fvp_baser_aemv8r_aarch32.dts" 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 new file mode 100644 index 000000000000000..0ecd14f9076d122 --- /dev/null +++ b/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml @@ -0,0 +1,14 @@ +# Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +identifier: fvp_baser_aemv8r_aarch32_smp +name: FVP Emulation FVP_BaseR_AEMv8R AArch32 (SMP) +arch: arm +type: sim +toolchain: + - zephyr + - cross-compile +ram: 2048 +flash: 64 +testing: + timeout_multiplier: 25 diff --git a/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp_defconfig b/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp_defconfig new file mode 100644 index 000000000000000..3f7f981b46e7eb9 --- /dev/null +++ b/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp_defconfig @@ -0,0 +1,32 @@ +# Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_FVP_AEMV8R_AARCH32=y +CONFIG_SOC_FVP_AEMV8R_AARCH32=y +CONFIG_BOARD_FVP_BASER_AEMV8R_AARCH32=y +CONFIG_ARM_MPU=y + +CONFIG_ISR_STACK_SIZE=1024 +CONFIG_THREAD_STACK_INFO=y + +# Enable Timer and Sys clock +CONFIG_SYS_CLOCK_TICKS_PER_SEC=100 +CONFIG_ARM_ARCH_TIMER=y + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable serial port +CONFIG_UART_INTERRUPT_DRIVEN=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +CONFIG_CACHE_MANAGEMENT=y + +CONFIG_USE_SWITCH=y +CONFIG_SMP=y +CONFIG_MP_MAX_NUM_CPUS=4 + +CONFIG_DCACHE=n diff --git a/boards/arm/gd32a503v_eval/doc/index.rst b/boards/arm/gd32a503v_eval/doc/index.rst index 1039faf515fb649..b926a265bb45e14 100644 --- a/boards/arm/gd32a503v_eval/doc/index.rst +++ b/boards/arm/gd32a503v_eval/doc/index.rst @@ -34,7 +34,7 @@ Hardware - CMSIS-DAP swd debug interface over USB HID. -- 2 CAN port(support CAN-FD) +- 2 CAN FD ports For more information about the GD32A503 SoC and GD32A503V-EVAL board: diff --git a/boards/arm/gd32a503v_eval/gd32a503v_eval.dts b/boards/arm/gd32a503v_eval/gd32a503v_eval.dts index f5f79267c16fed4..dc6e0325452bef4 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 396e68d24b6e760..e2e2145d9afb1eb 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/doc/index.rst b/boards/arm/gd32e103v_eval/doc/index.rst index ccf1e9b1e3e4d84..3d9058793fe08c4 100644 --- a/boards/arm/gd32e103v_eval/doc/index.rst +++ b/boards/arm/gd32e103v_eval/doc/index.rst @@ -36,7 +36,7 @@ Hardware - CMSIS-DAP swd debug interface over USB HID. -- 2 CAN port(support CAN-FD) +- 2 CAN FD ports - This function is not available in this board due to hardware issues, please check ``GD32C103`` . diff --git a/boards/arm/gd32e103v_eval/gd32e103v_eval.dts b/boards/arm/gd32e103v_eval/gd32e103v_eval.dts index 1811736fb0417a1..c4aa7403591fbbf 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 4da44f66ff57c55..5c287ed51fef4ef 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 f09658eb7b8633e..000000000000000 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 000000000000000..bad1bd26a4f21c6 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 9e7aef4dcd4a031..c3484d8beec8439 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 6f7140ca17fdd35..9f9be821e410af8 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 528d07470dd3355..000000000000000 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 000000000000000..bfa7112f343e443 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 35971620c176429..8a2317da68e6782 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 c3f721c4beb1a2a..84133e75e4eb057 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 5630f4bbf05ebe8..000000000000000 --- 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 f2ff8bd1efc2c6d..fe96f6832a0374e 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 efa513384017105..000000000000000 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 000000000000000..1badefd1e38826b 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 fd24ffb5d644933..cd67921e59e3890 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 f8df275d8301cc6..1b36e5cfdbd990d 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 ec5800eae978d75..000000000000000 --- 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 032905d9842a827..000000000000000 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 000000000000000..2721d8bffbd31b7 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 56017e4aef52bb0..59e9d258975cbdd 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 01dd5ff86de2644..4e2f87c4015b81d 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 f2b3f48fbcab2cb..000000000000000 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 000000000000000..f76c58206b30c0c 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 d3166c8ab640437..e45f05a58a65c4e 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 803ff1a97097b8e..20500889670694b 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 7fca77536466f79..000000000000000 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 000000000000000..be33bd01263e67e 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 179886cd0db4c16..0e31f262db3c6e9 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 b40cbb54c793faa..c636a5647c7d052 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 792533b63ac0fbf..306d190b3d4a86d 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 868e4907f3f3906..9537f9aef301564 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 31348d149205503..5ee22563bd06621 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 ff8dadacfa45007..579adf4026f35d9 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 255e1df3942477e..a776221cc32f897 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/CMakeLists.txt b/boards/arm/ip_k66f/CMakeLists.txt index 9881313609aae2c..2fab2b7dc868b3f 100644 --- a/boards/arm/ip_k66f/CMakeLists.txt +++ b/boards/arm/ip_k66f/CMakeLists.txt @@ -1 +1,3 @@ # SPDX-License-Identifier: Apache-2.0 + +set(BOARD_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "Board linker script, ${BOARD}") diff --git a/boards/arm/ip_k66f/ip_k66f-pinctrl.dtsi b/boards/arm/ip_k66f/ip_k66f-pinctrl.dtsi index 86e0e71a4caf040..30ccd75c81a3119 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 268573de547c5c2..02602825712fbea 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 000000000000000..1b4e30a54c4fa37 --- /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 000000000000000..ca35c4321a09796 --- /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 000000000000000..ac24f811559b67d --- /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 000000000000000..8b22ba96ea6b636 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 000000000000000..2cc0f5e17eb3f2c 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 000000000000000..6e6be186dd773e1 --- /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 000000000000000..e65572c6e35066b --- /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 000000000000000..144ee2275ad366b --- /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 000000000000000..5e6649fe25ac060 --- /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 000000000000000..f4902698c6358b3 --- /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/doc/index.rst b/boards/arm/lpcxpresso11u68/doc/index.rst index 75a4b7f15a5aa1b..23198a359eaa9af 100644 --- a/boards/arm/lpcxpresso11u68/doc/index.rst +++ b/boards/arm/lpcxpresso11u68/doc/index.rst @@ -107,7 +107,7 @@ Flashing The LPCXpresso11U68 board can be flashed by using the on-board LPC-Link2 debug probe (based on a NXP LPC43xx MCU). This MCU provides either a CMSIS-DAP or a J-Link interface. It depends on the embedded firmware image. The default -OpenOCD configuration supports the the CMSIS-DAP interface. If you want to +OpenOCD configuration supports the CMSIS-DAP interface. If you want to switch to J-Link, then you need to edit the ``boards/arm/lpcxpresso11u68/support/openocd.cfg`` file and to replace:: diff --git a/boards/arm/lpcxpresso11u68/lpcxpresso11u68.yaml b/boards/arm/lpcxpresso11u68/lpcxpresso11u68.yaml index e59360c084b1401..192ca797f629054 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 a99ee0b6018d3e5..da944a569f5c62b 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 7647f98ad44d970..b648cd94c4fd39f 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 57d53c1489ac6c4..48340c5f589f4c4 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 32f7be75b332e26..a6df50bba733395 100644 --- a/boards/arm/lpcxpresso55s06/board.cmake +++ b/boards/arm/lpcxpresso55s06/board.cmake @@ -1,9 +1,12 @@ # # Copyright (c) 2022 metraTec +# Copyright 2023 NXP # # SPDX-License-Identifier: Apache-2.0 # +board_runner_args(linkserver "--device=LPC55S06:LPCXpresso55S06") board_runner_args(jlink "--device=LPC55S06" "--reset-after-load") 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 3f4ed27b488e2f6..a6be7665a10cfc0 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/lpcxpresso55s06/lpcxpresso55s06_common.dtsi b/boards/arm/lpcxpresso55s06/lpcxpresso55s06_common.dtsi index 03633b468dc57e2..aa2373b829ccf86 100644 --- a/boards/arm/lpcxpresso55s06/lpcxpresso55s06_common.dtsi +++ b/boards/arm/lpcxpresso55s06/lpcxpresso55s06_common.dtsi @@ -1,6 +1,6 @@ /* * Copyright (c) 2022 metraTec - * Copyright 2022 NXP + * Copyright 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,12 +12,11 @@ chosen { zephyr,sram = &sram0; zephyr,flash = &flash0; - zephyr,code-partition = &sramx; + zephyr,code-partition = &slot0_partition; zephyr,console = &flexcomm0; zephyr,shell-uart = &flexcomm0; zephyr,entropy = &rng; zephyr,flash-controller = &iap; - zephyr,code-partition = &slot0_partition; zephyr,canbus = &can0; }; @@ -118,23 +117,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(196)>; + reg = <0x00008000 DT_SIZE_K(96)>; + }; + slot1_partition: partition@20000 { + label = "image-1"; + reg = <0x00020000 DT_SIZE_K(96)>; }; - storage_partition: partition@30000 { + storage_partition: partition@38000 { label = "storage"; - reg = <0x00030000 DT_SIZE_K(64)>; + reg = <0x00038000 DT_SIZE_K(20)>; }; + /* The last 12KB are reserved for PFR on the 256KB flash. */ }; }; diff --git a/boards/arm/lpcxpresso55s06/lpcxpresso55s06_defconfig b/boards/arm/lpcxpresso55s06/lpcxpresso55s06_defconfig index b239a73b8c0c493..a743b67e2fd32e9 100644 --- a/boards/arm/lpcxpresso55s06/lpcxpresso55s06_defconfig +++ b/boards/arm/lpcxpresso55s06/lpcxpresso55s06_defconfig @@ -13,7 +13,6 @@ CONFIG_SERIAL=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_GPIO=y CONFIG_PINCTRL=y -CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=96000000 CONFIG_ARM_MPU=y CONFIG_RUNTIME_NMI=y diff --git a/boards/arm/lpcxpresso55s16/Kconfig.defconfig b/boards/arm/lpcxpresso55s16/Kconfig.defconfig index 49ed6830ed2e6c4..2979ac8808d73f6 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 7daaf7d25c108ff..f1a6370b01fe55e 100644 --- a/boards/arm/lpcxpresso55s16/board.cmake +++ b/boards/arm/lpcxpresso55s16/board.cmake @@ -1,9 +1,14 @@ # # Copyright (c) 2020 Henrik Brix Andersen +# Copyright 2023 NXP # # SPDX-License-Identifier: Apache-2.0 # +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/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/doc/index.rst b/boards/arm/lpcxpresso55s16/doc/index.rst index abb9170543efc1c..9c25ac8898e8043 100644 --- a/boards/arm/lpcxpresso55s16/doc/index.rst +++ b/boards/arm/lpcxpresso55s16/doc/index.rst @@ -139,7 +139,7 @@ System Clock ============ The LPC55S16 SoC is configured to use PLL1 clocked from the external 24MHz -crystal, running at 150MHz as a source for the system clock. When the flash +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 always set to 96MHz when flash programming operations are performed. diff --git a/boards/arm/lpcxpresso55s16/lpcxpresso55s16-pinctrl.dtsi b/boards/arm/lpcxpresso55s16/lpcxpresso55s16-pinctrl.dtsi index c0b2c76c5400259..5da724505236258 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/lpcxpresso55s16/lpcxpresso55s16_common.dtsi b/boards/arm/lpcxpresso55s16/lpcxpresso55s16_common.dtsi index b1e152e74c965bb..1b68d976f3e8a2f 100644 --- a/boards/arm/lpcxpresso55s16/lpcxpresso55s16_common.dtsi +++ b/boards/arm/lpcxpresso55s16/lpcxpresso55s16_common.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 Henrik Brix Andersen + * Copyright 2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,11 +12,12 @@ chosen { zephyr,sram = &sram0; zephyr,flash = &flash0; - zephyr,code-partition = &sramx; + zephyr,code-partition = &slot0_partition; zephyr,console = &flexcomm0; zephyr,shell-uart = &flexcomm0; zephyr,entropy = &rng; zephyr,canbus = &can0; + zephyr,flash-controller = &iap; }; aliases{ @@ -162,23 +164,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(196)>; + reg = <0x00008000 DT_SIZE_K(96)>; + }; + slot1_partition: partition@20000 { + label = "image-1"; + reg = <0x00020000 DT_SIZE_K(96)>; }; - storage_partition: partition@30000 { + storage_partition: partition@38000 { label = "storage"; - reg = <0x00030000 DT_SIZE_K(64)>; + reg = <0x00038000 DT_SIZE_K(20)>; }; + /* The last 12KB are reserved for PFR on the 256KB flash. */ }; }; diff --git a/boards/arm/lpcxpresso55s16/lpcxpresso55s16_defconfig b/boards/arm/lpcxpresso55s16/lpcxpresso55s16_defconfig index 1c7617436cee705..44af7c468e1e2bf 100644 --- a/boards/arm/lpcxpresso55s16/lpcxpresso55s16_defconfig +++ b/boards/arm/lpcxpresso55s16/lpcxpresso55s16_defconfig @@ -13,7 +13,6 @@ CONFIG_SERIAL=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_GPIO=y CONFIG_PINCTRL=y -CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=96000000 CONFIG_ARM_MPU=y CONFIG_RUNTIME_NMI=y diff --git a/boards/arm/lpcxpresso55s28/Kconfig.defconfig b/boards/arm/lpcxpresso55s28/Kconfig.defconfig index 40e95c1b388f84e..ee3fd9685c41e1a 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 9cd2296a40437d8..933e3815a8c9281 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/doc/index.rst b/boards/arm/lpcxpresso55s28/doc/index.rst index e624a1151365caa..7750254d4235419 100644 --- a/boards/arm/lpcxpresso55s28/doc/index.rst +++ b/boards/arm/lpcxpresso55s28/doc/index.rst @@ -126,7 +126,7 @@ System Clock ============ The LPC55S28 SoC is configured to use PLL1 clocked from the external 24MHz -crystal, running at 150MHz as a source for the system clock. When the flash +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 always set to 96MHz when flash programming operations are performed. diff --git a/boards/arm/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi b/boards/arm/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi index a8955d2a0340d87..dbf467f3c166a2c 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 7f311be98db5b8f..a71ffb151570200 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/lpcxpresso55s28/lpcxpresso55s28_defconfig b/boards/arm/lpcxpresso55s28/lpcxpresso55s28_defconfig index d99a3d01c55994f..8ce8f718d7e5272 100644 --- a/boards/arm/lpcxpresso55s28/lpcxpresso55s28_defconfig +++ b/boards/arm/lpcxpresso55s28/lpcxpresso55s28_defconfig @@ -13,7 +13,6 @@ CONFIG_SERIAL=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_GPIO=y CONFIG_PINCTRL=y -CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=96000000 CONFIG_ARM_MPU=y CONFIG_HW_STACK_PROTECTION=y diff --git a/boards/arm/lpcxpresso55s36/Kconfig.defconfig b/boards/arm/lpcxpresso55s36/Kconfig.defconfig index 3f3b1305bf79686..fd3ea5cd189ea19 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 2aceb6ca675c531..d1a92d0164d0ef2 100644 --- a/boards/arm/lpcxpresso55s36/board.cmake +++ b/boards/arm/lpcxpresso55s36/board.cmake @@ -1,11 +1,13 @@ # -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # # SPDX-License-Identifier: Apache-2.0 # +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/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/doc/index.rst b/boards/arm/lpcxpresso55s36/doc/index.rst index e35e285ff6cf77b..a8914f20154ed4f 100644 --- a/boards/arm/lpcxpresso55s36/doc/index.rst +++ b/boards/arm/lpcxpresso55s36/doc/index.rst @@ -147,8 +147,9 @@ the functionality of a pin. System Clock ============ -The LPC55S36 SoC is configured to use the internal FRO at 96MHz as a -source for the system clock. Other sources for the system clock are +The LPC55S36 SoC is configured to use PLL1 clocked from the external 24MHz +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. Other sources for the system clock are provided in the SOC, depending on your system requirements. Serial Port diff --git a/boards/arm/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi b/boards/arm/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi index 8ca6f659f2e9e83..619b275b5937e7c 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/lpcxpresso55s36/lpcxpresso55s36.dts b/boards/arm/lpcxpresso55s36/lpcxpresso55s36.dts index 3b51a1602f2c310..be2b16c27f75037 100644 --- a/boards/arm/lpcxpresso55s36/lpcxpresso55s36.dts +++ b/boards/arm/lpcxpresso55s36/lpcxpresso55s36.dts @@ -17,7 +17,7 @@ chosen { zephyr,sram = &sram0; zephyr,flash = &flash0; - zephyr,code-partition = &sramx; + zephyr,code-partition = &slot0_partition; zephyr,console = &flexcomm0; zephyr,shell-uart = &flexcomm0; zephyr,canbus = &can0; @@ -143,20 +143,33 @@ pinctrl-names = "default"; }; +/* Flash is divided into 32 kB sub-regions. + * Each sub-region can be assigned individual + * security tier in secure AHB controller. + */ &flash0 { partitions { compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; - slot0_partition: partition@0 { - label = "executable"; - reg = <0x00000000 DT_SIZE_K(182)>; - }; - - storage_partition: partition@88000 { + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x0 DT_SIZE_K(32)>; + }; + slot0_partition: partition@8000 { + label = "image-0"; + reg = <0x00008000 DT_SIZE_K(96)>; + }; + slot1_partition: partition@20000 { + label = "image-1"; + reg = <0x00020000 DT_SIZE_K(96)>; + }; + storage_partition: partition@38000 { label = "storage"; - reg = <0x0002d800 DT_SIZE_K(64)>; + reg = <0x00038000 DT_SIZE_K(20)>; }; + /* The last 12KB are reserved for PFR on the 256KB flash. + */ }; }; diff --git a/boards/arm/lpcxpresso55s36/lpcxpresso55s36_defconfig b/boards/arm/lpcxpresso55s36/lpcxpresso55s36_defconfig index 40c1b5fec75a62d..4bf154138aff65a 100644 --- a/boards/arm/lpcxpresso55s36/lpcxpresso55s36_defconfig +++ b/boards/arm/lpcxpresso55s36/lpcxpresso55s36_defconfig @@ -13,7 +13,6 @@ CONFIG_SERIAL=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_GPIO=y CONFIG_PINCTRL=y -CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=96000000 CONFIG_ARM_MPU=y CONFIG_RUNTIME_NMI=y diff --git a/boards/arm/lpcxpresso55s69/Kconfig.defconfig b/boards/arm/lpcxpresso55s69/Kconfig.defconfig index 7c98507e35c38f2..c8bc5421e098feb 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 21ed8e82672c051..ed9aedf4f4e4c62 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 d6ec337ae9ea7f8..d6c16095f5380fc 100644 --- a/boards/arm/lpcxpresso55s69/doc/index.rst +++ b/boards/arm/lpcxpresso55s69/doc/index.rst @@ -191,21 +191,21 @@ Memory mappings There are multiple memory configurations, they all start from the MCUboot partitioning which looks like the table below -+---------+------------------+---------------------------------+ -| Name | Address[Size] | Comment | -+=========+==================+=================================+ -| boot | 0x00000000[32K] | Bootloader | -+---------+------------------+---------------------------------+ -| slot0 | 0x00008000[160k] | Image that runs after boot | -+---------+------------------+---------------------------------+ -| slot1 | 0x00030000[96k] | Second image, core 1 or NS | -+---------+------------------+---------------------------------+ -| slot2 | 0x00048000[160k] | Updates slot0 image | -+---------+------------------+---------------------------------+ -| slot3 | 0x00070000[96k] | Updates slot1 image | -+---------+------------------+---------------------------------+ -| storage | 0x00088000[50k] | File system, persistent storage | -+---------+------------------+---------------------------------+ ++----------+------------------+---------------------------------+ +| Name | Address[Size] | Comment | ++==========+==================+=================================+ +| boot | 0x00000000[32K] | Bootloader | ++----------+------------------+---------------------------------+ +| slot0 | 0x00008000[160k] | Image that runs after boot | ++----------+------------------+---------------------------------+ +| slot0_ns | 0x00030000[96k] | Second image, core 1 or NS | ++----------+------------------+---------------------------------+ +| slot1 | 0x00048000[160k] | Updates slot0 image | ++----------+------------------+---------------------------------+ +| slot1_ns | 0x00070000[96k] | Updates slot0_ns image | ++----------+------------------+---------------------------------+ +| storage | 0x00088000[50k] | File system, persistent storage | ++----------+------------------+---------------------------------+ See below examples of how this partitioning is used @@ -256,8 +256,8 @@ Dual Core samples System Clock ============ -The LPC55S69 SoC is configured to use PLL1 clocked from the external 24MHz -crystal, running at 150MHz as a source for the system clock. When the flash +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 always set to 96MHz when flash programming operations are performed. diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi b/boards/arm/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi index 5842f1f7eb2aa92..9699793638854d3 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/lpcxpresso55s69/lpcxpresso55s69.dtsi b/boards/arm/lpcxpresso55s69/lpcxpresso55s69.dtsi index 11b3263c3aa9559..e3d5b08fa19ebae 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69.dtsi +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69.dtsi @@ -117,28 +117,27 @@ compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; - /* Please enable mcuboot's swap move, no scratch */ boot_partition: partition@0 { label = "mcuboot"; - reg = <0x00000000 0x00008000>; + reg = <0x00000000 DT_SIZE_K(32)>; read-only; }; slot0_partition: partition@8000 { label = "image-0"; - reg = <0x00008000 0x00028000>; + reg = <0x00008000 DT_SIZE_K(160)>; }; - slot1_partition: partition@30000 { - label = "image-1"; - reg = <0x00030000 0x00018000>; + slot0_ns_partition: partition@30000 { + label = "image-0-nonsecure"; + reg = <0x00030000 DT_SIZE_K(96)>; }; - slot2_partition: partition@48000 { - label = "image-2"; - reg = <0x00048000 0x00028000>; + slot1_partition: partition@48000 { + label = "image-1"; + reg = <0x00048000 DT_SIZE_K(160)>; }; - slot3_partition: partition@70000 { - label = "image-3"; - reg = <0x00070000 0x00018000>; + slot1_ns_partition: partition@70000 { + label = "image-1-nonsecure"; + reg = <0x00070000 DT_SIZE_K(96)>; }; /* * The flash starting at 0x88000 and ending at @@ -146,7 +145,7 @@ */ storage_partition: partition@88000 { label = "storage"; - reg = <0x00088000 0x0000ca00>; + reg = <0x00088000 DT_SIZE_K(50)>; }; }; }; diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts index 050d625013f858e..14ba04fa448deab 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts @@ -37,7 +37,7 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; - zephyr,code-cpu1-partition = &slot1_partition; + zephyr,code-cpu1-partition = &slot0_ns_partition; zephyr,sram-cpu1-partition = &sram3; zephyr,console = &flexcomm0; zephyr,shell-uart = &flexcomm0; @@ -204,3 +204,7 @@ i2s1: &flexcomm7 { &dma1 { status = "okay"; }; + +&mrt_channel0 { + status = "okay"; +}; diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0_defconfig b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0_defconfig index f6bfb945eec7643..ece94dd0b6f57b3 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0_defconfig +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0_defconfig @@ -12,7 +12,6 @@ CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_GPIO=y -CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=96000000 CONFIG_ARM_MPU=y CONFIG_HW_STACK_PROTECTION=y CONFIG_PINCTRL=y diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu1.dts b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu1.dts index 1c3f11882a04581..9ade525bc375dc7 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu1.dts +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu1.dts @@ -20,7 +20,7 @@ chosen { zephyr,sram = &sram3; zephyr,flash = &flash0; - zephyr,code-partition = &slot1_partition; + zephyr,code-partition = &slot0_ns_partition; zephyr,entropy = &rng; }; }; diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu1_defconfig b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu1_defconfig index 63d748062212b0a..d93ccd893299780 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu1_defconfig +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu1_defconfig @@ -8,7 +8,6 @@ CONFIG_SOC_SERIES_LPC55XXX=y CONFIG_SOC_LPC55S69_CPU1=y CONFIG_BOARD_LPCXPRESSO55S69_CPU1=y CONFIG_GPIO=y -CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=96000000 CONFIG_PINCTRL=y CONFIG_RUNTIME_NMI=y diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_ns.dts b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_ns.dts index 0491958f9e0486e..cc2e41e08152b12 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_ns.dts +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_ns.dts @@ -29,7 +29,7 @@ chosen { zephyr,sram = &non_secure_ram; zephyr,flash = &flash0; - zephyr,code-partition = &slot1_partition; + zephyr,code-partition = &slot0_ns_partition; zephyr,console = &flexcomm0; zephyr,shell-uart = &flexcomm0; zephyr,entropy = &rng; diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_ns_defconfig b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_ns_defconfig index a82f0241fed80bf..451a92a74a68555 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_ns_defconfig +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_ns_defconfig @@ -12,7 +12,6 @@ CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_GPIO=y -CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=96000000 CONFIG_PINCTRL=y # TFM sets up MPU_NS, can't correctly change this configuration yet diff --git a/boards/arm/mercury_xu/board.c b/boards/arm/mercury_xu/board.c index 8204b29ae905ab1..db436299a9c40f2 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 000000000000000..3bc31ad3c746728 --- /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 c58e48e31f9c2e3..df51ab470c579ed 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 6655cf9a44290c7..d01d7082f946de0 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 1bbaa146dd6eafa..67f4b3677a5fcac 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_clicker_2/mikroe_clicker_2_defconfig b/boards/arm/mikroe_clicker_2/mikroe_clicker_2_defconfig index 0d46fd7c84e6543..15ade5bcf58a3cd 100644 --- a/boards/arm/mikroe_clicker_2/mikroe_clicker_2_defconfig +++ b/boards/arm/mikroe_clicker_2/mikroe_clicker_2_defconfig @@ -9,6 +9,7 @@ CONFIG_SERIAL=y # console CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y # enable GPIO CONFIG_GPIO=y 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 60f270855a71597..e9d3b46d3b4584e 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 c345742bc7e7fa9..c7b1943810eb03e 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 8854d16ac551719..4c1779778ba7998 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 ee0fd50bf5feb15..399336291f933ea 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 f9ca5de1ff2be40..a690f201ba15635 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 62e3944f73c216b..c29fdcc7d286b8d 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 580b8cef0f38b17..f5fee9cea2fc9dc 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 65b31812349f021..9d190081e320a28 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 71f755bacdebd07..330de94d692779b 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 302b3c64d80d41f..e611af6c798531d 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 be9b7ba10e12d8c..442bf1b43e259cb 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 d3e44a5b04086fb..f7d6bc1db6efa8d 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 412eeeb0e4c67ae..b77d1ee424e925e 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 a3df588c9af8412..0a28acc04ca401b 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 f3c9ac623ed95ff..cfab4278fb4bf35 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 40f45565a6ed1be..751ec16687b5fda 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 8da66d34084d9f3..9fe3a42bf9f38f1 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 4f8d3b803c6fe82..e873a0f21675a05 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 704743ded71b8e1..db0a2eb1fedc903 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 303dad375386432..c04a3f5d09050ae 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 000000000000000..2229b2a9b70efa8 --- /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 3e27286cc234a5e..1090e3943815611 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 164e7cdb6540f7a..7377cd0f1d8dc6e 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 54d459f5c0825c6..10e09bc14052662 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 f5ca4ed99cdacc6..651a0aebff9a351 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 2ddc0771bb0daea..ad26eeecc3fdc36 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 6e9a9c4c2bbd8b6..5beae5ffc40b863 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 104c6d7710012b9..79660c08e781c92 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 e7a3230af941310..265ce1cd5f8d5f9 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 3081e162138d559..de225ae56f330c2 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. @@ -436,9 +451,9 @@ Board Revisions *************** The original MIMXRT1050-EVK (rev A0) board was updated with a newer -MIMXRT1050-EVKB (rev A1) board, with these major hardware differences:: +MIMXRT1050-EVKB (rev A1) board, with these major hardware differences: -- SoC changed from MIMXRT1052DVL6**A** to MIMXRT1052DVL6**B** +- SoC changed from MIMXRT1052DVL6\ **A** to MIMXRT1052DVL6\ **B** - Hardware bug fixes for: power, interfaces, and memory - Arduino headers included @@ -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 000000000000000..7fe69f0d52ed019 --- /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 27e48b64ae8fcdc..1b73a7453a96cf3 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 5068bc674e457f0..d1e8da5834b7958 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 46f78275a0ce607..27542b88bfd0d80 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 aef6f37c03b01c9..b3b325805fa6eab 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 838deeb477d788f..cfd546e5b37c692 100644 --- a/boards/arm/mimxrt1060_evk/doc/index.rst +++ b/boards/arm/mimxrt1060_evk/doc/index.rst @@ -11,7 +11,7 @@ processor series and expands the i.MX RT series to three scalable families. The i.MX RT1060 doubles the On-Chip SRAM to 1MB while keeping pin-to-pin compatibility with i.MX RT1050. This series introduces additional features -ideal for real-time applications such as High-Speed GPIO, CAN-FD, and +ideal for real-time applications such as High-Speed GPIO, CAN FD, and synchronous parallel NAND/NOR/PSRAM controller. The i.MX RT1060 runs on the Arm® Cortex-M7® core up to 600 MHz. @@ -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 000000000000000..7fe69f0d52ed019 --- /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 7d2ff7a43e4794e..f41f92ba1ee3303 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 998e942e5a23c10..42782b4045401f2 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 a920010688bd2be..efdf5e2ff229dbd 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/doc/index.rst b/boards/arm/mimxrt1062_fmurt6/doc/index.rst index e1b7f284cc099e8..2c801c454af46db 100644 --- a/boards/arm/mimxrt1062_fmurt6/doc/index.rst +++ b/boards/arm/mimxrt1062_fmurt6/doc/index.rst @@ -11,7 +11,7 @@ processor series and expands the i.MX RT series to three scalable families. The i.MX RT1062 doubles the On-Chip SRAM to 1MB while keeping pin-to-pin compatibility with i.MX RT1050. This series introduces additional features -ideal for real-time applications such as High-Speed GPIO, CAN-FD, and +ideal for real-time applications such as High-Speed GPIO, CAN FD, and synchronous parallel NAND/NOR/PSRAM controller. The i.MX RT1062 runs on the Arm® Cortex-M7® core up to 600 MHz. diff --git a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts index c3af13f1f0dd084..ff6f1bf68278a77 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 9ebf3eaa71b8991..e0604d396210127 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/doc/index.rst b/boards/arm/mimxrt1064_evk/doc/index.rst index 462fe7629b3e29a..24abf5ca76f57b7 100644 --- a/boards/arm/mimxrt1064_evk/doc/index.rst +++ b/boards/arm/mimxrt1064_evk/doc/index.rst @@ -10,7 +10,7 @@ The i.MX RT1064 adds to the industry's first crossover processor series and expands the i.MX RT series to three scalable families. The i.MX RT1064 doubles the On-Chip SRAM to 1MB while keeping pin-to-pin compatibility with i.MX RT1050. This series introduces additional features -ideal for real-time applications such as High-Speed GPIO, CAN-FD, and +ideal for real-time applications such as High-Speed GPIO, CAN FD, and synchronous parallel NAND/NOR/PSRAM controller. The i.MX RT1064 runs on the Arm® Cortex-M7® core up to 600 MHz. 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 000000000000000..7fe69f0d52ed019 --- /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 043b421dcfb22db..d8be3020998de79 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 ebd88badcb6b519..f6b6d5c74b26278 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 d3ee99ad7310bfa..2449429a891e883 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 000000000000000..58b8a8016227a0d --- /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 f2a3c4ff9dd040c..1f17d8d62de0fdc 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 02d09138e750bcd..93e1c3452fa2661 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 1582861ffc9bb31..faff1975ca81e4d 100644 --- a/boards/arm/mimxrt1170_evk/doc/index.rst +++ b/boards/arm/mimxrt1170_evk/doc/index.rst @@ -349,6 +349,11 @@ Use the ``-r linkserver`` option with West to use the LinkServer runner. west flash -r linkserver +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. Configuring a Console ===================== @@ -437,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 000000000000000..58b8a8016227a0d --- /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 41a5607e7287875..35e7c521532495d 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 4d3b193e5dc155c..9e59e733ebcfb03 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 5700b77837c9f95..79725d1ac352295 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 e93f701cd875bcd..feceb9eaa30dfbe 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 51294dec28896bb..002c69765453c5c 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 3a4580a3603e02f..96779115e141cf7 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 fce50f4c23d4225..dd2cb36354c166b 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 000000000000000..f30095651f918d4 --- /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 61ed427858a101a..8bdbd864a4e0861 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: @@ -174,6 +176,20 @@ Serial Port The MIMXRT595 SoC has 13 FLEXCOMM interfaces for serial communication. One is configured as USART for the console and the remaining are not used. +Fusion F1 DSP Core +================== + +You can build a Zephyr application for the RT500 DSP core using nxp_adsp_rt595 +board. Xtensa toolchain supporting RT500 DSP core is included in Zephyr SDK. +To build the hello_world sample for the RT500 DSP core: + +.. code-block:: shell + + $ west build -b nxp_adsp_rt595 samples/hello_world + +For detailed instructions on how to debug DSP firmware, please refer to +this document: `Getting Started with Xplorer for EVK-MIMXRT595`_ + Programming and Debugging ************************* @@ -313,3 +329,6 @@ steps: .. _i.MX RT595 Reference Manual: https://www.nxp.com/webapp/Download?colCode=IMXRT500RM + +.. _Getting Started with Xplorer for EVK-MIMXRT595: + https://www.nxp.com/docs/en/supporting-information/GSXEVKMIMXRT595.pdf diff --git a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi index 4073475446b38c0..3f1bb622689c09a 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 49dd4f424be44bc..f32420304df7f2f 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>; }; }; }; @@ -478,3 +482,31 @@ zephyr_udc0: &usbhs { dmas = <&smartdma>; 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 6e35595c078ff47..95b17cb059fd901 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 a399d5f6398e230..79e6f768dd1d097 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 f0236e3a64f4e66..579cd1e4087d112 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 ef48a752ef5cc80..63febf90fce1f31 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 f16de683d36b0fc..4a8c410bce9afe9 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 1a385a3babc2278..1a9b44a01c0af51 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 1f9d1a59e23827d..ac27e70e5938193 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 fec9dfc0fa845c2..0236f2a137d2bcc 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 806f4ac70526fe1..51e09ba282d638d 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 1cd049ec8f96e29..e8789e72e18d501 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 d69228b235a5cef..2bb956645cafae0 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 80e235244a1214d..e2b24cd9ba571a2 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 a52b88ff4477b7b..311694ca399977a 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 002c4210f5266fa..b5f383d546a07ce 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 53168a4de2d6aef..50700e8278e02ce 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 ac6531441ebeff2..dd8c9c4571c856a 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.board b/boards/arm/mr_canhubk3/Kconfig.board index 3cea453a2a29c4f..af9a09391cd7380 100644 --- a/boards/arm/mr_canhubk3/Kconfig.board +++ b/boards/arm/mr_canhubk3/Kconfig.board @@ -3,5 +3,5 @@ config BOARD_MR_CANHUBK3 bool "mr_canhubk3" - depends on SOC_SERIES_S32K3_M7 - select SOC_PART_NUMBER_S32K344 + depends on SOC_SERIES_S32K3XX + select SOC_PART_NUMBER_PS32K344EHVPBS diff --git a/boards/arm/mr_canhubk3/Kconfig.defconfig b/boards/arm/mr_canhubk3/Kconfig.defconfig index 6cf6f085492710f..53e554da88f8b48 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 63dbb36666b67c5..711ee43a0ca5463 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 1c3ff008508c2ff..e057aeb1ef653f3 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi +++ b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi @@ -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 ec5eb1ece43f86d..97bca1402b421d6 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 { @@ -409,10 +444,18 @@ phy-connection-type = "rmii"; local-mac-address = [02 04 9f aa bb cc]; 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>; + master-slave = "slave"; }; }; @@ -493,24 +536,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 +593,14 @@ }; }; +&lcu1 { + status = "okay"; +}; + +&trgmux { + status = "okay"; +}; + &edma0 { status = "okay"; }; diff --git a/boards/arm/mr_canhubk3/mr_canhubk3_defconfig b/boards/arm/mr_canhubk3/mr_canhubk3_defconfig index 68613d22f111d56..d8182ce8327bb62 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3_defconfig +++ b/boards/arm/mr_canhubk3/mr_canhubk3_defconfig @@ -2,8 +2,8 @@ # SPDX-License-Identifier: Apache-2.0 CONFIG_BOARD_MR_CANHUBK3=y -CONFIG_SOC_S32K344_M7=y -CONFIG_SOC_SERIES_S32K3_M7=y +CONFIG_SOC_S32K344=y +CONFIG_SOC_SERIES_S32K3XX=y CONFIG_BUILD_OUTPUT_HEX=y # Use Systick as system clock diff --git a/boards/arm/msp_exp432p401r_launchxl/doc/index.rst b/boards/arm/msp_exp432p401r_launchxl/doc/index.rst index 462aeb04de0dc29..d2a2e12153a6ab2 100644 --- a/boards/arm/msp_exp432p401r_launchxl/doc/index.rst +++ b/boards/arm/msp_exp432p401r_launchxl/doc/index.rst @@ -88,7 +88,7 @@ Prerequisites: to the paths of the OpenOCD binary and its scripts, before including the common openocd.board.cmake file: - .. code-block:: none + .. code-block:: cmake set(OPENOCD "/usr/local/bin/openocd" CACHE FILEPATH "" FORCE) set(OPENOCD_DEFAULT_PATH /usr/local/share/openocd/scripts) diff --git a/boards/arm/nrf52840_mdk/doc/index.rst b/boards/arm/nrf52840_mdk/doc/index.rst index fce05bee59371db..6e0b24b65f2b4b3 100644 --- a/boards/arm/nrf52840_mdk/doc/index.rst +++ b/boards/arm/nrf52840_mdk/doc/index.rst @@ -7,7 +7,7 @@ Overview ******** The nRF52840-MDK is a versatile, easy-to-use IoT hardware platform for -Bluetooth 5, Bluetooth mesh, Thread, IEEE 802.15.4, ANT and 2.4GHz proprietary +Bluetooth 5, Bluetooth Mesh, Thread, IEEE 802.15.4, ANT and 2.4GHz proprietary applications using the nRF52840 SoC. The development kit comes with a fully integrated debugger (also known as diff --git a/boards/arm/nrf52840_mdk_usb_dongle/nrf52840_mdk_usb_dongle_defconfig b/boards/arm/nrf52840_mdk_usb_dongle/nrf52840_mdk_usb_dongle_defconfig index c76e57e17a9f23c..63decf69707d836 100644 --- a/boards/arm/nrf52840_mdk_usb_dongle/nrf52840_mdk_usb_dongle_defconfig +++ b/boards/arm/nrf52840_mdk_usb_dongle/nrf52840_mdk_usb_dongle_defconfig @@ -7,6 +7,11 @@ CONFIG_BOARD_NRF52840_MDK_USB_DONGLE=y # Enable MPU CONFIG_ARM_MPU=y +# Console +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y + # Enable hardware stack protection CONFIG_HW_STACK_PROTECTION=y diff --git a/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts b/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts index 96006ec4722aa69..60c3ecf55a127af 100644 --- a/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts +++ b/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts @@ -149,10 +149,18 @@ &gpio0 { status = "okay"; + gpio-reserved-ranges = <0 2>, <6 1>, <8 3>, <17 7>; + gpio-line-names = "XL1", "XL2", "AREF", "A0", "A1", "RTS", "TXD", + "CTS", "RXD", "NFC1", "NFC2", "BUTTON1", "BUTTON2", "LED1", + "LED2", "LED3", "LED4", "QSPI CS", "RESET", "QSPI CLK", + "QSPI DIO0", "QSPI DIO1", "QSPI DIO2", "QSPI DIO3","BUTTON3", + "BUTTON4", "SDA", "SCL", "A2", "A3", "A4", "A5"; }; &gpio1 { status = "okay"; + gpio-line-names = "", "D0", "D1", "D2", "D3", "D4", "D5", "D6", + "D7", "", "D8", "D9", "D10", "D11", "D12", "D13"; }; &uart0 { diff --git a/boards/arm/nrf52840dongle_nrf52840/Kconfig.defconfig b/boards/arm/nrf52840dongle_nrf52840/Kconfig.defconfig index 75a76b332937498..76c7559be8d7622 100644 --- a/boards/arm/nrf52840dongle_nrf52840/Kconfig.defconfig +++ b/boards/arm/nrf52840dongle_nrf52840/Kconfig.defconfig @@ -33,6 +33,9 @@ config USB_DEVICE_STACK config USB_CDC_ACM default SERIAL +config CONSOLE + default y + config UART_CONSOLE default CONSOLE diff --git a/boards/arm/nrf5340_audio_dk_nrf5340/CMakeLists.txt b/boards/arm/nrf5340_audio_dk_nrf5340/CMakeLists.txt index c950fd9172466d4..fa1c1ba14d93254 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 b/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig index fc237786896776c..00e48c605429f14 100644 --- a/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig +++ b/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig @@ -43,7 +43,7 @@ config DOMAIN_CPUNET_BOARD 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_rpmsg on the nRF5340_cpunet for + another board. For example hci_ipc on the nRF5340_cpunet for Bluetooth applications. endif # BOARD_NRF5340_AUDIO_DK_NRF5340_CPUAPP || BOARD_NRF5340_AUDIO_DK_NRF5340_CPUAPP_NS diff --git a/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig.defconfig b/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig.defconfig index 87a9a2175a8780f..685ebc49b63a4c6 100644 --- a/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig.defconfig +++ b/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig.defconfig @@ -70,11 +70,12 @@ config MBOX_NRFX_IPC if BOARD_NRF5340_AUDIO_DK_NRF5340_CPUAPP || BOARD_NRF5340_AUDIO_DK_NRF5340_CPUAPP_NS choice BT_HCI_BUS_TYPE - default BT_RPMSG if BT + default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE - default 4096 if BT_RPMSG +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/doc/index.rst b/boards/arm/nrf5340_audio_dk_nrf5340/doc/index.rst index 7718258eec2652e..3d8d2413e9176dc 100644 --- a/boards/arm/nrf5340_audio_dk_nrf5340/doc/index.rst +++ b/boards/arm/nrf5340_audio_dk_nrf5340/doc/index.rst @@ -53,9 +53,6 @@ The nrf5340_audio_dk_nrf5340_cpuapp build target provides support for the applic core on the nRF5340 SoC. The nrf5340_audio_dk_nrf5340_cpunet build target provides support for the network core on the nRF5340 SoC. -.. note:: - Trusted Firmware-M (TF-M) and building the ``ns`` target is not supported for this board. - The `Nordic Semiconductor Infocenter`_ contains the processor's information and the datasheet. 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 4368ca303fc17b5..f9082e6ca4006d2 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/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpuapp_common-pinctrl.dtsi b/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpuapp_common-pinctrl.dtsi index 46359082eddba2c..5247c04429bb34f 100644 --- a/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpuapp_common-pinctrl.dtsi +++ b/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpuapp_common-pinctrl.dtsi @@ -51,6 +51,28 @@ }; }; + uart1_default: uart1_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + i2c1_default: i2c1_default { group1 { psels = , diff --git a/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpuapp_common.dtsi b/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpuapp_common.dtsi index f529f16fbe8ab1a..132687888b212db 100644 --- a/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpuapp_common.dtsi +++ b/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpuapp_common.dtsi @@ -13,7 +13,7 @@ zephyr,uart-mcumgr = &uart0; zephyr,bt-mon-uart = &uart0; zephyr,bt-c2h-uart = &uart0; - zephyr,bt-hci-rpmsg-ipc = &ipc0; + zephyr,bt-hci-ipc = &ipc0; watchdog0 = &wdt0; }; @@ -141,6 +141,14 @@ pinctrl-names = "default", "sleep"; }; +arduino_serial: &uart1 { + compatible = "nordic,nrf-uarte"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; +}; + &i2c1 { compatible = "nordic,nrf-twim"; status = "okay"; diff --git a/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpunet.dts b/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpunet.dts index 11244f82c5cb5d0..16aa4179fa9e2a3 100644 --- a/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpunet.dts +++ b/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpunet.dts @@ -18,7 +18,7 @@ zephyr,uart-mcumgr = &uart0; zephyr,bt-mon-uart = &uart0; zephyr,bt-c2h-uart = &uart0; - zephyr,bt-hci-rpmsg-ipc = &ipc0; + zephyr,bt-hci-ipc = &ipc0; zephyr,sram = &sram1; zephyr,flash = &flash1; zephyr,code-partition = &slot0_partition; diff --git a/boards/arm/nrf5340dk_nrf5340/CMakeLists.txt b/boards/arm/nrf5340dk_nrf5340/CMakeLists.txt index 8ba3238c40bb2ab..5128462d70cf45c 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 b/boards/arm/nrf5340dk_nrf5340/Kconfig index 85190d7c890c060..518328e57e818ec 100644 --- a/boards/arm/nrf5340dk_nrf5340/Kconfig +++ b/boards/arm/nrf5340dk_nrf5340/Kconfig @@ -43,7 +43,7 @@ config DOMAIN_CPUNET_BOARD 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_rpmsg on the nRF5340_cpunet for + another board. For example hci_ipc on the nRF5340_cpunet for Bluetooth applications. endif # BOARD_NRF5340DK_NRF5340_CPUAPP || BOARD_NRF5340DK_NRF5340_CPUAPP_NS diff --git a/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig b/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig index d337e2f1a1c2d38..84f19365cc53da7 100644 --- a/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig +++ b/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig @@ -8,21 +8,6 @@ if BOARD_NRF5340DK_NRF5340_CPUAPP || BOARD_NRF5340DK_NRF5340_CPUAPP_NS config BOARD default "nrf5340dk_nrf5340_cpuapp" if BOARD_NRF5340DK_NRF5340_CPUAPP || BOARD_NRF5340DK_NRF5340_CPUAPP_NS -# By default, if we build for a Non-Secure version of the board, -# enable building with TF-M as the Secure Execution Environment. -config BUILD_WITH_TFM - default y if BOARD_NRF5340DK_NRF5340_CPUAPP_NS - -if BUILD_WITH_TFM - -# By default, if we build with TF-M, instruct build system to -# flash the combined TF-M (Secure) & Zephyr (Non Secure) image -config TFM_FLASH_MERGED_BINARY - bool - default y - -endif # BUILD_WITH_TFM - # Code Partition: # # For the secure version of the board the firmware is linked at the beginning @@ -82,11 +67,12 @@ config MBOX_NRFX_IPC if BOARD_NRF5340DK_NRF5340_CPUAPP || BOARD_NRF5340DK_NRF5340_CPUAPP_NS choice BT_HCI_BUS_TYPE - default BT_RPMSG if BT + default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE - default 4096 if BT_RPMSG +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/nrf5340_cpuapp_common-pinctrl.dtsi b/boards/arm/nrf5340dk_nrf5340/nrf5340_cpuapp_common-pinctrl.dtsi index 6db9767c0dc8a3e..f93e3a694029c66 100644 --- a/boards/arm/nrf5340dk_nrf5340/nrf5340_cpuapp_common-pinctrl.dtsi +++ b/boards/arm/nrf5340dk_nrf5340/nrf5340_cpuapp_common-pinctrl.dtsi @@ -84,10 +84,12 @@ uart1_default: uart1_default { group1 { - psels = ; + psels = , + ; }; group2 { - psels = ; + psels = , + ; bias-pull-up; }; }; @@ -95,7 +97,9 @@ uart1_sleep: uart1_sleep { group1 { psels = , - ; + , + , + ; low-power-enable; }; }; diff --git a/boards/arm/nrf5340dk_nrf5340/nrf5340_cpuapp_common.dtsi b/boards/arm/nrf5340dk_nrf5340/nrf5340_cpuapp_common.dtsi index e3029b45df3bedd..70ba32524500eb5 100644 --- a/boards/arm/nrf5340dk_nrf5340/nrf5340_cpuapp_common.dtsi +++ b/boards/arm/nrf5340dk_nrf5340/nrf5340_cpuapp_common.dtsi @@ -14,7 +14,7 @@ zephyr,uart-mcumgr = &uart0; zephyr,bt-mon-uart = &uart0; zephyr,bt-c2h-uart = &uart0; - zephyr,bt-hci-rpmsg-ipc = &ipc0; + zephyr,bt-hci-ipc = &ipc0; nordic,802154-spinel-ipc = &ipc0; zephyr,ieee802154 = &ieee802154; }; diff --git a/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp.yaml b/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp.yaml index 545a41e9cd66fcd..6ed15a5d7ef1e22 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 9519f50f3e95278..90abc04b11940e8 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/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpunet.dts b/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpunet.dts index f142744debd91d6..80c3d183cd25eeb 100644 --- a/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpunet.dts +++ b/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpunet.dts @@ -19,7 +19,7 @@ zephyr,uart-mcumgr = &uart0; zephyr,bt-mon-uart = &uart0; zephyr,bt-c2h-uart = &uart0; - zephyr,bt-hci-rpmsg-ipc = &ipc0; + zephyr,bt-hci-ipc = &ipc0; nordic,802154-spinel-ipc = &ipc0; zephyr,sram = &sram1; zephyr,flash = &flash1; diff --git a/boards/arm/nrf54l15pdk_nrf54l15/Kconfig.board b/boards/arm/nrf54l15pdk_nrf54l15/Kconfig.board new file mode 100644 index 000000000000000..d95fe51009f36e9 --- /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 000000000000000..532ea07c859bc6c --- /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 000000000000000..378b7bcdb572cd2 --- /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 000000000000000..80fb2060a077277 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 000000000000000..fa896f98398cf2e --- /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 000000000000000..02b02bc817156bc --- /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 000000000000000..1e0245f6cc36a8e --- /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 000000000000000..de5ce29d162bc07 --- /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 000000000000000..bc74c3eeb336fcf --- /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 000000000000000..4fe5b260db375ad --- /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/Kconfig.board b/boards/arm/nrf9131ek_nrf9131/Kconfig.board new file mode 100644 index 000000000000000..4a237e3fb617a7f --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/Kconfig.board @@ -0,0 +1,14 @@ +# nRF9131-EK board configuration + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF9131_LACA + +config BOARD_NRF9131EK_NRF9131 + bool "nRF9131 EK NRF9131" + +config BOARD_NRF9131EK_NRF9131_NS + bool "nRF9131 EK NRF9131 non-secure" + +endif # SOC_NRF9131_LACA diff --git a/boards/arm/nrf9131ek_nrf9131/Kconfig.defconfig b/boards/arm/nrf9131ek_nrf9131/Kconfig.defconfig new file mode 100644 index 000000000000000..0ece4f9a2ac1cff --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/Kconfig.defconfig @@ -0,0 +1,38 @@ +# nRF9131 EK NRF9131 board configuration + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NRF9131EK_NRF9131 || BOARD_NRF9131EK_NRF9131_NS + +config BOARD + default "nrf9131ek_nrf9131" + +# For the secure version of the board the firmware is linked at the beginning +# of the flash, or into the code-partition defined in DT if it is intended to +# be loaded by MCUboot. If the secure firmware is to be combined with a non- +# secure image (TRUSTED_EXECUTION_SECURE=y), the secure FW image shall always +# be restricted to the size of its code partition. +# For the non-secure version of the board, the firmware +# must be linked into the code-partition (non-secure) defined in DT, regardless. +# Apply this configuration below by setting the Kconfig symbols used by +# the linker according to the information extracted from DT partitions. + +# Workaround for not being able to have commas in macro arguments +DT_CHOSEN_Z_CODE_PARTITION := zephyr,code-partition + +config FLASH_LOAD_SIZE + default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) + depends on BOARD_NRF9131EK_NRF9131 && TRUSTED_EXECUTION_SECURE + +if BOARD_NRF9131EK_NRF9131_NS + +config FLASH_LOAD_OFFSET + default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) + +config FLASH_LOAD_SIZE + default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) + +endif # BOARD_NRF9131EK_NRF9131_NS + +endif # BOARD_NRF9131EK_NRF9131 || BOARD_NRF9131EK_NRF9131_NS diff --git a/boards/arm/nrf9131ek_nrf9131/board.cmake b/boards/arm/nrf9131ek_nrf9131/board.cmake new file mode 100644 index 000000000000000..8293a428b401347 --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/board.cmake @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_BOARD_NRF9131EK_NRF9131_NS) + set(TFM_PUBLIC_KEY_FORMAT "full") +endif() + +if(CONFIG_TFM_FLASH_MERGED_BINARY) + set_property(TARGET runners_yaml_props_target PROPERTY hex_file tfm_merged.hex) +endif() + +# TODO: change to nRF9131_xxAA when such device is available in JLink +board_runner_args(jlink "--device=nRF9160_xxAA" "--speed=4000") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/nrf9131ek_nrf9131/doc/img/nrf9131ek_nrf9131.webp b/boards/arm/nrf9131ek_nrf9131/doc/img/nrf9131ek_nrf9131.webp new file mode 100644 index 000000000000000..056296ebbbcab5b Binary files /dev/null and b/boards/arm/nrf9131ek_nrf9131/doc/img/nrf9131ek_nrf9131.webp differ diff --git a/boards/arm/nrf9131ek_nrf9131/doc/index.rst b/boards/arm/nrf9131ek_nrf9131/doc/index.rst new file mode 100644 index 000000000000000..57473c631ed5413 --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/doc/index.rst @@ -0,0 +1,229 @@ +.. _nrf9131ek_nrf9131: + +nRF9131 EK +########## + +Overview +******** + +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: + +* :abbr:`ADC (Analog to Digital Converter)` +* CLOCK +* FLASH +* :abbr:`GPIO (General Purpose Input Output)` +* :abbr:`I2C (Inter-Integrated Circuit)` +* :abbr:`MPU (Memory Protection Unit)` +* :abbr:`NVIC (Nested Vectored Interrupt Controller)` +* :abbr:`PWM (Pulse Width Modulation)` +* :abbr:`RTC (nRF RTC System Clock)` +* Segger RTT (RTT Console) +* :abbr:`SPI (Serial Peripheral Interface)` +* :abbr:`UARTE (Universal asynchronous receiver-transmitter with EasyDMA)` +* :abbr:`WDT (Watchdog Timer)` +* :abbr:`IDAU (Implementation Defined Attribution Unit)` + +.. figure:: img/nrf9131ek_nrf9131.webp + :align: center + :alt: nRF9131 EK + + nRF9131 EK (Credit: Nordic Semiconductor) + +The `Nordic Semiconductor Infocenter`_ +contains the processor's information and the datasheet. + + +Hardware +******** + +nRF9131 EK has two external oscillators. The frequency of +the slow clock is 32.768 kHz. The frequency of the main clock +is 32 MHz. + +Supported Features +================== + +The nrf9131ek_nrf9131 board configuration supports the following +hardware features: + ++-----------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+======================+ +| ADC | on-chip | adc | ++-----------+------------+----------------------+ +| CLOCK | on-chip | clock_control | ++-----------+------------+----------------------+ +| FLASH | on-chip | flash | ++-----------+------------+----------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+----------------------+ +| I2C(M) | on-chip | i2c | ++-----------+------------+----------------------+ +| MPU | on-chip | arch/arm | ++-----------+------------+----------------------+ +| NVIC | on-chip | arch/arm | ++-----------+------------+----------------------+ +| PWM | on-chip | pwm | ++-----------+------------+----------------------+ +| RTC | on-chip | system clock | ++-----------+------------+----------------------+ +| RTT | Segger | console | ++-----------+------------+----------------------+ +| SPI(M/S) | on-chip | spi | ++-----------+------------+----------------------+ +| SPU | on-chip | system protection | ++-----------+------------+----------------------+ +| UARTE | on-chip | serial | ++-----------+------------+----------------------+ +| WDT | on-chip | watchdog | ++-----------+------------+----------------------+ + +Connections and IOs +=================== + +LED +--- + +* LED (red) = P0.29 +* LED (green) = P0.30 +* LED (blue) = P0.31 + +Push buttons and Switches +------------------------- + +* BUTTON = P0.28 +* RESET + +Security components +=================== + +- Implementation Defined Attribution Unit (`IDAU`_). The IDAU is implemented + with the System Protection Unit and is used to define secure and non-secure + memory maps. By default, all of the memory space (Flash, SRAM, and + peripheral address space) is defined to be secure accessible only. +- Secure boot. + + +Programming and Debugging +************************* + +nrf9131ek_nrf9131 supports the Armv8m Security Extension, and by default boots +in the Secure state. + +Building Secure/Non-Secure Zephyr applications with Arm |reg| TrustZone |reg| +============================================================================= + +Applications on the nRF9131 may contain a Secure and a Non-Secure firmware +image. The Secure image can be built using either Zephyr or +`Trusted Firmware M`_ (TF-M). Non-Secure firmware images are always built +using Zephyr. The two alternatives are described below. + +.. note:: + + By default the Secure image for nRF9131 is built using TF-M. + +Building the Secure firmware using Zephyr +----------------------------------------- + +The process requires the following steps: + +1. Build the Secure Zephyr application using ``-DBOARD=nrf9131ek_nrf9131`` and + ``CONFIG_TRUSTED_EXECUTION_SECURE=y`` in the application project configuration file. +2. Build the Non-Secure Zephyr application using ``-DBOARD=nrf9131ek_nrf9131_ns``. +3. Merge the two binaries together. + +Building the Secure firmware with TF-M +-------------------------------------- + +The process to build the Secure firmware image using TF-M and the Non-Secure +firmware image using Zephyr requires the following action: + +1. Build the Non-Secure Zephyr application + using ``-DBOARD=nrf9131ek_nrf9131_ns``. + To invoke the building of TF-M the Zephyr build system requires the + Kconfig option ``BUILD_WITH_TFM`` to be enabled, which is done by + default when building Zephyr as a Non-Secure application. + The Zephyr build system will perform the following steps automatically: + + * Build the Non-Secure firmware image as a regular Zephyr application + * Build a TF-M (secure) firmware image + * Merge the output binaries together + * Optionally build a bootloader image (MCUboot) + +.. note:: + + Depending on the TF-M configuration, an application DTS overlay may be + required, to adjust the Non-Secure image Flash and SRAM starting address + and sizes. + +When building a Secure/Non-Secure application, the Secure application will +have to set the IDAU (SPU) configuration to allow Non-Secure access to all +CPU resources utilized by the Non-Secure application firmware. SPU +configuration shall take place before jumping to the Non-Secure application. + +Building a Secure only application +================================== + +Build the Zephyr app in the usual way (see :ref:`build_an_application` +and :ref:`application_run`), using ``-DBOARD=nrf9131ek_nrf9131``. + + +Flashing +======== + +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`. Then build and flash +applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +Here is an example for the :ref:`hello_world` application. + +First, run your favorite terminal program to listen for output. + +.. code-block:: console + + $ minicom -D -b 115200 + +Replace :code:`` with the port where the nRF9131 EK +can be found. For example, under Linux, :code:`/dev/ttyACM0`. + +Then build and flash the application in the usual way. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: nrf9131ek_nrf9131 + :goals: build flash + +Debugging +========= + +Refer to the :ref:`nordic_segger` page to learn about debugging Nordic boards with a +Segger IC. + + +Testing the LEDs and buttons in the nRF9131 EK +********************************************** + +There are 2 samples that allow you to test that the button and LED 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/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common.dtsi`. + +References +********** + +.. target-notes:: + +.. _IDAU: + https://developer.arm.com/docs/100690/latest/attribution-units-sau-and-idau +.. _Nordic Semiconductor Infocenter: https://infocenter.nordicsemi.com +.. _Trusted Firmware M: https://www.trustedfirmware.org/projects/tf-m/ diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131.dts b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131.dts new file mode 100644 index 000000000000000..4b66e5348a0509a --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131.dts @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf9131ek_nrf9131_common.dtsi" + +/ { + chosen { + zephyr,sram = &sram0_s; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,sram-secure-partition = &sram0_s; + zephyr,sram-non-secure-partition = &sram0_ns; + }; +}; diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131.yaml b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131.yaml new file mode 100644 index 000000000000000..d1b04054ce8914a --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131.yaml @@ -0,0 +1,17 @@ +identifier: nrf9131ek_nrf9131 +name: nRF9131-EK-NRF9131 +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 88 +flash: 1024 +supported: + - gpio + - i2c + - pwm + - spi + - watchdog + - counter diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common-pinctrl.dtsi b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common-pinctrl.dtsi new file mode 100644 index 000000000000000..419e7c8d70ce975 --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common-pinctrl.dtsi @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + uart1_default: uart1_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + i2c2_default: i2c2_default { + group1 { + psels = , + ; + }; + }; + + i2c2_sleep: i2c2_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + pwm0_default: pwm0_default { + group1 { + psels = , + , + ; + }; + }; + + pwm0_sleep: pwm0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + spi3_default: spi3_default { + group1 { + psels = , + , + ; + nordic,drive-mode = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common.dtsi b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common.dtsi new file mode 100644 index 000000000000000..2c3b8481d2ae86e --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_common.dtsi @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "nrf9131ek_nrf9131_common-pinctrl.dtsi" +#include + +/ { + model = "Nordic nRF9131 EK NRF9131"; + compatible = "nordic,nrf9131-ek-nrf9131"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>; + label = "Red LED 1"; + }; + led1: led_1 { + gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>; + label = "Green LED 2"; + }; + led2: led_2 { + gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; + label = "Blue LED 3"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_led0: pwm_led_0 { + pwms = <&pwm0 0 PWM_MSEC(8) PWM_POLARITY_NORMAL>; + }; + pwm_led1: pwm_led_1 { + pwms = <&pwm0 1 PWM_MSEC(8) PWM_POLARITY_NORMAL>; + }; + pwm_led2: pwm_led_2 { + pwms = <&pwm0 2 PWM_MSEC(8) PWM_POLARITY_NORMAL>; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 28 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 1"; + zephyr,code = ; + }; + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led0; + led1 = &led1; + led2 = &led2; + pwm-led0 = &pwm_led0; + pwm-led1 = &pwm_led1; + pwm-led2 = &pwm_led2; + sw0 = &button0; + bootloader-led0 = &led0; + mcuboot-button0 = &button0; + mcuboot-led0 = &led0; + watchdog0 = &wdt0; + spi-flash0 = &gd25wb256; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&i2c2 { + compatible = "nordic,nrf-twim"; + status = "okay"; + pinctrl-0 = <&i2c2_default>; + pinctrl-1 = <&i2c2_sleep>; + pinctrl-names = "default", "sleep"; + clock-frequency = ; + + pmic_main: npm1300@6b { + compatible = "nordic,npm1300"; + reg = <0x6b>; + pmic_charger: charger { + compatible = "nordic,npm1300-charger"; + term-microvolt = <4150000>; + term-warm-microvolt = <4000000>; + current-microamp = <150000>; + dischg-limit-microamp = <1000000>; + vbus-limit-microamp = <500000>; + thermistor-ohms = <10000>; + thermistor-beta = <3380>; + charging-enable; + }; + regulators { + compatible = "nordic,npm1300-regulator"; + BUCK1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + BUCK2 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + }; + }; +}; + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + cs-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + gd25wb256: gd25wb256e3ir@0 { + compatible = "jedec,spi-nor"; + status = "disabled"; + reg = <0>; + spi-max-frequency = <8000000>; + size = <268435456>; + has-dpd; + t-enter-dpd = <3000>; + t-exit-dpd = <40000>; + sfdp-bfp = [ + e5 20 f3 ff ff ff ff 0f 44 eb 08 6b 08 3b 42 bb + ee ff ff ff ff ff 00 ff ff ff 00 ff 0c 20 0f 52 + 10 d8 00 ff 44 7a c9 fe 83 67 26 62 ec 82 18 44 + 7a 75 7a 75 04 c4 d5 5c 00 06 74 00 08 50 00 01 + ]; + jedec-id = [c8 65 19]; + }; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x10000>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + }; + slot0_ns_partition: partition@50000 { + label = "image-0-nonsecure"; + }; + slot1_partition: partition@85000 { + label = "image-1"; + }; + slot1_ns_partition: partition@c5000 { + label = "image-1-nonsecure"; + }; + storage_partition: partition@fa000 { + label = "storage"; + reg = <0x000fa000 0x00006000>; + }; + }; +}; + + + +/ { + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + sram0_s: image_s@20000000 { + /* Secure image memory */ + }; + + sram0_modem: image_modem@20016000 { + /* Modem (shared) memory */ + }; + + sram0_ns: image_ns@20020000 { + /* Non-Secure image memory */ + }; + }; +}; + +/* Include partition configuration file */ +#include "nrf9131ek_nrf9131_partition_conf.dtsi" diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_defconfig b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_defconfig new file mode 100644 index 000000000000000..fc77ffe0d13a856 --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_defconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF91X=y +CONFIG_SOC_NRF9131_LACA=y +CONFIG_BOARD_NRF9131EK_NRF9131=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable TrustZone-M +CONFIG_ARM_TRUSTZONE_M=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +CONFIG_PINCTRL=y diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns.dts b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns.dts new file mode 100644 index 000000000000000..9a652cd0aed8bfb --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf9131ek_nrf9131_common.dtsi" + +/ { + chosen { + zephyr,flash = &flash0; + zephyr,sram = &sram0_ns; + zephyr,code-partition = &slot0_ns_partition; + }; +}; + +/* Disable UART1, because it is used by default in TF-M */ +&uart1 { + status = "disabled"; +}; diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns.yaml b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns.yaml new file mode 100644 index 000000000000000..cf33abd55da3c03 --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns.yaml @@ -0,0 +1,15 @@ +identifier: nrf9131ek_nrf9131_ns +name: nRF9131-EK-NRF9131-Non-Secure +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 128 +flash: 212 +supported: + - i2c + - pwm + - watchdog + - netif:modem diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns_defconfig b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns_defconfig new file mode 100644 index 000000000000000..83af1cf6b74ad11 --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_ns_defconfig @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF91X=y +CONFIG_SOC_NRF9131_LACA=y +CONFIG_BOARD_NRF9131EK_NRF9131_NS=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable TrustZone-M +CONFIG_ARM_TRUSTZONE_M=y + +# This Board implies building Non-Secure firmware +CONFIG_TRUSTED_EXECUTION_NONSECURE=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +CONFIG_PINCTRL=y + +# enable PMIC +CONFIG_I2C=y +CONFIG_REGULATOR=y +CONFIG_SENSOR=y +CONFIG_NPM1300_CHARGER=y diff --git a/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_partition_conf.dtsi b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_partition_conf.dtsi new file mode 100644 index 000000000000000..d14d8d95f75855b --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/nrf9131ek_nrf9131_partition_conf.dtsi @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Default Flash planning for nRF9131ek_nrf9131. + * + * Zephyr build for nRF9131 with ARM TrustZone-M support, + * implies building Secure and Non-Secure Zephyr images. + * + * Secure image will be placed, by default, in flash0 + * (or in slot0, if MCUboot is present). + * Secure image will use sram0 for system memory. + * + * Non-Secure image will be placed in slot0_ns, and use + * sram0_ns for system memory. + * + * Note that the Secure image only requires knowledge of + * the beginning of the Non-Secure image (not its size). + */ + +&slot0_partition { + reg = <0x00010000 0x40000>; +}; + +&slot0_ns_partition { + reg = <0x00050000 0x35000>; +}; + +&slot1_partition { + reg = <0x00085000 0x40000>; +}; + +&slot1_ns_partition { + reg = <0x000c5000 0x35000>; +}; + +/* Default SRAM planning when building for nRF9131 with + * ARM TrustZone-M support + * - Lowest 88 kB SRAM allocated to Secure image (sram0_s). + * - 40 kB SRAM reserved for and used by the modem library + * (sram0_modem). This memory is Non-Secure. + * - Upper 128 kB allocated to Non-Secure image (sram0_ns). + * When building with TF-M, both sram0_modem and sram0_ns + * are allocated to the Non-Secure image. + */ + +&sram0_s { + reg = <0x20000000 DT_SIZE_K(88)>; +}; + +&sram0_modem { + reg = <0x20016000 DT_SIZE_K(40)>; +}; + +&sram0_ns { + reg = <0x20020000 DT_SIZE_K(128)>; +}; diff --git a/boards/arm/nrf9131ek_nrf9131/pre_dt_board.cmake b/boards/arm/nrf9131ek_nrf9131/pre_dt_board.cmake new file mode 100644 index 000000000000000..c8267afd1b470a1 --- /dev/null +++ b/boards/arm/nrf9131ek_nrf9131/pre_dt_board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2021 Linaro Limited +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "unique_unit_address_if_enabled" to handle the following overlaps: +# - flash-controller@39000 & kmu@39000 +# - power@5000 & clock@5000 +list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") diff --git a/boards/arm/nrf9151dk_nrf9151/Kconfig.board b/boards/arm/nrf9151dk_nrf9151/Kconfig.board new file mode 100644 index 000000000000000..92352ddc16fa368 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/Kconfig.board @@ -0,0 +1,14 @@ +# nRF9151 DK NRF9151 board configuration + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF9151_LACA + +config BOARD_NRF9151DK_NRF9151 + bool "nRF9151 DK NRF9151" + +config BOARD_NRF9151DK_NRF9151_NS + bool "nRF9151 DK NRF9151 non-secure" + +endif # SOC_NRF9151_LACA diff --git a/boards/arm/nrf9151dk_nrf9151/Kconfig.defconfig b/boards/arm/nrf9151dk_nrf9151/Kconfig.defconfig new file mode 100644 index 000000000000000..3cbff101d63624f --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/Kconfig.defconfig @@ -0,0 +1,47 @@ +# nRF9151 DK NRF9151 board configuration + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NRF9151DK_NRF9151 || BOARD_NRF9151DK_NRF9151_NS + +config BOARD + default "nrf9151dk_nrf9151" + +# For the secure version of the board the firmware is linked at the beginning +# of the flash, or into the code-partition defined in DT if it is intended to +# be loaded by MCUboot. If the secure firmware is to be combined with a non- +# secure image (TRUSTED_EXECUTION_SECURE=y), the secure FW image shall always +# be restricted to the size of its code partition. +# For the non-secure version of the board, the firmware +# must be linked into the code-partition (non-secure) defined in DT, regardless. +# Apply this configuration below by setting the Kconfig symbols used by +# the linker according to the information extracted from DT partitions. + +# Workaround for not being able to have commas in macro arguments +DT_CHOSEN_Z_CODE_PARTITION := zephyr,code-partition + +config FLASH_LOAD_SIZE + default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) + depends on BOARD_NRF9151DK_NRF9151 && TRUSTED_EXECUTION_SECURE + +if BOARD_NRF9151DK_NRF9151_NS + +config FLASH_LOAD_OFFSET + default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) + +config FLASH_LOAD_SIZE + default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) + +endif # BOARD_NRF9151DK_NRF9151_NS + +config BT_HCI_VS + default y if BT + +config BT_WAIT_NOP + default BT && $(dt_nodelabel_enabled,nrf5340_reset) + +config I2C + default $(dt_compat_on_bus,$(DT_COMPAT_NXP_PCAL6408A),i2c) + +endif # BOARD_NRF9151DK_NRF9151 || BOARD_NRF9151DK_NRF9151_NS diff --git a/boards/arm/nrf9151dk_nrf9151/board.cmake b/boards/arm/nrf9151dk_nrf9151/board.cmake new file mode 100644 index 000000000000000..a3126c941d98271 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/board.cmake @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_BOARD_NRF9151DK_NRF9151_NS) + set(TFM_PUBLIC_KEY_FORMAT "full") +endif() + +if(CONFIG_TFM_FLASH_MERGED_BINARY) + set_property(TARGET runners_yaml_props_target PROPERTY hex_file tfm_merged.hex) +endif() + +# TODO: change to nRF9151_xxAA when such device is available in JLink +board_runner_args(jlink "--device=nRF9160_xxAA" "--speed=4000") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/nrf9151dk_nrf9151/doc/index.rst b/boards/arm/nrf9151dk_nrf9151/doc/index.rst new file mode 100644 index 000000000000000..4c02e7ed372d831 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/doc/index.rst @@ -0,0 +1,203 @@ +.. _nrf9151dk_nrf9151: + +nRF9151 DK +########## + +Overview +******** + +The nRF9151 DK (PCA10171) is a single-board development kit for evaluation and +development on the nRF9151 SiP for DECT NR+ and LTE-M/NB-IoT with GNSS. The nrf9151dk_nrf9151 +board configuration provides support for the Nordic Semiconductor nRF9151 ARM +Cortex-M33F CPU with ARMv8-M Security Extension and the following devices: + +* :abbr:`ADC (Analog to Digital Converter)` +* CLOCK +* FLASH +* :abbr:`GPIO (General Purpose Input Output)` +* :abbr:`I2C (Inter-Integrated Circuit)` +* :abbr:`MPU (Memory Protection Unit)` +* :abbr:`NVIC (Nested Vectored Interrupt Controller)` +* :abbr:`PWM (Pulse Width Modulation)` +* :abbr:`RTC (nRF RTC System Clock)` +* Segger RTT (RTT Console) +* :abbr:`SPI (Serial Peripheral Interface)` +* :abbr:`UARTE (Universal asynchronous receiver-transmitter with EasyDMA)` +* :abbr:`WDT (Watchdog Timer)` +* :abbr:`IDAU (Implementation Defined Attribution Unit)` + +More information about the board can be found at the +`nRF9151 DK website`_. The `Nordic Semiconductor Infocenter`_ +contains the processor's information and the datasheet. + + +Hardware +******** + +nRF9151 DK has two external oscillators. The frequency of +the slow clock is 32.768 kHz. The frequency of the main clock +is 32 MHz. + +Supported Features +================== + +The nrf9151dk_nrf9151 board configuration supports the following +hardware features: + ++-----------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+======================+ +| ADC | on-chip | adc | ++-----------+------------+----------------------+ +| CLOCK | on-chip | clock_control | ++-----------+------------+----------------------+ +| FLASH | on-chip | flash | ++-----------+------------+----------------------+ +| FLASH | external | spi | ++-----------+------------+----------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+----------------------+ +| GPIO | external | i2c | ++-----------+------------+----------------------+ +| I2C(M) | on-chip | i2c | ++-----------+------------+----------------------+ +| MPU | on-chip | arch/arm | ++-----------+------------+----------------------+ +| NVIC | on-chip | arch/arm | ++-----------+------------+----------------------+ +| PWM | on-chip | pwm | ++-----------+------------+----------------------+ +| RTC | on-chip | system clock | ++-----------+------------+----------------------+ +| RTT | nRF53 | console | ++-----------+------------+----------------------+ +| SPI(M/S) | on-chip | spi | ++-----------+------------+----------------------+ +| SPU | on-chip | system protection | ++-----------+------------+----------------------+ +| UARTE | on-chip | serial | ++-----------+------------+----------------------+ +| WDT | on-chip | watchdog | ++-----------+------------+----------------------+ + + +.. _nrf9151dk_additional_hardware: + +Other hardware features have not been enabled yet for this board. +See `nRF9151 DK website`_ and `Nordic Semiconductor Infocenter`_ +for a complete list of nRF9151 DK board hardware features. + +Connections and IOs +=================== + +LED +--- + +* LED1 (green) = P0.0 +* LED2 (green) = P0.1 +* LED3 (green) = P0.4 +* LED4 (green) = P0.5 + +Push buttons and Switches +------------------------- + +* BUTTON1 = P0.8 +* BUTTON2 = P0.9 +* SWITCH1 = P0.18 +* SWITCH2 = P0.19 +* BOOT = SW5 = boot/reset + +Security components +=================== + +- Implementation Defined Attribution Unit (`IDAU`_). The IDAU is implemented + with the System Protection Unit and is used to define secure and non-secure + memory maps. By default, all of the memory space (Flash, SRAM, and + peripheral address space) is defined to be secure accessible only. +- Secure boot. + + +Programming and Debugging +************************* + +nrf9151dk_nrf9151 supports the Armv8m Security Extension, and by default boots +in the Secure state. + +Building Secure/Non-Secure Zephyr applications with Arm |reg| TrustZone |reg| +============================================================================= + +The process requires the following steps: + +1. Build the Secure Zephyr application using ``-DBOARD=nrf9151dk_nrf9151`` and + ``CONFIG_TRUSTED_EXECUTION_SECURE=y`` in the application project configuration file. +2. Build the Non-Secure Zephyr application using ``-DBOARD=nrf9151dk_nrf9151_ns``. +3. Merge the two binaries together. + +When building a Secure/Non-Secure application, the Secure application will +have to set the IDAU (SPU) configuration to allow Non-Secure access to all +CPU resources utilized by the Non-Secure application firmware. SPU +configuration shall take place before jumping to the Non-Secure application. + +Building a Secure only application +================================== + +Build the Zephyr app in the usual way (see :ref:`build_an_application` +and :ref:`application_run`), using ``-DBOARD=nrf9151dk_nrf9151``. + +Flashing +======== + +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`. Then build and flash +applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +Here is an example for the :ref:`hello_world` application. + +First, run your favorite terminal program to listen for output. + +.. code-block:: console + + $ minicom -D -b 115200 + +Replace :code:`` with the port where the nRF9151 DK +can be found. For example, under Linux, :code:`/dev/ttyACM0`. + +Then build and flash the application in the usual way. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: nrf9151dk_nrf9151 + :goals: build flash + +Debugging +========= + +Refer to the :ref:`nordic_segger` page to learn about debugging Nordic boards with a +Segger IC. + + +Testing the LEDs and buttons in the nRF9151 DK +********************************************** + +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/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common.dtsi`. + +References +********** + +.. target-notes:: + +.. _IDAU: + https://developer.arm.com/docs/100690/latest/attribution-units-sau-and-idau +.. _nRF9151 DK website: https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF9151-DK +.. _Nordic Semiconductor Infocenter: https://infocenter.nordicsemi.com +.. _Trusted Firmware M: https://www.trustedfirmware.org/projects/tf-m/ diff --git a/boards/arm/nrf9151dk_nrf9151/dts/bindings/nordic,nrf9151dk-nrf5340-reset.yaml b/boards/arm/nrf9151dk_nrf9151/dts/bindings/nordic,nrf9151dk-nrf5340-reset.yaml new file mode 100644 index 000000000000000..2b51125312cff3f --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/dts/bindings/nordic,nrf9151dk-nrf5340-reset.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: GPIO used to reset nRF5340 on nRF9151 DK + +compatible: "nordic,nrf9151dk-nrf5340-reset" + +include: base.yaml + +properties: + status: + required: true + + gpios: + type: phandle-array + required: true + description: | + GPIO to use as nRF5340 reset line: output in nRF9151, input in nRF5340. diff --git a/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_buttons_on_io_expander.dtsi b/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_buttons_on_io_expander.dtsi new file mode 100644 index 000000000000000..20f7d2406a57c50 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_buttons_on_io_expander.dtsi @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pcal6408a { + status = "okay"; +}; + +&button0 { + gpios = <&pcal6408a 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; +}; + +&button1 { + gpios = <&pcal6408a 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; +}; + +&button2 { + gpios = <&pcal6408a 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; +}; + +&button3 { + gpios = <&pcal6408a 3 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; +}; diff --git a/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_leds_on_io_expander.dtsi b/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_leds_on_io_expander.dtsi new file mode 100644 index 000000000000000..d80c509d215200d --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/dts/nrf9151dk_leds_on_io_expander.dtsi @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pcal6408a { + status = "okay"; +}; + +&led0 { + gpios = <&pcal6408a 4 GPIO_ACTIVE_HIGH>; +}; + +&led1 { + gpios = <&pcal6408a 5 GPIO_ACTIVE_HIGH>; +}; + +&led2 { + gpios = <&pcal6408a 6 GPIO_ACTIVE_HIGH>; +}; + +&led3 { + gpios = <&pcal6408a 7 GPIO_ACTIVE_HIGH>; +}; diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.dts b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.dts new file mode 100644 index 000000000000000..8c3b49214343bbb --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.dts @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf9151dk_nrf9151_common.dtsi" + +/ { + chosen { + zephyr,sram = &sram0_s; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,sram-secure-partition = &sram0_s; + zephyr,sram-non-secure-partition = &sram0_ns; + }; +}; diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.yaml b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.yaml new file mode 100644 index 000000000000000..3ad90fea76d9d67 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151.yaml @@ -0,0 +1,22 @@ +identifier: nrf9151dk_nrf9151 +name: nRF9151-DK-NRF9151 +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 88 +flash: 1024 +supported: + - arduino_gpio + - arduino_i2c + - arduino_serial + - arduino_spi + - gpio + - i2c + - pwm + - spi + - watchdog + - counter +vendor: nordic diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common-pinctrl.dtsi b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common-pinctrl.dtsi new file mode 100644 index 000000000000000..a1680e830f4eee5 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common-pinctrl.dtsi @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + uart1_default: uart1_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + i2c2_default: i2c2_default { + group1 { + psels = , + ; + }; + }; + + i2c2_sleep: i2c2_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + pwm0_default: pwm0_default { + group1 { + psels = ; + }; + }; + + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; + + spi3_default: spi3_default { + group1 { + psels = , + , + ; + nordic,drive-mode = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common.dtsi b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common.dtsi new file mode 100644 index 000000000000000..958e864c63cdc57 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_common.dtsi @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "nrf9151dk_nrf9151_common-pinctrl.dtsi" +#include + +/ { + model = "Nordic nRF9151 DK NRF9151"; + compatible = "nordic,nrf9151-dk-nrf9151"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + label = "Green LED 1"; + }; + led1: led_1 { + gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; + label = "Green LED 2"; + }; + led2: led_2 { + gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + label = "Green LED 3"; + }; + led3: led_3 { + gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>; + label = "Green LED 4"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_led0: pwm_led_0 { + pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 1"; + zephyr,code = ; + }; + button1: button_1 { + gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 2"; + zephyr,code = ; + }; + button2: button_2 { + gpios = <&gpio0 18 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 3"; + zephyr,code = ; + }; + button3: button_3 { + gpios = <&gpio0 19 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 4"; + zephyr,code = ; + }; + }; + + nrf5340_reset: gpio-reset { + compatible = "nordic,nrf9151dk-nrf5340-reset"; + status = "disabled"; + gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; + }; + + 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 14 0>, /* A0 */ + <1 0 &gpio0 15 0>, /* A1 */ + <2 0 &gpio0 16 0>, /* A2 */ + <3 0 &gpio0 17 0>, /* A3 */ + <4 0 &gpio0 18 0>, /* A4 */ + <5 0 &gpio0 19 0>, /* A5 */ + <6 0 &gpio0 0 0>, /* D0 */ + <7 0 &gpio0 1 0>, /* D1 */ + <8 0 &gpio0 2 0>, /* D2 */ + <9 0 &gpio0 3 0>, /* D3 */ + <10 0 &gpio0 4 0>, /* D4 */ + <11 0 &gpio0 5 0>, /* D5 */ + <12 0 &gpio0 6 0>, /* D6 */ + <13 0 &gpio0 7 0>, /* D7 */ + <14 0 &gpio0 8 0>, /* D8 */ + <15 0 &gpio0 9 0>, /* D9 */ + <16 0 &gpio0 10 0>, /* D10 */ + <17 0 &gpio0 11 0>, /* D11 */ + <18 0 &gpio0 12 0>, /* D12 */ + <19 0 &gpio0 13 0>, /* D13 */ + <20 0 &gpio0 30 0>, /* D14 */ + <21 0 &gpio0 31 0>; /* D15 */ + }; + + arduino_adc: analog-connector { + compatible = "arduino,uno-adc"; + #io-channel-cells = <1>; + io-channel-map = <0 &adc 1>, /* A0 = P0.14 = AIN1 */ + <1 &adc 2>, /* A1 = P0.15 = AIN2 */ + <2 &adc 3>, /* A2 = P0.16 = AIN3 */ + <3 &adc 4>, /* A3 = P0.17 = AIN4 */ + <4 &adc 5>, /* A4 = P0.18 = AIN5 */ + <5 &adc 6>; /* A5 = P0.19 = AIN6 */ + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led0; + led1 = &led1; + led2 = &led2; + led3 = &led3; + pwm-led0 = &pwm_led0; + sw0 = &button0; + sw1 = &button1; + sw2 = &button2; + sw3 = &button3; + bootloader-led0 = &led0; + mcuboot-button0 = &button0; + mcuboot-led0 = &led0; + watchdog0 = &wdt0; + spi-flash0 = &gd25wb256; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +arduino_serial: &uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; +}; + +arduino_i2c: &i2c2 { + compatible = "nordic,nrf-twim"; + status = "okay"; + pinctrl-0 = <&i2c2_default>; + pinctrl-1 = <&i2c2_sleep>; + pinctrl-names = "default", "sleep"; + clock-frequency = ; + + pcal6408a: pcal6408a@21 { + compatible = "nxp,pcal6408a"; + status = "disabled"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + int-gpios = <&gpio0 19 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; +}; + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +arduino_spi: &spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>, /* D10 */ + <&gpio0 20 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + gd25wb256: gd25wb256e3ir@1 { + compatible = "jedec,spi-nor"; + status = "disabled"; + reg = <1>; + spi-max-frequency = <8000000>; + size = <268435456>; + has-dpd; + t-enter-dpd = <3000>; + t-exit-dpd = <40000>; + sfdp-bfp = [ + e5 20 f3 ff ff ff ff 0f 44 eb 08 6b 08 3b 42 bb + ee ff ff ff ff ff 00 ff ff ff 00 ff 0c 20 0f 52 + 10 d8 00 ff 44 7a c9 fe 83 67 26 62 ec 82 18 44 + 7a 75 7a 75 04 c4 d5 5c 00 06 74 00 08 50 00 01 + ]; + jedec-id = [c8 65 19]; + }; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x10000>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + }; + slot0_ns_partition: partition@50000 { + label = "image-0-nonsecure"; + }; + slot1_partition: partition@85000 { + label = "image-1"; + }; + slot1_ns_partition: partition@c5000 { + label = "image-1-nonsecure"; + }; + storage_partition: partition@fa000 { + label = "storage"; + reg = <0x000fa000 0x00006000>; + }; + }; +}; + +/ { + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + sram0_s: image_s@20000000 { + /* Secure image memory */ + }; + + sram0_modem: image_modem@20016000 { + /* Modem (shared) memory */ + }; + + sram0_ns: image_ns@20020000 { + /* Non-Secure image memory */ + }; + }; +}; + +/* Include partition configuration file */ +#include "nrf9151dk_nrf9151_partition_conf.dtsi" diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_defconfig b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_defconfig new file mode 100644 index 000000000000000..7afe5ac7aa995d8 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_defconfig @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF91X=y +CONFIG_SOC_NRF9151_LACA=y +CONFIG_BOARD_NRF9151DK_NRF9151=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable TrustZone-M +CONFIG_ARM_TRUSTZONE_M=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/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.dts b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.dts new file mode 100644 index 000000000000000..a41c4aad3882e9f --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf9151dk_nrf9151_common.dtsi" + +/ { + chosen { + zephyr,flash = &flash0; + zephyr,sram = &sram0_ns; + zephyr,code-partition = &slot0_ns_partition; + }; +}; + +/* Disable UART1, because it is used by default in TF-M */ +&uart1 { + status = "disabled"; +}; diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.yaml b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.yaml new file mode 100644 index 000000000000000..c5d4fe925415ead --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns.yaml @@ -0,0 +1,20 @@ +identifier: nrf9151dk_nrf9151_ns +name: nRF9151-DK-NRF9151-Non-Secure +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 128 +flash: 192 +supported: + - arduino_gpio + - arduino_i2c + - arduino_serial + - arduino_spi + - i2c + - pwm + - watchdog + - netif:modem +vendor: nordic diff --git a/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns_defconfig b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns_defconfig new file mode 100644 index 000000000000000..949ef39f856df09 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_ns_defconfig @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF91X=y +CONFIG_SOC_NRF9151_LACA=y +CONFIG_BOARD_NRF9151DK_NRF9151_NS=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable TrustZone-M +CONFIG_ARM_TRUSTZONE_M=y + +# This Board implies building Non-Secure firmware +CONFIG_TRUSTED_EXECUTION_NONSECURE=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/nrf9151dk_nrf9151/nrf9151dk_nrf9151_partition_conf.dtsi b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_partition_conf.dtsi new file mode 100644 index 000000000000000..b209608a725b660 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/nrf9151dk_nrf9151_partition_conf.dtsi @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Default Flash planning for nRF9151dk_nrf9151. + * + * Zephyr build for nRF9151 with ARM TrustZone-M support, + * implies building Secure and Non-Secure Zephyr images. + * + * Secure image will be placed, by default, in flash0 + * (or in slot0, if MCUboot is present). + * Secure image will use sram0 for system memory. + * + * Non-Secure image will be placed in slot0_ns, and use + * sram0_ns for system memory. + * + * Note that the Secure image only requires knowledge of + * the beginning of the Non-Secure image (not its size). + */ + +&slot0_partition { + reg = <0x00010000 0x40000>; +}; + +&slot0_ns_partition { + reg = <0x00050000 0x35000>; +}; + +&slot1_partition { + reg = <0x00085000 0x40000>; +}; + +&slot1_ns_partition { + reg = <0x000c5000 0x35000>; +}; + +/* Default SRAM planning when building for nRF9151 with + * ARM TrustZone-M support + * - Lowest 88 kB SRAM allocated to Secure image (sram0_s). + * - 40 kB SRAM reserved for and used by the modem library + * (sram0_modem). This memory is Non-Secure. + * - Upper 128 kB allocated to Non-Secure image (sram0_ns). + * When building with TF-M, both sram0_modem and sram0_ns + * are allocated to the Non-Secure image. + */ + +&sram0_s { + reg = <0x20000000 DT_SIZE_K(88)>; +}; + +&sram0_modem { + reg = <0x20016000 DT_SIZE_K(40)>; +}; + +&sram0_ns { + reg = <0x20020000 DT_SIZE_K(128)>; +}; diff --git a/boards/arm/nrf9151dk_nrf9151/pre_dt_board.cmake b/boards/arm/nrf9151dk_nrf9151/pre_dt_board.cmake new file mode 100644 index 000000000000000..c8267afd1b470a1 --- /dev/null +++ b/boards/arm/nrf9151dk_nrf9151/pre_dt_board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2021 Linaro Limited +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "unique_unit_address_if_enabled" to handle the following overlaps: +# - flash-controller@39000 & kmu@39000 +# - power@5000 & clock@5000 +list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") diff --git a/boards/arm/nrf9160_innblue21/doc/index.rst b/boards/arm/nrf9160_innblue21/doc/index.rst index 628166c409ca8ec..c0f9e33cd759b03 100644 --- a/boards/arm/nrf9160_innblue21/doc/index.rst +++ b/boards/arm/nrf9160_innblue21/doc/index.rst @@ -95,7 +95,7 @@ Building Secure/Non-Secure Zephyr applications The process requires the following steps: 1. Build the Secure Zephyr application using ``-DBOARD=nrf9160_innblue21`` and - ``CONFIG_TRUSTED_EXECUTION_SECURE=y`` in the the application project configuration file. + ``CONFIG_TRUSTED_EXECUTION_SECURE=y`` in the application project configuration file. 2. Build the Non-Secure Zephyr application using ``-DBOARD=nrf9160_innblue21_ns``. 3. Merge the two binaries together. @@ -104,9 +104,6 @@ have to set the IDAU (SPU) configuration to allow Non-Secure access to all CPU resources utilized by the Non-Secure application firmware. SPU configuration shall take place before jumping to the Non-Secure application. -.. note:: - Trusted Firmware-M (TF-M) and building the ``ns`` target is not supported for this board. - Building a Secure only application ================================== diff --git a/boards/arm/nrf9160_innblue21/nrf9160_innblue21_common.dtsi b/boards/arm/nrf9160_innblue21/nrf9160_innblue21_common.dtsi index 0abfd4d6b9cce4c..0ec5de5dfb1af19 100644 --- a/boards/arm/nrf9160_innblue21/nrf9160_innblue21_common.dtsi +++ b/boards/arm/nrf9160_innblue21/nrf9160_innblue21_common.dtsi @@ -168,27 +168,23 @@ boot_partition: partition@0 { label = "mcuboot"; - reg = <0x00000000 0xc000>; + reg = <0x00000000 0x10000>; }; - slot0_partition: partition@c000 { + slot0_partition: partition@10000 { label = "image-0"; }; - slot0_ns_partition: partition@3e000 { + slot0_ns_partition: partition@50000 { label = "image-0-nonsecure"; }; - slot1_partition: partition@7e000 { + slot1_partition: partition@80000 { label = "image-1"; }; - slot1_ns_partition: partition@b0000 { + slot1_ns_partition: partition@c0000 { label = "image-1-nonsecure"; }; - scratch_partition: partition@f0000 { - label = "image-scratch"; - reg = <0x000f0000 0xa000>; - }; - storage_partition: partition@fa000 { + storage_partition: partition@f8000 { label = "storage"; - reg = <0x000fa000 0x00006000>; + reg = <0x000f8000 0x00008000>; }; }; }; diff --git a/boards/arm/nrf9160_innblue21/nrf9160_innblue21_ns.yaml b/boards/arm/nrf9160_innblue21/nrf9160_innblue21_ns.yaml index 096821d8364d0d1..4584ad0e6a49efd 100644 --- a/boards/arm/nrf9160_innblue21/nrf9160_innblue21_ns.yaml +++ b/boards/arm/nrf9160_innblue21/nrf9160_innblue21_ns.yaml @@ -7,7 +7,7 @@ toolchain: - xtools - zephyr ram: 128 -flash: 256 +flash: 192 supported: - i2c - pwm diff --git a/boards/arm/nrf9160_innblue21/nrf9160_innblue21_partition_conf.dtsi b/boards/arm/nrf9160_innblue21/nrf9160_innblue21_partition_conf.dtsi index d3a30abdc768760..2c64ba67a8a54e6 100644 --- a/boards/arm/nrf9160_innblue21/nrf9160_innblue21_partition_conf.dtsi +++ b/boards/arm/nrf9160_innblue21/nrf9160_innblue21_partition_conf.dtsi @@ -22,19 +22,19 @@ */ &slot0_partition { - reg = <0x0000c000 0x30000>; + reg = <0x00010000 0x40000>; }; &slot0_ns_partition { - reg = <0x0003e000 0x40000>; + reg = <0x00050000 0x30000>; }; &slot1_partition { - reg = <0x0007e000 0x30000>; + reg = <0x00080000 0x40000>; }; &slot1_ns_partition { - reg = <0x000b0000 0x40000>; + reg = <0x000c0000 0x30000>; }; /* Default SRAM planning when building for nRF9160 with diff --git a/boards/arm/nrf9160_innblue22/doc/index.rst b/boards/arm/nrf9160_innblue22/doc/index.rst index ce3eb35d60f8e23..0f2f83bcfe1e983 100644 --- a/boards/arm/nrf9160_innblue22/doc/index.rst +++ b/boards/arm/nrf9160_innblue22/doc/index.rst @@ -95,7 +95,7 @@ Building Secure/Non-Secure Zephyr applications The process requires the following steps: 1. Build the Secure Zephyr application using ``-DBOARD=nrf9160_innblue22`` and - ``CONFIG_TRUSTED_EXECUTION_SECURE=y`` in the the application project configuration file. + ``CONFIG_TRUSTED_EXECUTION_SECURE=y`` in the application project configuration file. 2. Build the Non-Secure Zephyr application using ``-DBOARD=nrf9160_innblue22_ns``. 3. Merge the two binaries together. @@ -104,9 +104,6 @@ have to set the IDAU (SPU) configuration to allow Non-Secure access to all CPU resources utilized by the Non-Secure application firmware. SPU configuration shall take place before jumping to the Non-Secure application. -.. note:: - Trusted Firmware-M (TF-M) and building the ``ns`` target is not supported for this board. - Building a Secure only application ================================== diff --git a/boards/arm/nrf9160_innblue22/nrf9160_innblue22_common.dtsi b/boards/arm/nrf9160_innblue22/nrf9160_innblue22_common.dtsi index 4582f975f5d17db..4738dd84a63481f 100644 --- a/boards/arm/nrf9160_innblue22/nrf9160_innblue22_common.dtsi +++ b/boards/arm/nrf9160_innblue22/nrf9160_innblue22_common.dtsi @@ -171,27 +171,24 @@ boot_partition: partition@0 { label = "mcuboot"; - reg = <0x00000000 0xc000>; + reg = <0x00000000 0x10000>; }; - slot0_partition: partition@c000 { + slot0_partition: partition@10000 { label = "image-0"; }; - slot0_ns_partition: partition@3e000 { + slot0_ns_partition: partition@50000 { label = "image-0-nonsecure"; }; - slot1_partition: partition@7e000 { + slot1_partition: partition@80000 { label = "image-1"; }; - slot1_ns_partition: partition@b0000 { + slot1_ns_partition: partition@c0000 { label = "image-1-nonsecure"; }; - scratch_partition: partition@f0000 { - label = "image-scratch"; - reg = <0x000f0000 0xa000>; - }; - storage_partition: partition@fa000 { + /* 0xf0000 to 0xf7fff reserved for TF-M partitions */ + storage_partition: partition@f8000 { label = "storage"; - reg = <0x000fa000 0x00006000>; + reg = <0x000f8000 0x00008000>; }; }; }; diff --git a/boards/arm/nrf9160_innblue22/nrf9160_innblue22_ns.yaml b/boards/arm/nrf9160_innblue22/nrf9160_innblue22_ns.yaml index 2ce0d6e3db22e06..0186c26a377db5e 100644 --- a/boards/arm/nrf9160_innblue22/nrf9160_innblue22_ns.yaml +++ b/boards/arm/nrf9160_innblue22/nrf9160_innblue22_ns.yaml @@ -7,7 +7,7 @@ toolchain: - xtools - zephyr ram: 128 -flash: 256 +flash: 192 supported: - i2c - pwm diff --git a/boards/arm/nrf9160_innblue22/nrf9160_innblue22_partition_conf.dtsi b/boards/arm/nrf9160_innblue22/nrf9160_innblue22_partition_conf.dtsi index 3588a6a7ce16c7c..b14640a02ecff9a 100644 --- a/boards/arm/nrf9160_innblue22/nrf9160_innblue22_partition_conf.dtsi +++ b/boards/arm/nrf9160_innblue22/nrf9160_innblue22_partition_conf.dtsi @@ -22,19 +22,19 @@ */ &slot0_partition { - reg = <0x0000c000 0x30000>; + reg = <0x00010000 0x40000>; }; &slot0_ns_partition { - reg = <0x0003e000 0x40000>; + reg = <0x00050000 0x30000>; }; &slot1_partition { - reg = <0x0007e000 0x30000>; + reg = <0x00080000 0x40000>; }; &slot1_ns_partition { - reg = <0x000b0000 0x40000>; + reg = <0x000c0000 0x30000>; }; /* Default SRAM planning when building for nRF9160 with diff --git a/boards/arm/nrf9160dk_nrf52840/doc/index.rst b/boards/arm/nrf9160dk_nrf52840/doc/index.rst index 752eee4c6fac89e..e16d6bc30e4e9d0 100644 --- a/boards/arm/nrf9160dk_nrf52840/doc/index.rst +++ b/boards/arm/nrf9160dk_nrf52840/doc/index.rst @@ -228,7 +228,7 @@ P0.17, P0.18, and P0.19 so that they are routed to nRF52840 pins P0.17, P0.20, and P0.15, respectively, add the following in the devicetree overlay in your application: -.. code-block:: none +.. code-block:: devicetree &nrf_interface_pins_0_2_routing { status = "okay"; @@ -237,7 +237,7 @@ application: And if you want to, for example, disable routing for the VCOM2 pins, add the following: -.. code-block:: none +.. code-block:: devicetree &vcom2_pins_routing { status = "disabled"; @@ -252,7 +252,7 @@ configure the signal routing between nRF9160 and nRF52840 on the nRF9160 DK. For example, to use ``uart1`` on both these chips for communication between them, add the following line in the overlays for applications on both sides: -.. code-block:: none +.. code-block:: devicetree #include diff --git a/boards/arm/nrf9160dk_nrf9160/Kconfig.defconfig b/boards/arm/nrf9160dk_nrf9160/Kconfig.defconfig index cd052dc7a205524..7d9046f63b500de 100644 --- a/boards/arm/nrf9160dk_nrf9160/Kconfig.defconfig +++ b/boards/arm/nrf9160dk_nrf9160/Kconfig.defconfig @@ -8,21 +8,6 @@ if BOARD_NRF9160DK_NRF9160 || BOARD_NRF9160DK_NRF9160_NS config BOARD default "nrf9160dk_nrf9160" -# By default, if we build for a Non-Secure version of the board, -# enable building with TF-M as the Secure Execution Environment. -config BUILD_WITH_TFM - default y if BOARD_NRF9160DK_NRF9160_NS - -if BUILD_WITH_TFM - -# By default, if we build with TF-M, instruct build system to -# flash the combined TF-M (Secure) & Zephyr (Non Secure) image -config TFM_FLASH_MERGED_BINARY - bool - default y - -endif # BUILD_WITH_TFM - # For the secure version of the board the firmware is linked at the beginning # of the flash, or into the code-partition defined in DT if it is intended to # be loaded by MCUboot. If the secure firmware is to be combined with a non- diff --git a/boards/arm/nrf9161dk_nrf9161/Kconfig.defconfig b/boards/arm/nrf9161dk_nrf9161/Kconfig.defconfig index 2674e87cad49d72..ea7150ede5fe572 100644 --- a/boards/arm/nrf9161dk_nrf9161/Kconfig.defconfig +++ b/boards/arm/nrf9161dk_nrf9161/Kconfig.defconfig @@ -8,21 +8,6 @@ if BOARD_NRF9161DK_NRF9161 || BOARD_NRF9161DK_NRF9161_NS config BOARD default "nrf9161dk_nrf9161" -# By default, if we build for a Non-Secure version of the board, -# enable building with TF-M as the Secure Execution Environment. -config BUILD_WITH_TFM - default y if BOARD_NRF9161DK_NRF9161_NS - -if BUILD_WITH_TFM - -# By default, if we build with TF-M, instruct build system to -# flash the combined TF-M (Secure) & Zephyr (Non Secure) image -config TFM_FLASH_MERGED_BINARY - bool - default y - -endif # BUILD_WITH_TFM - # For the secure version of the board the firmware is linked at the beginning # of the flash, or into the code-partition defined in DT if it is intended to # be loaded by MCUboot. If the secure firmware is to be combined with a non- diff --git a/boards/arm/nrf9161dk_nrf9161/doc/index.rst b/boards/arm/nrf9161dk_nrf9161/doc/index.rst index 559288b06aabd0b..18b214a7fde9188 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/nrf9161dk_nrf9161/nrf9161dk_nrf9161_common.dtsi b/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_common.dtsi index a6aeccf34b99d51..8168a8317e417e7 100644 --- a/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_common.dtsi +++ b/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_common.dtsi @@ -230,16 +230,12 @@ arduino_spi: &spi3 { slot0_ns_partition: partition@50000 { label = "image-0-nonsecure"; }; - slot1_partition: partition@80000 { + slot1_partition: partition@85000 { label = "image-1"; }; - slot1_ns_partition: partition@c0000 { + slot1_ns_partition: partition@c5000 { label = "image-1-nonsecure"; }; - scratch_partition: partition@f0000 { - label = "image-scratch"; - reg = <0x000f0000 0xa000>; - }; storage_partition: partition@fa000 { label = "storage"; reg = <0x000fa000 0x00006000>; diff --git a/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_partition_conf.dtsi b/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_partition_conf.dtsi index 80b4c5f6b3abf36..9e378cb94e060aa 100644 --- a/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_partition_conf.dtsi +++ b/boards/arm/nrf9161dk_nrf9161/nrf9161dk_nrf9161_partition_conf.dtsi @@ -26,15 +26,15 @@ }; &slot0_ns_partition { - reg = <0x00050000 0x30000>; + reg = <0x00050000 0x35000>; }; &slot1_partition { - reg = <0x00080000 0x40000>; + reg = <0x00085000 0x40000>; }; &slot1_ns_partition { - reg = <0x000c0000 0x30000>; + reg = <0x000c5000 0x35000>; }; /* Default SRAM planning when building for nRF9161 with diff --git a/boards/arm/nucleo_c031c6/doc/index.rst b/boards/arm/nucleo_c031c6/doc/index.rst index fcf134f497e4d35..3e28230cba2d778 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 821470b20c048f9..a6f104398c75e4d 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 b7adddf65093836..ccfb1540f26f3b4 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 a9676350eb4c5f5..66ad80adeedc051 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 d3afe9e59e33afb..ac1659dfc390deb 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 5d7e214bd1bc28c..50a96e3fed4a214 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 f1f0df58e1083e6..9ff09e28770bb14 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 b717c75b58a59e8..8f67b04ad626495 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 d44ee9e51d733eb..64824e787ebab35 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 c844ef9ab9c58f6..aa01b1ad3ad4cb8 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 c5702552ca8a1f3..23c979e49aaa15d 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 ee7d652d1c55a17..908dfbf9a2a20b6 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 b00213ced7e74e2..7979171472e1c35 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 3b20f6a7a0cfe7c..e65e9194ad4d7b1 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 a835d963d2b79f5..37d62c043107cf6 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 e03b91c0ad92f92..6afc2996acc6ced 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 b0a8f4314623035..697324e84fab9cb 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 000000000000000..f15e218e16167ee --- /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 000000000000000..1dfff0c9d441107 --- /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 000000000000000..9072fa9147676db --- /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 000000000000000..6335e34584a729a --- /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 000000000000000..0778ea20cfd21e1 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 000000000000000..f0c40595f3a41c3 --- /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 000000000000000..e3a2e65ad3b23a5 --- /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 000000000000000..94cdcb739143da9 --- /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 000000000000000..345694efd8088b1 --- /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 000000000000000..599f7e840124a44 --- /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 ef9fdf9d20e6d12..8bc083bcc3f6e58 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 2616a3b6dccc3fb..aa13ddb7f200906 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 bed503e2609c3f6..7eca2af1edaa196 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 6f933b08546150b..93a10b553ab865c 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 056bb298c4f43ff..8908ed5ce43c6e0 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 f6aebe8f12bb0c2..424f1ade9f77365 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 76b2369280e3772..9c510e49864abff 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 66e6a9ba87da674..9627b094fc00668 100644 --- a/boards/arm/nucleo_g0b1re/doc/index.rst +++ b/boards/arm/nucleo_g0b1re/doc/index.rst @@ -56,7 +56,7 @@ Nucleo G0B1RE provides the following hardware components: - HDMI_CEC(1) - USB 2.0 FS device (crystal-less) and host controller(1) - USB Type-C Power Delivery controller -- CAN-FD(2) +- CAN FD(2) - GPIO (up to 94) with external interrupt capability - Tamper Pins(3) - 12-bit ADC with 16 channels @@ -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 e74550e497fbcb8..337d73ebe89ccfb 100644 --- a/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts +++ b/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts @@ -61,6 +61,7 @@ &clk_hsi48 { status = "okay"; + crs-usb-sof; }; &pll { @@ -186,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"; @@ -213,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 bc267274401d5ef..e2389efdbb74a37 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/Kconfig.defconfig b/boards/arm/nucleo_g431rb/Kconfig.defconfig index 993bee2f79602dd..62c8e061965f24a 100644 --- a/boards/arm/nucleo_g431rb/Kconfig.defconfig +++ b/boards/arm/nucleo_g431rb/Kconfig.defconfig @@ -12,8 +12,4 @@ config SPI_STM32_INTERRUPT default y depends on SPI -# LPTIM clocked by LSE, force tick freq to 4096 for tick accuracy -config SYS_CLOCK_TICKS_PER_SEC - default 4096 if STM32_LPTIM_TIMER - endif # BOARD_NUCLEO_G431RB diff --git a/boards/arm/nucleo_g431rb/doc/index.rst b/boards/arm/nucleo_g431rb/doc/index.rst index dfe1b680fe6eb95..0359a29b231e9f1 100644 --- a/boards/arm/nucleo_g431rb/doc/index.rst +++ b/boards/arm/nucleo_g431rb/doc/index.rst @@ -119,6 +119,8 @@ The Zephyr nucleo_g431rb board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | SPI | on-chip | spi | +-----------+------------+-------------------------------------+ +| RNG | on-chip | rng | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. @@ -132,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 2ab18ec736050f9..9303087c1dce5c4 100644 --- a/boards/arm/nucleo_g431rb/nucleo_g431rb.dts +++ b/boards/arm/nucleo_g431rb/nucleo_g431rb.dts @@ -63,6 +63,10 @@ status = "okay"; }; +&clk_hsi48 { + status = "okay"; +}; + &clk_hse { clock-frequency = ; status = "okay"; @@ -86,6 +90,12 @@ apb2-prescaler = <1>; }; +&rng { + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x04000000>, + <&rcc STM32_SRC_HSI48 CLK48_SEL(0)>; + status = "okay"; +}; + &usart1 { pinctrl-0 = <&usart1_tx_pc4 &usart1_rx_pc5>; pinctrl-names = "default"; @@ -138,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.yaml b/boards/arm/nucleo_g431rb/nucleo_g431rb.yaml index 642b8a68c496b17..71ca5707ac58b3e 100644 --- a/boards/arm/nucleo_g431rb/nucleo_g431rb.yaml +++ b/boards/arm/nucleo_g431rb/nucleo_g431rb.yaml @@ -19,6 +19,7 @@ supported: - usb device - counter - spi + - rng - dac - watchdog vendor: st diff --git a/boards/arm/nucleo_g474re/doc/index.rst b/boards/arm/nucleo_g474re/doc/index.rst index 437668ed42eb1da..87fca388905a452 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 33c071d0adb64c6..8a87f6e0d01cbe7 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 9b6f880ac4c1753..7d1ac5c5b5aeae1 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 7b5c327e97d83b6..26f4491a7ad0672 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 d27c7367aca122e..44a87bb512930ac 100644 --- a/boards/arm/nucleo_h723zg/doc/index.rst +++ b/boards/arm/nucleo_h723zg/doc/index.rst @@ -71,7 +71,7 @@ Nucleo H723ZG provides the following hardware components: - UART(4) - USB OTG Full Speed and High Speed(1) - USB OTG Full Speed(1) -- CAN-FD(2) +- CAN FD(2) - SAI(2) - SPDIF_Rx(4) - HDMI_CEC(1) @@ -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 af0ee0186ec6fad..e6cb6e242cddffb 100644 --- a/boards/arm/nucleo_h743zi/doc/index.rst +++ b/boards/arm/nucleo_h743zi/doc/index.rst @@ -73,7 +73,7 @@ Nucleo H743ZI provides the following hardware components: - UART(4) - USB OTG Full Speed and High Speed(1) - USB OTG Full Speed(1) -- CAN-FD(2) +- CAN FD(2) - SAI(2) - SPDIF_Rx(4) - HDMI_CEC(1) @@ -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 f93964479e232c7..ad88d87f0599f35 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 f419c17ccc42382..36c4b80bc58add2 100644 --- a/boards/arm/nucleo_h745zi_q/doc/index.rst +++ b/boards/arm/nucleo_h745zi_q/doc/index.rst @@ -75,7 +75,7 @@ Nucleo H745ZI-Q provides the following hardware components: - UART(4) - USB OTG Full Speed and High Speed(1) - USB OTG Full Speed(1) -- CAN-FD(2) +- CAN FD(2) - SAI(2) - SPDIF_Rx(4) - HDMI_CEC(1) @@ -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_m7.dts b/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q_m7.dts index d63b4ff8a58edf6..184232867bb52a0 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 41a9af209548845..eab88c9952a7a4d 100644 --- a/boards/arm/nucleo_h753zi/doc/index.rst +++ b/boards/arm/nucleo_h753zi/doc/index.rst @@ -73,7 +73,7 @@ Nucleo H753ZI provides the following hardware components: - UART(4) - USB OTG Full Speed and High Speed(1) - USB OTG Full Speed(1) -- CAN-FD(2) +- CAN FD(2) - SAI(2) - SPDIF_Rx(4) - HDMI_CEC(1) @@ -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 922423e3669edc3..ec43ace7dcb5cf3 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 92dfbd98deb313a..1144f13e731406f 100644 --- a/boards/arm/nucleo_h7a3zi_q/doc/index.rst +++ b/boards/arm/nucleo_h7a3zi_q/doc/index.rst @@ -69,7 +69,7 @@ Nucleo H7A3ZI-Q provides the following hardware components: - USART(5) - UART(5) - USB OTG Full Speed and High Speed(1) -- CAN-FD(2) +- CAN FD(2) - SAI(2) - SPDIF_Rx(4) - HDMI_CEC(1) @@ -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 9b815ede4de2cf3..04fc12c53f32b46 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 eb1f6e253874ff4..da0fcaa271e3ced 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 33f84b14e6cc018..ba448176fcad9b1 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/Kconfig.defconfig b/boards/arm/nucleo_l073rz/Kconfig.defconfig index 66c2d366181bcd6..6a73209134a8f85 100644 --- a/boards/arm/nucleo_l073rz/Kconfig.defconfig +++ b/boards/arm/nucleo_l073rz/Kconfig.defconfig @@ -12,8 +12,4 @@ config SPI_STM32_INTERRUPT default y depends on SPI -# LPTIM clocked by LSI, force tick freq to 4000 for tick accuracy -config SYS_CLOCK_TICKS_PER_SEC - default 4000 if STM32_LPTIM_TIMER - endif # BOARD_NUCLEO_L073RZ diff --git a/boards/arm/nucleo_l073rz/doc/index.rst b/boards/arm/nucleo_l073rz/doc/index.rst index de662f5b14ff971..a828a5b70eb69d6 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 b5cf07203a6d53c..93571670b7dba0b 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 2595144e730de99..020beb6583f4e0c 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 007ae04379dc7f7..3485d01cba1d6fa 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 94d6f6f20f0ac6c..b054c472f22603a 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 da2660417c01f24..6e86a44cee0ccf6 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 cfbf949df57b5eb..10dff333643841e 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 b39a87345e57984..573c121dfd1a1e0 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 43f6e1fdb4cdd36..49d011b88467510 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 79c7caca7bbf670..7e61d9f89076796 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 037f4a5fd14bc01..0def9a56111a2ed 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 9adb38a2c59a58c..b132403ce2adbd3 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 d170d283e99d3b9..260ecca2707204a 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 51675477af41367..65a2df527a9caa5 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 0de2c364ecf8a52..bbb547130d86a50 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 c79a4b7b4e75ea0..7c2da293e200568 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 f877be5c1685227..f6e96c635171d5f 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/Kconfig.defconfig b/boards/arm/nucleo_wb55rg/Kconfig.defconfig index 1a7ffcff0efc323..66c77220d3adc94 100644 --- a/boards/arm/nucleo_wb55rg/Kconfig.defconfig +++ b/boards/arm/nucleo_wb55rg/Kconfig.defconfig @@ -13,8 +13,4 @@ choice BT_HCI_BUS_TYPE depends on BT endchoice -# LPTIM clocked by LSE, force tick freq to 4096 for tick accuracy -config SYS_CLOCK_TICKS_PER_SEC - default 4096 if STM32_LPTIM_TIMER - endif # BOARD_NUCLEO_WB55RG diff --git a/boards/arm/nucleo_wb55rg/board.cmake b/boards/arm/nucleo_wb55rg/board.cmake index 83fd477865f0d5d..75762ef577e8109 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 b92c921df38fde7..21806ca24af074d 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"; @@ -202,6 +202,10 @@ zephyr_udc0: &usb { status = "okay"; }; +&aes1 { + status = "okay"; +}; + &flash0 { partitions { compatible = "fixed-partitions"; diff --git a/boards/arm/nucleo_wba52cg/Kconfig.defconfig b/boards/arm/nucleo_wba52cg/Kconfig.defconfig index 36f0e77818b0e21..dfdac1bba98b6fe 100644 --- a/boards/arm/nucleo_wba52cg/Kconfig.defconfig +++ b/boards/arm/nucleo_wba52cg/Kconfig.defconfig @@ -13,8 +13,4 @@ config SPI_STM32_INTERRUPT default y depends on SPI -# LPTIM clocked by LSE, force tick freq to 4096 for tick accuracy -config SYS_CLOCK_TICKS_PER_SEC - default 4096 if STM32_LPTIM_TIMER - endif # BOARD_NUCLEO_WBA52CG diff --git a/boards/arm/nucleo_wba52cg/board.cmake b/boards/arm/nucleo_wba52cg/board.cmake index 50f543d4e6ab2f9..27c19f19b00d199 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/doc/nucleo_wba52cg.rst b/boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst index 5f13e9fd0b8665f..db45d48a7fa72dc 100644 --- a/boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst +++ b/boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst @@ -222,12 +222,32 @@ Default settings are 115200 8N1. Programming and Debugging ************************* +Nucleo WBA52CG 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_wba52cg/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 ======== -Nucleo WBA52CG board includes an ST-LINK/V3 embedded debug tool interface. -For now, only STM32CubeProgrammer is available for flashing. It is configured -as flashing tool by default. +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 WBA52CG ----------------------------------------- @@ -244,6 +264,21 @@ 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_wba52cg + :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 @@ -265,3 +300,6 @@ For that: .. _STM32WBA52CG reference manual: https://www.st.com/resource/en/reference_manual/rm0493-multiprotocol-wireless-bluetooth-lowenergy-armbased-32bit-mcu-stmicroelectronics.pdf + +.. _OpenOCD official Github mirror: + https://github.com/openocd-org/openocd/commit/870769b0ba9f4dae6ada9d8b1a40d75bd83aaa06 diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts index 0a6e03c7d6cffed..67bc009bd8a2de7 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>; @@ -82,6 +86,13 @@ status = "okay"; }; +&rtc { + status = "okay"; + clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00200000>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; + prescaler = <32768>; +}; + &usart1 { pinctrl-0 = <&usart1_tx_pb12 &usart1_rx_pa8>; pinctrl-names = "default"; @@ -89,6 +100,13 @@ 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>; @@ -111,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.yaml b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml index a5eb79afc423fbc..8e075b44ae12dcb 100644 --- a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml @@ -15,6 +15,7 @@ supported: - arduino_gpio - arduino_i2c - arduino_spi + - counter ram: 128 flash: 1024 vendor: st diff --git a/boards/arm/nucleo_wba52cg/support/openocd.cfg b/boards/arm/nucleo_wba52cg/support/openocd.cfg new file mode 100644 index 000000000000000..7c785bec412853c --- /dev/null +++ b/boards/arm/nucleo_wba52cg/support/openocd.cfg @@ -0,0 +1,24 @@ +# Note: Using OpenOCD using nucloe_wba52cg requires using STMicroelectronics +# 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] diff --git a/boards/arm/nucleo_wba55cg/Kconfig.board b/boards/arm/nucleo_wba55cg/Kconfig.board new file mode 100644 index 000000000000000..44bb0e5dcd80583 --- /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 000000000000000..ed24776ee4e4b1b --- /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 000000000000000..619cebea62a43b9 --- /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 000000000000000..50f543d4e6ab2f9 --- /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 000000000000000..67c7d351e99626f 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 000000000000000..2ea660da1f16f8e --- /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 000000000000000..3a2ad07c1b0cacf --- /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 000000000000000..0f435e29c75e0d1 --- /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 000000000000000..2c523d8801957aa --- /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 000000000000000..247de974f3963e7 --- /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/Kconfig.defconfig b/boards/arm/nucleo_wl55jc/Kconfig.defconfig index 197453cc03e3742..981e20f030646f2 100644 --- a/boards/arm/nucleo_wl55jc/Kconfig.defconfig +++ b/boards/arm/nucleo_wl55jc/Kconfig.defconfig @@ -8,7 +8,4 @@ if BOARD_NUCLEO_WL55JC config BOARD default "nucleo_wl55jc" -config SYS_CLOCK_TICKS_PER_SEC - default 4000 if STM32_LPTIM_TIMER - endif # BOARD_NUCLEO_WL55JC diff --git a/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts b/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts index 48822f2fe1329f2..e83f45452ddd8ac 100644 --- a/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts +++ b/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" #include / { @@ -19,7 +20,7 @@ zephyr,shell-uart = &lpuart1; zephyr,sram = &sram0; zephyr,flash = &flash0; - zephyr,code-partition = &flash0; + zephyr,code-partition = &slot0_partition; }; leds: leds { @@ -74,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"; @@ -190,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/nucleo_wl55jc/st_morpho_connector.dtsi b/boards/arm/nucleo_wl55jc/st_morpho_connector.dtsi new file mode 100644 index 000000000000000..c2e2a06bb3eb8cd --- /dev/null +++ b/boards/arm/nucleo_wl55jc/st_morpho_connector.dtsi @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , /* shared with SWD connected to STLINK */ + , /* shared with SWD connected to STLINK */ + , + , + , + , + , + , + , + , + , + , + + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB7=ON, SB2=OFF, SB6=OFF */ + , + , /* SB9=ON, SB4=OFF, SB10=OFF */ + ; + }; +}; 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 8aff684b1a9a8a5..b6b8f3eb5083d57 100644 --- a/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi +++ b/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi @@ -24,4 +24,29 @@ ; }; }; + + /* CAN TX/RX --> PJ10/PJ11 */ + canfd0_default: canfd0_default { + group0 { + pinmux = , + ; + }; + }; + + /* EMAC multi-function pins for MDIO, TX, REFCLK, RX pins */ + emac_default: emac_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 860ca7579f11aee..da3350d9494d04d 100644 --- a/boards/arm/numaker_pfm_m467/numaker_pfm_m467.dts +++ b/boards/arm/numaker_pfm_m467/numaker_pfm_m467.dts @@ -29,6 +29,7 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; + zephyr,canbus = &canfd0; }; @@ -108,3 +109,17 @@ pinctrl-names = "default"; status = "okay"; }; + +&canfd0 { + bus-speed = <125000>; + bus-speed-data = <1000000>; + pinctrl-0 = <&canfd0_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&emac { + pinctrl-0 = <&emac_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/arm/olimex_lora_stm32wl_devkit/doc/olimex_lora_stm32wl_devkit.rst b/boards/arm/olimex_lora_stm32wl_devkit/doc/olimex_lora_stm32wl_devkit.rst index be63585fbb1dc30..cd7d3436296d709 100644 --- a/boards/arm/olimex_lora_stm32wl_devkit/doc/olimex_lora_stm32wl_devkit.rst +++ b/boards/arm/olimex_lora_stm32wl_devkit/doc/olimex_lora_stm32wl_devkit.rst @@ -126,7 +126,7 @@ CON1 pin header. :goals: build flash Run a serial terminal to connect with your board. By default, ``usart1`` is -accessible via the the built-in USB to UART converter. +accessible via the built-in USB to UART converter. .. code-block:: console 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 b24649edb71afc5..6d26b7c3f19b4f4 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 de1bd72e6d0f57d..d8e520eda35298e 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 4643c740884982a..03ebb8bf8e2387a 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 000000000000000..a582b3cc819ea14 --- /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 000000000000000..e4f583984590e1a --- /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 000000000000000..3fcaaf39e563cb2 --- /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 000000000000000..47c02a95b7f7be2 --- /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 000000000000000..e8a33e8c7bf1298 --- /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 000000000000000..314252de2399ed2 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 000000000000000..95b8b94444b9873 --- /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/pan1783_cpuapp_common-pinctrl.dtsi b/boards/arm/pan1783/pan1783_cpuapp_common-pinctrl.dtsi new file mode 100644 index 000000000000000..cdafbaf2cdc650b --- /dev/null +++ b/boards/arm/pan1783/pan1783_cpuapp_common-pinctrl.dtsi @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + i2c1_default: i2c1_default { + group1 { + psels = , + ; + }; + }; + + i2c1_sleep: i2c1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart0_default: uart0_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + pwm0_default: pwm0_default { + group1 { + psels = ; + }; + }; + + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; + + qspi_default: qspi_default { + group1 { + psels = , + , + , + , + , + ; + nordic,drive-mode = ; + }; + }; + + qspi_sleep: qspi_sleep { + group1 { + psels = , + , + , + , + ; + low-power-enable; + }; + group2 { + psels = ; + low-power-enable; + bias-pull-up; + }; + }; + + uart1_default: uart1_default { + group1 { + psels = ; + }; + group2 { + psels = ; + bias-pull-up; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + spi4_default: spi4_default { + group1 { + psels = , + , + ; + }; + }; + + spi4_sleep: spi4_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + +}; diff --git a/boards/arm/pan1783/pan1783_cpuapp_common.dtsi b/boards/arm/pan1783/pan1783_cpuapp_common.dtsi new file mode 100644 index 000000000000000..77d093a5d4003ee --- /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 000000000000000..6eb6792c9969598 --- /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/pan1783_cpunet-pinctrl.dtsi b/boards/arm/pan1783/pan1783_cpunet-pinctrl.dtsi new file mode 100644 index 000000000000000..8a82e07406eef0f --- /dev/null +++ b/boards/arm/pan1783/pan1783_cpunet-pinctrl.dtsi @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + spi0_default: spi0_default { + group1 { + psels = , + , + ; + }; + }; + + spi0_sleep: spi0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + +}; diff --git a/boards/arm/pan1783/pan1783_cpunet_common.dtsi b/boards/arm/pan1783/pan1783_cpunet_common.dtsi new file mode 100644 index 000000000000000..5b5e7735e4a4c38 --- /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 000000000000000..529051ec62943fb --- /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/pan1783_evb_cpuapp.dts b/boards/arm/pan1783/pan1783_evb_cpuapp.dts new file mode 100644 index 000000000000000..54f71dd87d5b20d --- /dev/null +++ b/boards/arm/pan1783/pan1783_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 PAN1783 EVB (NRF5340) Application"; + compatible = "panasonic,pan1783-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/pan1783_evb_cpuapp.yaml b/boards/arm/pan1783/pan1783_evb_cpuapp.yaml new file mode 100644 index 000000000000000..a0242b83252b036 --- /dev/null +++ b/boards/arm/pan1783/pan1783_evb_cpuapp.yaml @@ -0,0 +1,21 @@ +identifier: pan1783_evb_cpuapp +name: PAN1783-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/pan1783_evb_cpuapp_defconfig b/boards/arm/pan1783/pan1783_evb_cpuapp_defconfig new file mode 100644 index 000000000000000..b709d16dc54d142 --- /dev/null +++ b/boards/arm/pan1783/pan1783_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_PAN1783_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/pan1783_evb_cpunet.dts b/boards/arm/pan1783/pan1783_evb_cpunet.dts new file mode 100644 index 000000000000000..7063e53af46d504 --- /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/pan1783_evb_cpunet.yaml b/boards/arm/pan1783/pan1783_evb_cpunet.yaml new file mode 100644 index 000000000000000..725fae94cc5bf14 --- /dev/null +++ b/boards/arm/pan1783/pan1783_evb_cpunet.yaml @@ -0,0 +1,14 @@ +identifier: pan1783_evb_cpunet +name: PAN1783-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/pan1783_evb_cpunet_defconfig b/boards/arm/pan1783/pan1783_evb_cpunet_defconfig new file mode 100644 index 000000000000000..f83ea00045534e5 --- /dev/null +++ b/boards/arm/pan1783/pan1783_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_PAN1783_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/pan1783_shared_sram_planning_conf.dtsi b/boards/arm/pan1783/pan1783_shared_sram_planning_conf.dtsi new file mode 100644 index 000000000000000..9e2b673f84a58f6 --- /dev/null +++ b/boards/arm/pan1783/pan1783_shared_sram_planning_conf.dtsi @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Default shared SRAM planning when building for PAN1783 EVB. + * This file is included by both nRF5340 CPUAPP (Application MCU) + * and nRF5340 CPUNET (Network MCU). + * - 64 kB SRAM allocated as Shared memory (sram0_shared) + * - Region defined after the image SRAM of Application MCU + */ + +/ { + chosen { + /* shared memory reserved for the inter-processor communication */ + zephyr,ipc_shm = &sram0_shared; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + sram0_shared: memory@20070000 { + /* SRAM allocated to shared memory */ + reg = <0x20070000 0x10000>; + }; + }; +}; diff --git a/boards/arm/pan1783/pan1783a_evb_cpuapp.dts b/boards/arm/pan1783/pan1783a_evb_cpuapp.dts new file mode 100644 index 000000000000000..29f0dcb796c4d93 --- /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 000000000000000..2a89c3f1f375d7c --- /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 000000000000000..2f624e1db0cf5f4 --- /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 000000000000000..9cd0409a4326946 --- /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 000000000000000..2dd985f61ff42f7 --- /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 000000000000000..3e44ff7338cfc90 --- /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 000000000000000..aba6e9281e2111d --- /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 000000000000000..0bc70dab27375a2 --- /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 000000000000000..f58bdce8bfc0c03 --- /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 000000000000000..1b345aaa94526be --- /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 000000000000000..98a2f2908de226a --- /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 000000000000000..3ba18cd433a00c3 --- /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/pre_dt_board.cmake b/boards/arm/pan1783/pre_dt_board.cmake new file mode 100644 index 000000000000000..b84665fcf51e99e --- /dev/null +++ b/boards/arm/pan1783/pre_dt_board.cmake @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "unique_unit_address_if_enabled" to handle the following overlaps: +# - flash-controller@39000 & kmu@39000 +# - power@5000 & clock@5000 +# - /reserved-memory/image@20000000 & /reserved-memory/image_s@20000000 +list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") diff --git a/boards/arm/pandora_stm32l475/doc/index.rst b/boards/arm/pandora_stm32l475/doc/index.rst index 62a903faf78441c..76da038e9ec4b0b 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/pinnacle_100_dvk/pinnacle_100_dvk.dts b/boards/arm/pinnacle_100_dvk/pinnacle_100_dvk.dts index 19f9e6ff41ed221..b50c526be4ce8b5 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 8aa63a89a575671..3f203f2adbc5cce 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 b/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig index 875762de8282471..caf06f347d5f64f 100644 --- a/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig +++ b/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig @@ -43,7 +43,7 @@ config DOMAIN_CPUNET_BOARD 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_rpmsg on the nRF5340_cpunet for + another board. For example hci_ipc on the nRF5340_cpunet for Bluetooth applications. endif # BOARD_RAYTAC_MDBT53_DB_40_NRF5340_CPUAPP || BOARD_RAYTAC_MDBT53_DB_40_NRF5340_CPUAPP_NS diff --git a/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig.defconfig b/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig.defconfig index a0a59dc13ab8dd5..fb5a6b85630628e 100644 --- a/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig.defconfig +++ b/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig.defconfig @@ -8,21 +8,6 @@ if BOARD_RAYTAC_MDBT53_DB_40_NRF5340_CPUAPP || BOARD_RAYTAC_MDBT53_DB_40_NRF534 config BOARD default "raytac_mdbt53_db_40_nrf5340_cpuapp" -# By default, if we build for a Non-Secure version of the board, -# enable building with TF-M as the Secure Execution Environment. -config BUILD_WITH_TFM - default n if BOARD_RAYTAC_MDBT53_DB_40_NRF5340_CPUAPP_NS - -if BUILD_WITH_TFM - -# By default, if we build with TF-M, instruct build system to -# flash the combined TF-M (Secure) & Zephyr (Non Secure) image -config TFM_FLASH_MERGED_BINARY - bool - default n - -endif # BUILD_WITH_TFM - # Code Partition: # # For the secure version of the board the firmware is linked at the beginning @@ -85,11 +70,12 @@ config MBOX_NRFX_IPC if BOARD_RAYTAC_MDBT53_DB_40_NRF5340_CPUAPP || BOARD_RAYTAC_MDBT53_DB_40_NRF5340_CPUAPP_NS choice BT_HCI_BUS_TYPE - default BT_RPMSG if BT + default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE - default 4096 if BT_RPMSG +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_mdbt53_db_40_nrf5340/doc/index.rst b/boards/arm/raytac_mdbt53_db_40_nrf5340/doc/index.rst index a63714a53494aa6..bcff494f91b1b41 100644 --- a/boards/arm/raytac_mdbt53_db_40_nrf5340/doc/index.rst +++ b/boards/arm/raytac_mdbt53_db_40_nrf5340/doc/index.rst @@ -24,9 +24,6 @@ The raytac_mdbt53_db_40_nrf5340_cpuapp build target provides support for the app core on the nRF5340 SoC. The raytac_mdbt53_db_40_nrf5340_cpuapp build target provides support for the network core on the nRF5340 SoC. -.. note:: - Trusted Firmware-M (TF-M) and building the ``ns`` target is not supported for this board. - nRF5340 SoC provides support for the following devices: * :abbr:`ADC (Analog to Digital Converter)` diff --git a/boards/arm/raytac_mdbt53_db_40_nrf5340/raytac_mdbt53_db_40_nrf5340_cpuapp_common-pinctrl.dtsi b/boards/arm/raytac_mdbt53_db_40_nrf5340/raytac_mdbt53_db_40_nrf5340_cpuapp_common-pinctrl.dtsi index dabb02cc3c4735a..3a3e39f824f408f 100644 --- a/boards/arm/raytac_mdbt53_db_40_nrf5340/raytac_mdbt53_db_40_nrf5340_cpuapp_common-pinctrl.dtsi +++ b/boards/arm/raytac_mdbt53_db_40_nrf5340/raytac_mdbt53_db_40_nrf5340_cpuapp_common-pinctrl.dtsi @@ -41,18 +41,19 @@ uart1_default: uart1_default { group1 { - psels = ; - }; - group2 { - psels = ; - bias-pull-up; + psels = , + , + , + ; }; }; uart1_sleep: uart1_sleep { group1 { psels = , - ; + , + , + ; low-power-enable; }; }; diff --git a/boards/arm/raytac_mdbt53_db_40_nrf5340/raytac_mdbt53_db_40_nrf5340_cpuapp_common.dts b/boards/arm/raytac_mdbt53_db_40_nrf5340/raytac_mdbt53_db_40_nrf5340_cpuapp_common.dts index 21cc368f959d22a..3af7de1f17edf30 100644 --- a/boards/arm/raytac_mdbt53_db_40_nrf5340/raytac_mdbt53_db_40_nrf5340_cpuapp_common.dts +++ b/boards/arm/raytac_mdbt53_db_40_nrf5340/raytac_mdbt53_db_40_nrf5340_cpuapp_common.dts @@ -14,7 +14,7 @@ zephyr,uart-mcumgr = &uart0; zephyr,bt-mon-uart = &uart0; zephyr,bt-c2h-uart = &uart0; - zephyr,bt-hci-rpmsg-ipc = &ipc0; + zephyr,bt-hci-ipc = &ipc0; nordic,802154-spinel-ipc = &ipc0; zephyr,ieee802154 = &ieee802154; }; diff --git a/boards/arm/raytac_mdbt53_db_40_nrf5340/raytac_mdbt53_db_40_nrf5340_cpunet.dts b/boards/arm/raytac_mdbt53_db_40_nrf5340/raytac_mdbt53_db_40_nrf5340_cpunet.dts index b10848e4a284ca0..f9c834ef228d9c0 100644 --- a/boards/arm/raytac_mdbt53_db_40_nrf5340/raytac_mdbt53_db_40_nrf5340_cpunet.dts +++ b/boards/arm/raytac_mdbt53_db_40_nrf5340/raytac_mdbt53_db_40_nrf5340_cpunet.dts @@ -22,7 +22,7 @@ zephyr,sram = &sram1; zephyr,flash = &flash1; zephyr,code-partition = &slot0_partition; - zephyr,bt-hci-rpmsg-ipc = &ipc0; + zephyr,bt-hci-ipc = &ipc0; }; /* These aliases are provided for compatibility with samples */ diff --git a/boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig b/boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig index 5443d2b8486f995..02b44de6198a065 100644 --- a/boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig +++ b/boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig @@ -43,7 +43,7 @@ config DOMAIN_CPUNET_BOARD 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_rpmsg on the nRF5340_cpunet for + another board. For example hci_ipc on the nRF5340_cpunet for Bluetooth applications. endif # BOARD_RAYTAC_MDBT53V_DB_40_NRF5340_CPUAPP || BOARD_RAYTAC_MDBT53V_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 54c3d6cccf0ad57..fd3e5210d287b72 100644 --- a/boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig.defconfig +++ b/boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig.defconfig @@ -7,20 +7,6 @@ if BOARD_RAYTAC_MDBT53V_DB_40_NRF5340_CPUAPP || BOARD_RAYTAC_MDBT53V_DB_40_NRF5 config BOARD default "raytac_mdbt53v_db_40_nrf5340_cpuapp" if BOARD_RAYTAC_MDBT53V_DB_40_NRF5340_CPUAPP || BOARD_RAYTAC_MDBT53V_DB_40_NRF5340_CPUAPP_NS -# By default, if we build for a Non-Secure version of the board, -# enable building with TF-M as the Secure Execution Environment. -config BUILD_WITH_TFM - default n if BOARD_BL5340_DVK_CPUAPP_NS - -if BUILD_WITH_TFM - -# By default, if we build with TF-M, instruct build system to -# flash the combined TF-M (Secure) & Zephyr (Non Secure) image -config TFM_FLASH_MERGED_BINARY - bool - default n - -endif # BUILD_WITH_TFM # Code Partition: # @@ -84,11 +70,12 @@ config MBOX_NRFX_IPC if BOARD_RAYTAC_MDBT53V_DB_40_NRF5340_CPUAPP || BOARD_RAYTAC_MDBT53V_DB_40_NRF5340_CPUAPP_NS choice BT_HCI_BUS_TYPE - default BT_RPMSG if BT + default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE - default 4096 if BT_RPMSG +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/raytac_mdbt53v_db_40_nrf5340/doc/index.rst b/boards/arm/raytac_mdbt53v_db_40_nrf5340/doc/index.rst index cc2285f1484fc4f..ca38f03a78108c4 100644 --- a/boards/arm/raytac_mdbt53v_db_40_nrf5340/doc/index.rst +++ b/boards/arm/raytac_mdbt53v_db_40_nrf5340/doc/index.rst @@ -24,9 +24,6 @@ The raytac_mdbt53v_db_40_nrf5340_cpuapp build target provides support for the ap core on the nRF5340 SoC. The raytac_mdbt53v_db_40_nrf5340_cpuapp build target provides support for the network core on the nRF5340 SoC. -.. note:: - Trusted Firmware-M (TF-M) and building the ``ns`` target is not supported for this board. - nRF5340 SoC provides support for the following devices: * :abbr:`ADC (Analog to Digital Converter)` diff --git a/boards/arm/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpuapp_common-pinctrl.dtsi b/boards/arm/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpuapp_common-pinctrl.dtsi index 0839492b156a29d..0574b5b3892d753 100644 --- a/boards/arm/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpuapp_common-pinctrl.dtsi +++ b/boards/arm/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpuapp_common-pinctrl.dtsi @@ -39,6 +39,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/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpuapp_common.dts b/boards/arm/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpuapp_common.dts index 79887dba90933ce..c7d7521d08b05a4 100644 --- a/boards/arm/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpuapp_common.dts +++ b/boards/arm/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpuapp_common.dts @@ -14,7 +14,7 @@ zephyr,uart-mcumgr = &uart0; zephyr,bt-mon-uart = &uart0; zephyr,bt-c2h-uart = &uart0; - zephyr,bt-hci-rpmsg-ipc = &ipc0; + zephyr,bt-hci-ipc = &ipc0; nordic,802154-spinel-ipc = &ipc0; zephyr,ieee802154 = &ieee802154; }; @@ -107,6 +107,14 @@ pinctrl-names = "default", "sleep"; }; +&uart1 { + compatible = "nordic,nrf-uarte"; + 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/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpunet-pinctrl.dtsi b/boards/arm/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpunet-pinctrl.dtsi index 15e96ef213eaa27..51197c008bb2b71 100644 --- a/boards/arm/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpunet-pinctrl.dtsi +++ b/boards/arm/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpunet-pinctrl.dtsi @@ -9,7 +9,7 @@ group1 { psels = , , - , + , ; }; }; diff --git a/boards/arm/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpunet.dts b/boards/arm/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpunet.dts index 8b36a2aefbb4f57..14f0f11498614bd 100644 --- a/boards/arm/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpunet.dts +++ b/boards/arm/raytac_mdbt53v_db_40_nrf5340/raytac_mdbt53v_db_40_nrf5340_cpunet.dts @@ -21,7 +21,7 @@ zephyr,sram = &sram1; zephyr,flash = &flash1; zephyr,code-partition = &slot0_partition; - zephyr,bt-hci-rpmsg-ipc = &ipc0; + zephyr,bt-hci-ipc = &ipc0; }; diff --git a/boards/arm/rcar_spider/Kconfig.board b/boards/arm/rcar_spider/Kconfig.board new file mode 100644 index 000000000000000..1ff4c7e794d4589 --- /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 000000000000000..b2a590250f9bd76 --- /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 000000000000000..b106c562c540b17 --- /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 000000000000000..76bda515cfb8363 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 000000000000000..7956f18c44da3c5 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 000000000000000..33deb1f27a8d1b8 --- /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 000000000000000..b164961271a5230 --- /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 000000000000000..6d89b3ede94d530 --- /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 000000000000000..6dea2b344b70cb6 --- /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 000000000000000..7eea72fd80a52fd --- /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 000000000000000..518b63c7f48bdba --- /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 e1b4c3f971a9df4..5d560f26154a93e 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/reel_board/doc/index.rst b/boards/arm/reel_board/doc/index.rst index dc490249abd004d..dec81bd88ec61cc 100644 --- a/boards/arm/reel_board/doc/index.rst +++ b/boards/arm/reel_board/doc/index.rst @@ -462,8 +462,7 @@ Meaning of the Power Source Switch positions: X9 or X5. USB - link board BASE is powered from from USB connector - (via DCDC converter). + link board BASE is powered from USB connector (via DCDC converter). RB link board BASE is powered from reel board. The available power is diff --git a/boards/arm/ronoth_lodev/doc/index.rst b/boards/arm/ronoth_lodev/doc/index.rst index f1c60567a996466..58f0756ecb30f7f 100644 --- a/boards/arm/ronoth_lodev/doc/index.rst +++ b/boards/arm/ronoth_lodev/doc/index.rst @@ -8,7 +8,7 @@ Overview ======== The Ronoth_ LoDev_ is a small open source board containing a `AcSIP S76S`_ SiP from AcSIP_. -The `full LoDev design details`_ are available on on GitHub. The LoDev_ board can be purchased +The `full LoDev design details`_ are available on GitHub. The LoDev_ board can be purchased from Ronoth_ or from CrowdSupply_. The S76S contains an STMicro STM32L073RZ MCU, a `Semtech SX1276`_ LoRaWAN transceiver, diff --git a/boards/arm/rpi_pico/board.cmake b/boards/arm/rpi_pico/board.cmake index 07a128fad7bfa33..e9cd4edc18f594b 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 2fb41387864e6bc..f535d85506ae03c 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` @@ -140,7 +143,7 @@ Zephyr does not (currently) assemble PIO programs. Rather, they should be manually assembled and embedded in source code. An example of how this is done can be found at `drivers/serial/uart_rpi_pico_pio.c`. -Sample: SPI vio PIO +Sample: SPI via PIO ==================== The :zephyr_file:`samples/sensor/bme280/README.rst` sample includes a diff --git a/boards/arm/rpi_pico/rpi_pico-common.dtsi b/boards/arm/rpi_pico/rpi_pico-common.dtsi index 54f12e53843e0e4..95a27d3a0090c93 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 93790191e6e9d7c..761354420c6160a 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 485cfde0db5c468..ada56d844807a37 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 2a276892119f1a7..111edceb147e009 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 32bf9ef078fe030..d0acab19cc6eedc 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 a03556141970f8e..9b3868541d19f33 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/ruuvi_ruuvitag/ruuvi_ruuvitag_defconfig b/boards/arm/ruuvi_ruuvitag/ruuvi_ruuvitag_defconfig index 7e28dde8423c475..08403e5d814b46f 100644 --- a/boards/arm/ruuvi_ruuvitag/ruuvi_ruuvitag_defconfig +++ b/boards/arm/ruuvi_ruuvitag/ruuvi_ruuvitag_defconfig @@ -8,6 +8,11 @@ CONFIG_BOARD_RUUVI_RUUVITAG=y # Enable MPU CONFIG_ARM_MPU=y +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y + # Enable RTT CONFIG_USE_SEGGER_RTT=y diff --git a/boards/arm/rzt2m_starterkit/Kconfig.board b/boards/arm/rzt2m_starterkit/Kconfig.board new file mode 100644 index 000000000000000..9fddcf006a4f14d --- /dev/null +++ b/boards/arm/rzt2m_starterkit/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_RZT2M_STARTER_KIT + bool "RZ/T2M Starter Kit Board" + depends on SOC_RENESAS_RZT2M diff --git a/boards/arm/rzt2m_starterkit/Kconfig.defconfig b/boards/arm/rzt2m_starterkit/Kconfig.defconfig new file mode 100644 index 000000000000000..9699b23963c96f5 --- /dev/null +++ b/boards/arm/rzt2m_starterkit/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_RZT2M_STARTER_KIT + +config BOARD + default "rzt2m_starter_kit" + +endif diff --git a/boards/arm/rzt2m_starterkit/board.cmake b/boards/arm/rzt2m_starterkit/board.cmake new file mode 100644 index 000000000000000..dd92d0e905a7924 --- /dev/null +++ b/boards/arm/rzt2m_starterkit/board.cmake @@ -0,0 +1,11 @@ +# +# Copyright (c) 2023 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 +# + +board_set_debugger_ifnset(jlink) +board_set_flasher_ifnset(jlink) + +board_runner_args(jlink "--device=R9A07G075M2") +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/rzt2m_starterkit/doc/index.rst b/boards/arm/rzt2m_starterkit/doc/index.rst new file mode 100644 index 000000000000000..72dc6615f64b6f4 --- /dev/null +++ b/boards/arm/rzt2m_starterkit/doc/index.rst @@ -0,0 +1,98 @@ +.. _rzt2m_starterkit: + +Renesas Starter Kit+ for RZ/T2M +############################### + +Overview +******** + +The Renesas Starter Kit+ for RZ/T2M is an evaluation and development kit for the RZ/T2M MPU. +The board is powered through a 5V input via a DC Power Jack or USB Type-C Connector. + +.. figure:: rzt2m_starterkit.png + :width: 800px + :align: center + :alt: Starter Kit+ for RZ/T2M + + Starter Kit+ for RZ/T2M (Credit: Renesas) + +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), +* HyperRAM (512Mbit), +* QSPI Serial Flash (512Mbit), +* I2C EEPROM (32Kbit). + +The communication interfaces include: + +* Debug interfaces (J-Link, MIPI-10, MIPI-20), +* Ethernet, +* CAN, +* USB, +* RS485, +* UART, +* I2C, +* SPI. + +Supported Features +================== + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| SYSTICK | on-chip | systick | ++-----------+------------+-------------------------------------+ +| PINCTRL | on-chip | pinctrl | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ + +Other hardware features are not currently supported by the port. + +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`, + +The Zephyr console uses UART0. + +Programming and Debugging +************************* + +Debugging +========= + +Connect to the board using the J-Link On-board USB connector. +Use `west` to start the debug server: + +.. code-block:: console + + west debugserver + +Connect GDB to the server and load an application: + +.. code-block:: + + target remote :2331 + file build/zephyr/zephyr.elf + load + +References +********** + +.. _RZT2M Product page: https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rz-mpus/rzt2m-high-performance-multi-function-mpu-realizing-high-speed-processing-and-high-precision-control diff --git a/boards/arm/rzt2m_starterkit/doc/rzt2m_starterkit.png b/boards/arm/rzt2m_starterkit/doc/rzt2m_starterkit.png new file mode 100644 index 000000000000000..960df4fdbb58c53 Binary files /dev/null and b/boards/arm/rzt2m_starterkit/doc/rzt2m_starterkit.png differ diff --git a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts new file mode 100644 index 000000000000000..6b87455aafe0414 --- /dev/null +++ b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include + +/ { + model = "RZT/2M Starter Kit"; + compatible = "renesas,rzt2m_starter_kit"; + + chosen { + zephyr,sram = &cpu0_atcm; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; + + aliases { + led0 = &led0; + }; + + leds { + compatible = "gpio-leds"; + led0: led0 { + gpios = <&gpio19 6 0>; + label = "led0"; + }; + led1: led1 { + gpios = <&gpio19 4 0>; + label = "led1"; + }; + led2: led2 { + gpios = <&gpio20 0 0>; + label = "led2"; + }; + led3: led3 { + gpios = <&gpio23 4 0>; + label = "led3"; + }; + }; +}; + + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + uart3_default: uart3_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; +}; + +&uart0 { + status = "okay"; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&uart3 { + status = "okay"; + pinctrl-0 = <&uart3_default>; + pinctrl-names = "default"; +}; diff --git a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.yaml b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.yaml new file mode 100644 index 000000000000000..5d091d0fddb3b74 --- /dev/null +++ b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +identifier: rzt2m_starter_kit +name: Renesas RZ/T2M Starter Kit+ +type: mcu +arch: arm +ram: 2048 +toolchain: + - zephyr +supported: + - counter + - uart + - gpio +vendor: renesas diff --git a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit_defconfig b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit_defconfig new file mode 100644 index 000000000000000..8b994e00082f146 --- /dev/null +++ b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit_defconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_RENESAS_RZT2M=y +CONFIG_BOARD_RZT2M_STARTER_KIT=y + +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/boards/arm/s32z270dc2_r52/board.cmake b/boards/arm/s32z270dc2_r52/board.cmake index c7da302041a2618..31a4fe20d42bea8 100644 --- a/boards/arm/s32z270dc2_r52/board.cmake +++ b/boards/arm/s32z270dc2_r52/board.cmake @@ -1,19 +1,24 @@ -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # SPDX-License-Identifier: Apache-2.0 -board_set_flasher_ifnset(trace32) -board_set_debugger_ifnset(trace32) - board_runner_args(trace32 "--startup-args" - "elfFile=${PROJECT_BINARY_DIR}/${KERNEL_ELF_NAME}" - "thumb=no" + "elfFile=${PROJECT_BINARY_DIR}/${KERNEL_ELF_NAME}" + "rtu=${CONFIG_NXP_S32_RTU_INDEX}" +) + +board_runner_args(nxp_s32dbg + "--soc-family-name" "s32z2e2" + "--soc-name" "S32Z270" ) -if(CONFIG_BOARD_S32Z270DC2_RTU0_R52) -board_runner_args(trace32 "rtu=0") -elseif(CONFIG_BOARD_S32Z270DC2_RTU1_R52) -board_runner_args(trace32 "rtu=1") +if(CONFIG_DCLS) + board_runner_args(trace32 "lockstep=yes") + board_runner_args(nxp_s32dbg "--core-name" "R52_${CONFIG_NXP_S32_RTU_INDEX}_0_LS") +else() + board_runner_args(trace32 "lockstep=no") + board_runner_args(nxp_s32dbg "--core-name" "R52_${CONFIG_NXP_S32_RTU_INDEX}_0") endif() +include(${ZEPHYR_BASE}/boards/common/nxp_s32dbg.board.cmake) include(${ZEPHYR_BASE}/boards/common/trace32.board.cmake) diff --git a/boards/arm/s32z270dc2_r52/doc/index.rst b/boards/arm/s32z270dc2_r52/doc/index.rst index 60b465cc94072dc..e940a144f1f92fc 100644 --- a/boards/arm/s32z270dc2_r52/doc/index.rst +++ b/boards/arm/s32z270dc2_r52/doc/index.rst @@ -146,26 +146,21 @@ Applications for the ``s32z270dc2_rtu0_r52`` and ``s32z270dc2_rtu1_r52`` boards can be built in the usual way as documented in :ref:`build_an_application`. Currently is only possible to load and execute a Zephyr application binary on -this board from the internal SRAM, using `Lauterbach TRACE32`_ development -tools and debuggers. +this board from the core internal SRAM. -.. note:: - Currently, the start-up scripts executed with ``west flash`` and - ``west debug`` commands perform the same steps to initialize the SoC and - load the application to SRAM. The difference is that ``west flash`` hide the - Lauterbach TRACE32 interface, executes the application and exits. +This board supports West runners for the following debug tools: -Install Lauterbach TRACE32 Software -=================================== +- :ref:`NXP S32 Debug Probe ` (default) +- :ref:`Lauterbach TRACE32 ` -Follow the steps described in :ref:`lauterbach-trace32-debug-host-tools` to -install and set-up Lauterbach TRACE32 software. +Follow the installation steps of the debug tool you plan to use before loading +your firmware. Set-up the Board ================ -Connect the Lauterbach TRACE32 debugger to the board's JTAG connector (``J134``) -and to the host computer. +Connect the external debugger probe to the board's JTAG connector (``J134``) +and to the host computer via USB or Ethernet, as supported by the probe. For visualizing the serial output, connect the board's USB/UART port (``J119``) to the host computer and run your favorite terminal program to listen for output. @@ -178,16 +173,16 @@ For example, using the cross-platform `pySerial miniterm`_ terminal: Replace ```` with the port where the board can be found. For example, under Linux, ``/dev/ttyUSB0``. -Flashing -======== +Debugging +========= -For example, you can build and run the :ref:`hello_world` sample for the board +You can build and debug the :ref:`hello_world` sample for the board ``s32z270dc2_rtu0_r52`` with: .. zephyr-app-commands:: :zephyr-app: samples/hello_world :board: s32z270dc2_rtu0_r52 - :goals: build flash + :goals: build debug In case you are using a newer PCB revision, you have to use an adapted board definition as the default PCB revision is B. For example, if using revision D: @@ -195,30 +190,53 @@ definition as the default PCB revision is B. For example, if using revision D: .. zephyr-app-commands:: :zephyr-app: samples/hello_world :board: s32z270dc2_rtu0_r52@D - :goals: build flash + :goals: build debug + :compact: -You should see the following message in the terminal: +At this point you can do your normal debug session. Set breakpoints and then +:kbd:`c` to continue into the program. You should see the following message in +the terminal: .. code-block:: console Hello World! s32z270dc2_rtu0_r52 -Debugging -========= +To debug with Lauterbach TRACE32 softare run instead: -To enable debugging using Lauterbach TRACE32 software, run instead: +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: s32z270dc2_rtu0_r52 + :goals: build debug -r trace32 + :compact: + +Flashing +======== + +Follow these steps if you just want to download the application to the board +SRAM and run. + +``flash`` command is supported only by the Lauterbach TRACE32 runner: .. zephyr-app-commands:: :zephyr-app: samples/hello_world :board: s32z270dc2_rtu0_r52 - :goals: build debug + :goals: build flash -r trace32 + :compact: -Step through the application in your debugger, and you should see the following -message in the terminal: +.. note:: + Currently, the Lauterbach start-up scripts executed with ``flash`` and + ``debug`` commands perform the same steps to initialize the SoC and + load the application to SRAM. The difference is that ``flash`` hides the + Lauterbach TRACE32 interface, executes the application and exits. -.. code-block:: console +To imitate a similar behavior using NXP S32 Debug Probe runner, you can run the +``debug`` command with GDB in batch mode: - Hello World! s32z270dc2_rtu0_r52 +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: s32z270dc2_rtu0_r52 + :goals: build debug --tool-opt='--batch' + :compact: RTU and Core Configuration ========================== @@ -231,26 +249,29 @@ configuration). To build for split-lock mode, the :kconfig:option:`CONFIG_DCLS` must be disabled from your application Kconfig file. -Additionally, to run in a different core or with a different core -configuration than the default, extra parameters must be provided to the runner -as follows: +By default the board configuration will set the runner arguments according to +the build configuration. To debug for a core different than the default use: -.. code-block:: console +.. tabs:: + + .. group-tab:: lockstep configuration + + .. code-block:: console - west --startup-args elfFile= rtu= \ - core= lockstep= + west debug --core-name='R52___LS' + + .. group-tab:: split-lock configuration + + .. code-block:: console + + west debug --core-name='R52__' Where: -- ```` is ``flash`` or ``debug`` -- ```` is the path to the Zephyr application ELF in the output - directory - ```` is the zero-based RTU index (0 for ``s32z270dc2_rtu0_r52`` and 1 for ``s32z270dc2_rtu1_r52``) - ```` is the zero-based core index relative to the RTU on which to run the Zephyr application (0, 1, 2 or 3) -- ```` can be ``yes`` to run in lock-step, or ``no`` to run in - split-lock. For example, to build the :ref:`hello_world` sample for the board ``s32z270dc2_rtu0_r52`` with split-lock core configuration: @@ -260,13 +281,23 @@ For example, to build the :ref:`hello_world` sample for the board :board: s32z270dc2_rtu0_r52 :goals: build :gen-args: -DCONFIG_DCLS=n + :compact: To execute this sample in the second core of RTU0 in split-lock mode: .. code-block:: console - west flash --startup-args elfFile=build/zephyr/zephyr.elf \ - rtu=0 core=1 lockstep=no + west debug --core-name='R52_0_1' + +If using Lauterbach TRACE32, all runner parameters must be overridden from command +line: + +.. code-block:: console + + west debug --startup-args elfFile= rtu= core= lockstep= + +Where ```` is the path to the Zephyr application ELF in the output +directory. References ********** @@ -276,8 +307,5 @@ References .. _NXP S32Z2 Real-Time Processors website: https://www.nxp.com/products/processors-and-microcontrollers/s32-automotive-platform/s32z-and-s32e-real-time-processors/s32z2-safe-and-secure-high-performance-real-time-processors:S32Z2 -.. _Lauterbach TRACE32: - https://www.lauterbach.com - .. _pySerial miniterm: https://pyserial.readthedocs.io/en/latest/tools.html#module-serial.tools.miniterm diff --git a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52.dts b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52.dts index ebaf1658f3b6f6c..a865075808956d9 100644 --- a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52.dts +++ b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52.dts @@ -5,7 +5,6 @@ */ /dts-v1/; -#include #include #include "s32z270dc2_r52.dtsi" diff --git a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52.yaml b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52.yaml index dbf4d3bd840785f..891f6b3cce59824 100644 --- a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52.yaml +++ b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52.yaml @@ -1,4 +1,4 @@ -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # SPDX-License-Identifier: Apache-2.0 identifier: s32z270dc2_rtu0_r52 @@ -14,4 +14,6 @@ supported: - watchdog - netif:eth - can + - spi + - counter vendor: nxp diff --git a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml index db8c9e688544376..481ce3e63b25237 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 @@ -14,3 +14,6 @@ supported: - watchdog - netif:eth - can + - spi + - counter +vendor: nxp diff --git a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52.dts b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52.dts index 06cf6b258441d42..1f74fe4a3a9a014 100644 --- a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52.dts +++ b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52.dts @@ -5,7 +5,6 @@ */ /dts-v1/; -#include #include #include "s32z270dc2_r52.dtsi" diff --git a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52.yaml b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52.yaml index 2a722ee4606bb73..de48e46091a7235 100644 --- a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52.yaml +++ b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52.yaml @@ -1,4 +1,4 @@ -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # SPDX-License-Identifier: Apache-2.0 identifier: s32z270dc2_rtu1_r52 @@ -14,4 +14,6 @@ supported: - watchdog - netif:eth - can + - spi + - counter vendor: nxp diff --git a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml index aeb1eac2038e771..9f0a55547c11737 100644 --- a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml +++ b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml @@ -1,8 +1,8 @@ -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # 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 @@ -14,3 +14,6 @@ supported: - watchdog - netif:eth - can + - spi + - counter +vendor: nxp 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 2007cbe95b830d9..e41db2f1c55b2c0 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 968b19e7562d467..ee002c846fa98d5 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/sam_v71_xult/doc/index.rst b/boards/arm/sam_v71_xult/doc/index.rst index 5bed3274d71153c..a61fe887d6a877e 100644 --- a/boards/arm/sam_v71_xult/doc/index.rst +++ b/boards/arm/sam_v71_xult/doc/index.rst @@ -70,7 +70,7 @@ features: +-----------+------------+-------------------------------------+ | PWM | on-chip | pwm | +-----------+------------+-------------------------------------+ -| CAN-FD | on-chip | can | +| CAN FD | on-chip | can | +-----------+------------+-------------------------------------+ | HWINFO | on-chip | Unique device serial number | +-----------+------------+-------------------------------------+ diff --git a/boards/arm/scobc_module1/scobc_module1.dts b/boards/arm/scobc_module1/scobc_module1.dts index 1cfa73bc91b8f9b..3f704e1113d9196 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 8ec2b6795577bd6..ecadcfc07bd92ff 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 4287849bf315edf..1f3d19b39cadaef 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 e622d5c190f1356..4c5a9654b3d6dcd 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 e67e105021b7e91..aaa655bf84cddeb 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/CMakeLists.txt b/boards/arm/sensortile_box_pro/CMakeLists.txt new file mode 100644 index 000000000000000..4489ff54489ce5d --- /dev/null +++ b/boards/arm/sensortile_box_pro/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +# Define the toolchain to be used (by eg CI) +if(${ZEPHYR_TOOLCHAIN_VARIANT} STREQUAL "zephyr") + set(COMPILER_FULL_PATH ${ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc) +elseif(${ZEPHYR_TOOLCHAIN_VARIANT} STREQUAL "gnuarmemb") + set(COMPILER_FULL_PATH ${GNUARMEMB_TOOLCHAIN_PATH}/bin/arm-none-eabi-gcc) +endif() + +zephyr_library_sources(board.c) diff --git a/boards/arm/sensortile_box_pro/Kconfig.board b/boards/arm/sensortile_box_pro/Kconfig.board new file mode 100644 index 000000000000000..144297059991010 --- /dev/null +++ b/boards/arm/sensortile_box_pro/Kconfig.board @@ -0,0 +1,8 @@ +# SENSORTILE_BOX_PRO board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_SENSORTILE_BOX_PRO + bool "SENSORTILE_BOX_PRO Board" + depends on SOC_STM32U585XX diff --git a/boards/arm/sensortile_box_pro/Kconfig.defconfig b/boards/arm/sensortile_box_pro/Kconfig.defconfig new file mode 100644 index 000000000000000..48b55275be3dd7d --- /dev/null +++ b/boards/arm/sensortile_box_pro/Kconfig.defconfig @@ -0,0 +1,42 @@ +# SENSORTILE_BOX_PRO board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +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 + +if LOG + +# Logger cannot use itself to log +choice USB_CDC_ACM_LOG_LEVEL_CHOICE + default USB_CDC_ACM_LOG_LEVEL_OFF +endchoice + +endif # LOG + +endif # BOARD_SENSORTILE_BOX_PRO diff --git a/boards/arm/sensortile_box_pro/board.c b/boards/arm/sensortile_box_pro/board.c new file mode 100644 index 000000000000000..db3de065f2bfbff --- /dev/null +++ b/boards/arm/sensortile_box_pro/board.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_USB_DEVICE_STACK +/* + * Enable console on USB CDC_ACM + */ +static int sensortile_box_pro_usb_console_init(void) +{ + const struct device *const dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); + + if (!device_is_ready(dev) || usb_enable(NULL)) { + return -1; + } + + return 0; +} + +/* needs to be done at Application */ +SYS_INIT(sensortile_box_pro_usb_console_init, APPLICATION, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE); +#endif diff --git a/boards/arm/sensortile_box_pro/board.cmake b/boards/arm/sensortile_box_pro/board.cmake new file mode 100644 index 000000000000000..370c545442934f7 --- /dev/null +++ b/boards/arm/sensortile_box_pro/board.cmake @@ -0,0 +1,5 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 +board_runner_args(dfu-util "--pid=0483:df11" "--alt=0" "--dfuse") + +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) diff --git a/boards/arm/sensortile_box_pro/doc/img/sensortile_box_pro.jpg b/boards/arm/sensortile_box_pro/doc/img/sensortile_box_pro.jpg new file mode 100644 index 000000000000000..2865d8c576b3d5d Binary files /dev/null and b/boards/arm/sensortile_box_pro/doc/img/sensortile_box_pro.jpg differ diff --git a/boards/arm/sensortile_box_pro/doc/index.rst b/boards/arm/sensortile_box_pro/doc/index.rst new file mode 100644 index 000000000000000..bba5a4cb288be79 --- /dev/null +++ b/boards/arm/sensortile_box_pro/doc/index.rst @@ -0,0 +1,386 @@ +.. _sensortile_box_pro_board: + +ST SensorTile.box PRO +##################### + +Overview +******** + +The STEVAL-MKBOXPRO (SensorTile.box PRO) features an ARM Cortex-M33 based STM32U585AI MCU +and is a ready-to-use box kit for wireless IoT and wearable sensor platforms to help using +and developing apps based on remote motion and environmental sensor data. + +The SensorTile.box PRO board fits into a small plastic box with a long-life rechargeable +battery, and communicates with a standard smartphone through its Bluetooth interface, +providing data coming from the sensors. + +.. image:: img/sensortile_box_pro.jpg + :align: center + :alt: SensorTile.box PRO + +More information about the board can be found at the `SensorTile.box PRO website`_. + +Supported Features +****************** + +The SensorTile.box PRO provides motion, environmental, and audio +sensor data through either the BLE or USB protocols to a host application running +on a smartphone/PC to implement applications such as: + +- Pedometer optimized for belt positioning +- Baby crying detection with Cloud AI learning +- Barometer / environmental monitoring +- Vehicle / goods tracking +- Vibration monitoring +- Compass and inclinometer +- Sensor data logger + +(see `Motion and environmental sensors`_ section for the complete lists of available +sensors on board) + +Hardware +******** + +The STM32U585xx devices are an ultra-low-power microcontrollers family (STM32U5 +Series) based on the high-performance Arm|reg| Cortex|reg|-M33 32-bit RISC core. +They operate at a frequency of up to 160 MHz. + +- Ultra-low-power with FlexPowerControl (down to 300 nA Standby mode and 19.5 uA/MHz run mode) +- Core: ARM |reg| 32-bit Cortex |reg| -M33 CPU with TrustZone |reg| and FPU. +- Performance benchmark: + + - 1.5 DMPIS/MHz (Drystone 2.1) + - 651 CoreMark |reg| (4.07 CoreMark |reg| /MHZ) + +- Security and cryptography + + - Arm |reg| TrustZone |reg| and securable I/Os memories and peripherals + - Flexible life cycle scheme with RDP (readout protection) and password protected debug + - Root of trust thanks to unique boot entry and secure hide protection area (HDP) + - Secure Firmware Installation thanks to embedded Root Secure Services + - Secure data storage with hardware unique key (HUK) + - Secure Firmware Update support with TF-M + - 2 AES coprocessors including one with DPA resistance + - Public key accelerator, DPA resistant + - On-the-fly decryption of Octo-SPI external memories + - HASH hardware accelerator + - Active tampers + - True Random Number Generator NIST SP800-90B compliant + - 96-bit unique ID + - 512-byte One-Time Programmable for user data + - Active tampers + +- Clock management: + + - 4 to 50 MHz crystal oscillator + - 32 kHz crystal oscillator for RTC (LSE) + - Internal 16 MHz factory-trimmed RC ( |plusminus| 1%) + - Internal low-power 32 kHz RC ( |plusminus| 5%) + - 2 internal multispeed 100 kHz to 48 MHz oscillators, including one auto-trimmed by + LSE (better than |plusminus| 0.25 % accuracy) + - 3 PLLs for system clock, USB, audio, ADC + - Internal 48 MHz with clock recovery + +- Power management + + - Embedded regulator (LDO) + - Embedded SMPS step-down converter supporting switch on-the-fly and voltage scaling + +- RTC with HW calendar and calibration +- Up to 136 fast I/Os, most 5 V-tolerant, up to 14 I/Os with independent supply down to 1.08 V +- Up to 24 capacitive sensing channels: support touchkey, linear and rotary touch sensors +- Up to 17 timers and 2 watchdogs + + - 2x 16-bit advanced motor-control + - 2x 32-bit and 5 x 16-bit general purpose + - 4x low-power 16-bit timers (available in Stop mode) + - 2x watchdogs + - 2x SysTick timer + +- ART accelerator + + - 8-Kbyte instruction cache allowing 0-wait-state execution from Flash and + external memories: up to 160 MHz, MPU, 240 DMIPS and DSP + - 4-Kbyte data cache for external memories + +- Memories + + - 2-Mbyte Flash memory with ECC, 2 banks read-while-write, including 512 Kbytes with 100 kcycles + - 786-Kbyte SRAM with ECC OFF or 722-Kbyte SRAM including up to 322-Kbyte SRAM with ECC ON + - External memory interface supporting SRAM, PSRAM, NOR, NAND and FRAM memories + - 2 Octo-SPI memory interfaces + +- Rich analog peripherals (independent supply) + + - 14-bit ADC 2.5-Msps, resolution up to 16 bits with hardware oversampling + - 12-bit ADC 2.5-Msps, with hardware oversampling, autonomous in Stop 2 mode + - 12-bit DAC, low-power sample and hold + - 2 operational amplifiers with built-in PGA + - 2 ultra-low-power comparators + +- Up to 22 communication interfaces + + - USB Type-C / USB power delivery controller + - USB OTG 2.0 full-speed controller + - 2x SAIs (serial audio interface) + - 4x I2C FM+(1 Mbit/s), SMBus/PMBus + - 6x USARTs (ISO 7816, LIN, IrDA, modem) + - 3x SPIs (5x SPIs with dual OCTOSPI in SPI mode) + - 1x FDCAN + - 2x SDMMC interface + - 16- and 4-channel DMA controllers, functional in Stop mode + - 1 multi-function digital filter (6 filters)+ 1 audio digital filter with + sound-activity detection + +- CRC calculation unit +- Development support: serial wire debug (SWD), JTAG, Embedded Trace Macrocell |trade| +- True Random Number Generator (RNG) + +- Graphic features + + - Chrom-ART Accelerator (DMA2D) for enhanced graphic content creation + - 1 digital camera interface + +- Mathematical co-processor + + - CORDIC for trigonometric functions acceleration + - FMAC (filter mathematical accelerator) + + +More information about STM32U585AI can be found here: + +- `STM32U585 on www.st.com`_ +- `STM32U585 reference manual`_ + +Motion and environmental sensors +================================ + + - **LSM6DSV16X** 6-axis inertial measurement unit + (`lsm6dsv16x datasheet`_) + - **LIS2MDL** 3-axis magnetometer + (`lis2mdl datasheet`_) + - **LPS22DF** Altimeter / pressure sensor + (`lps22df datasheet`_) + - **LIS2DU12** 3-axis accelerometer + (`lis2du12 datasheet`_) + - **HTS221** Humidity sensor + (`hts221 datasheet`_) + - **STTS22H** Digital temperature sensor + (`stts22hh datasheet`_) + - **MP23db01HP** Microphone / audio sensor + (`mp23db01hp datasheet`_) + +Connections and IOs +=================== + +- 4x user LEDs + + - **led0** (Green) + - **led1** (Red - shared with BLE) + - **led2** (Yellow) + - **led3** (Blue) + + +- 4x buttons/switch + + - **User BT1** button, available to user application + - **User BT2** / **boot0** button, available to user application + but useful to let the SensorTile.box PRO enter DFU mode + if found pressed after h/w reset (see **rst** button and + `Programming and Debugging`_ section) + - **rst** button, used to reset the board (not available on case) + - **power** switch, used to Power on/off the board + +System Clock +============ + +SensorTile.box PRO System Clock could be driven by internal or external +oscillator, as well as main PLL clock. By default, the System clock is +driven by the PLL clock at 80MHz, driven by the 16MHz external oscillator. +The system clock can be boosted to 120MHz. +The internal AHB/APB1/APB2 AMBA buses are all clocked at 80MHz. + +Serial Port +=========== + +The SensorTile.box PRO has 4 U(S)ARTs. The UART4 is connected to JTAG/SWD connector +and may be used as console. + +USB interface +============= + +SensorTile.box PRO can be connected as a USB device to a PC host through its USB-C connector. +The final application may use it to declare SensorTile.box PRO device as belonging to a +certain standard or vendor class, e.g. a CDC, a mass storage or a composite device with both +functions. + +Console +======= + +There are two possible options for Zephyr console output: + +- through UART4 which is available on SWD connector (JP2). In this case a JTAG adapter + can be used to connect SensorTile.box PRO and have both SWD and console lines available. + + To enable console and shell over UART + + - switch the console lines from cdc_acm to uart4 + (:file:`boards/arm/sensortile_box_pro/sensortile_box_pro.dts`) + + - comment out the USB configuration macros + (:file:`boards/arm/sensortile_box_pro/sensortile_box_pro_defconfig`) + +.. code-block:: dts + :caption: boards/arm/sensortile_box_pro/sensortile_box_pro.dts + + / { + chosen { + zephyr,console = &uart4; + zephyr,shell-uart = &uart4; + //zephyr,console = &cdc_acm_uart0; + //zephyr,shell-uart = &cdc_acm_uart0; + }; + }; + +.. code-block:: Kconfig + :caption: boards/arm/sensortile_box_pro/sensortile_box_pro_defconfig + + # Comment out following USB config lines when + # switching console to UART + #CONFIG_USB_DEVICE_STACK=y + #CONFIG_USB_DEVICE_VID=0x0483 + #CONFIG_USB_DEVICE_PID=0x1235 + #CONFIG_USB_DEVICE_PRODUCT="Zephyr CDC SensorTile.box PRO" + #CONFIG_USB_CDC_ACM_LOG_LEVEL_OFF=y + #CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n + + +- through USB as USB CDC/ACM class. This is the default case present in the board dts file. + +.. code-block:: dts + :caption: boards/arm/sensortile_box_pro/sensortile_box_pro.dts + + / { + chosen { + zephyr,console = &cdc_acm_uart0; + }; + }; + + &zephyr_udc0 { + cdc_acm_uart0: cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + }; + }; + + + +Console default settings are 115200 8N1. + +Programming and Debugging +************************* + +There are two alternative methods of flashing ST Sensortile.box Pro board: + +1. Using DFU software tools + + This method requires to enter STM32U585 ROM bootloader DFU mode + by powering up (or reset) the board while keeping the BOOT0 button pressed. + No additional hardware is required except a USB-C cable. This method is fully + supported by :ref:`flash-debug-host-tools`. + You can read more about how to enable and use the ROM bootloader by checking + the application note `AN2606`_ (STM32U585xx section). + +2. Using SWD hardware tools + + This method requires to connect additional hardware, like a ST-LINK/V3 + embedded debug tool, to the board SWD connector. + +DFU flashing +============ + +Install dfu-util +---------------- + +It is recommended to use at least v0.9 of dfu-util. The package available in +Debian and Ubuntu can be quite old, so you might have to build dfu-util from source. +Information about how to get the source code and how to build it can be found +at the `DFU-UTIL website`_ + +Flash an Application to SensorTile.box PRO +------------------------------------------ + +While pressing the BOOT0 button, connect the USB-C cable to the USB OTG SensorTile.box PRO +port and to your computer. The board should be forced to enter DFU mode. + +Check that the board is indeed in DFU mode: + +.. code-block:: console + + $ sudo dfu-util -l + dfu-util 0.9 + + Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc. + Copyright 2010-2019 Tormod Volden and Stefan Schmidt + This program is Free Software and has ABSOLUTELY NO WARRANTY + Please report bugs to http://sourceforge.net/p/dfu-util/tickets/ + + Found DFU: [0483:df11] ver=2200, devnum=74, cfg=1, intf=0, path="2-2", alt=2, name="@OTP Memory /0x1FFF7000/01*0001Ke", serial="204A325D574D" + Found DFU: [0483:df11] ver=2200, devnum=74, cfg=1, intf=0, path="2-2", alt=1, name="@Option Bytes /0x1FF00000/01*040 e/0x1FF01000/01*040 e", serial="204A325D574D" + Found DFU: [0483:df11] ver=2200, devnum=74, cfg=1, intf=0, path="2-2", alt=0, name="@Internal Flash /0x08000000/512*0004Kg", serial="204A325D574D" + +You should see following confirmation on your Linux host: + +.. code-block:: console + + $ dmesg + usb 2-2: new full-speed USB device number 74 using xhci_hcd + usb 2-2: New USB device found, idVendor=0483, idProduct=df11 + usb 2-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3 + usb 2-2: Product: STM32 BOOTLOADER + usb 2-2: Manufacturer: STMicroelectronics + usb 2-2: SerialNumber: 204A325D574D + +You can build and flash the provided sample application +(:ref:`sensortile_box_pro_sample_sensors`) that reads sensors data and outputs +values on the console. + +References +********** + +.. target-notes:: + +.. _SensorTile.box PRO website: + https://www.st.com/en/evaluation-tools/steval-mkboxpro.html + +.. _STM32U585 on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32u575-585.html + +.. _STM32U585 reference manual: + https://www.st.com/resource/en/reference_manual/rm0456-stm32u575585-armbased-32bit-mcus-stmicroelectronics.pdf + +.. _lsm6dsv16x datasheet: + https://www.st.com/en/mems-and-sensors/lsm6dsv16x.html + +.. _lis2mdl datasheet: + https://www.st.com/en/mems-and-sensors/lis2mdl.html + +.. _lps22df datasheet: + https://www.st.com/en/mems-and-sensors/lps22df.html + +.. _lis2du12 datasheet: + https://www.st.com/en/mems-and-sensors/lis2du12.html + +.. _hts221 datasheet: + https://www.st.com/en/mems-and-sensors/hts221.html + +.. _stts22hh datasheet: + https://www.st.com/en/mems-and-sensors/stts22h.html + +.. _mp23db01hp datasheet: + https://www.st.com/en/mems-and-sensors/mp23db01hp.html + +.. _AN2606: + http://www.st.com/content/ccc/resource/technical/document/application_note/b9/9b/16/3a/12/1e/40/0c/CD00167594.pdf/files/CD00167594.pdf/jcr:content/translations/en.CD00167594.pdf + +.. _DFU-UTIL website: + http://dfu-util.sourceforge.net/ diff --git a/boards/arm/sensortile_box_pro/sensortile_box_pro.dts b/boards/arm/sensortile_box_pro/sensortile_box_pro.dts new file mode 100644 index 000000000000000..8c159eb831fe20f --- /dev/null +++ b/boards/arm/sensortile_box_pro/sensortile_box_pro.dts @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "STMicroelectronics SENSORTILE-BOX-PRO board"; + compatible = "st,sensortile-box-pro"; + + chosen { + /* + * By default, Zephyr console and shell are assigned to + * USB CDC/ACM. To enable console and shell over UART, + * uncomment following lines and set the correct config + * in sensortile_box_pro_defconfig. + * + * zephyr,console = &uart4; + * zephyr,shell-uart = &uart4; + */ + zephyr,console = &cdc_acm_uart0; + zephyr,shell-uart = &cdc_acm_uart0; + + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + leds { + compatible = "gpio-leds"; + green_led_1: led_1 { + gpios = <&gpiof 6 GPIO_ACTIVE_HIGH>; + label = "User GREEN led"; + }; + red_led_1: led_2 { + gpios = <&gpioh 11 GPIO_ACTIVE_HIGH>; + label = "User RED led"; + }; + yellow_led_1: led_3 { + gpios = <&gpioh 12 GPIO_ACTIVE_HIGH>; + label = "User YELLOW led"; + }; + blue_led_1: led_4 { + gpios = <&gpiof 9 GPIO_ACTIVE_HIGH>; + label = "User YELLOW led"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + button1: button1 { + label = "User BT1"; + gpios = <&gpioc 13 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + button2: button2 { + label = "User BT2"; + gpios = <&gpioe 0 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + }; + + sd_card: sd-card { + compatible = "st,stile_sd_card"; + en-sd-gpios = <&gpioh 10 (GPIO_ACTIVE_HIGH)>; + sel-sd-gpios = <&gpioh 8 (GPIO_ACTIVE_HIGH)>; + }; + + aliases { + led0 = &green_led_1; + led1 = &red_led_1; + led2 = &yellow_led_1; + led3 = &blue_led_1; + mcuboot-led0 = &blue_led_1; + mcuboot-button0 = &button1; + sw1 = &button1; + sw2 = &button2; + watchdog0 = &iwdg; + die-temp0 = &die_temp; + volt-sensor0 = &vref1; + volt-sensor1 = &vbat4; + }; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk_lse { + status = "okay"; +}; + +&clk_msis { + status = "okay"; + msi-range = <4>; + msi-pll-mode; +}; + +&gpioi { + status = "okay"; + + /* switch sensor IMU bus from I2C1 to SPI2 */ + mcu-sel-gpios { + gpio-hog; + gpios = <0 GPIO_ACTIVE_HIGH>; + output-low; + }; +}; + +&pll1 { + div-m = <1>; + mul-n = <80>; + div-q = <2>; + div-r = <2>; + clocks = <&clk_msis>; + status = "okay"; +}; + +&rcc { + clocks = <&pll1>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; + apb3-prescaler = <1>; +}; + +stm32_lp_tick_source: &lptim1 { + clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00000800>, + <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; + status = "okay"; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; + 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"; +}; + +&uart4 { + pinctrl-0 = <&uart4_tx_pa0 &uart4_rx_pa1>; + 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 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 { + pinctrl-0 = <&spi2_sck_pi1 &spi2_miso_pi2 &spi2_mosi_pi3>; + pinctrl-names = "default"; + status = "okay"; + + cs-gpios = <&gpioi 5 GPIO_ACTIVE_LOW>, <&gpioi 7 GPIO_ACTIVE_LOW>; + + lsm6dsv16x: lsm6dsv16x@0 { + compatible = "st,lsm6dsv16x"; + 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 { + status = "okay"; + st,prescaler = <1>; + pwm4: pwm { + status = "okay"; + pinctrl-0 = <&tim4_ch1_pb6>; + pinctrl-names = "default"; + }; +}; + +&timers3 { + status = "okay"; + st,prescaler = <255>; + pwm3: pwm { + status = "okay"; + pinctrl-0 = <&tim3_ch2_pe4>; + pinctrl-names = "default"; + }; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_scl_pb6 &i2c1_sda_pb7>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; + + hts221@5f { + compatible = "st,hts221"; + reg = <0x5f>; + drdy-gpios = <&gpioe 11 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; + + lps22df@5d { + compatible = "st,lps22df"; + reg = <0x5d>; + drdy-gpios = <&gpioe 8 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; + + lis2mdl@1e { + compatible = "st,lis2mdl"; + reg = <0x1e>; + irq-gpios = <&gpioe 6 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; +}; + +&i2c2 { + pinctrl-0 = <&i2c2_scl_ph4 &i2c2_sda_ph5>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&aes { + status = "okay"; +}; + +&rng { + status = "okay"; +}; + +zephyr_udc0: &usbotg_fs { + pinctrl-0 = <&usb_otg_fs_dm_pa11 &usb_otg_fs_dp_pa12>; + pinctrl-names = "default"; + status = "okay"; + + cdc_acm_uart0: cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&adc1 { + pinctrl-0 = <&adc1_in15_pb0>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <4>; + status = "okay"; +}; + +&adc4 { + pinctrl-0 = <&adc4_in19_pb1>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <4>; + status = "okay"; +}; + +&die_temp { + status = "okay"; +}; + +&dac1 { + pinctrl-0 = <&dac1_out1_pa4>; + pinctrl-names = "default"; + status = "okay"; +}; + +&iwdg { + status = "okay"; +}; + +&vref1 { + status = "okay"; +}; + +&vbat4 { + status = "okay"; +}; + +&sdmmc1 { + status = "okay"; + pinctrl-0 = <&sdmmc1_d0_pc8 &sdmmc1_d1_pc9 + &sdmmc1_d2_pc10 &sdmmc1_d3_pc11 + &sdmmc1_ck_pc12 &sdmmc1_cmd_pd2 + &sdmmc1_d0dir_pc6 &sdmmc1_d123dir_pc7 + &sdmmc1_cdir_pb9 &sdmmc1_ckin_pb8>; + pinctrl-names = "default"; + cd-gpios = <&gpioc 5 GPIO_ACTIVE_LOW>; + pwr-gpios = <&gpioh 10 GPIO_ACTIVE_LOW>; + bus-width = <4>; + clk-div = <4>; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * Following flash partition is dedicated to the use of sensortile_box_pro + * with TZEN=0 (so w/o TFM). + * Set the partitions with first MB to make use of the whole Bank1 + */ + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_K(416)>; + }; + slot1_partition: partition@78000 { + label = "image-1"; + reg = <0x00078000 DT_SIZE_K(416)>; + }; + scratch_partition: partition@e0000 { + label = "image-scratch"; + reg = <0x000e0000 DT_SIZE_K(64)>; + }; + storage_partition: partition@f0000 { + label = "storage"; + reg = <0x000f0000 DT_SIZE_K(64)>; + }; + + }; +}; + +&gpdma1 { + status = "okay"; +}; diff --git a/boards/arm/sensortile_box_pro/sensortile_box_pro.yaml b/boards/arm/sensortile_box_pro/sensortile_box_pro.yaml new file mode 100644 index 000000000000000..14624c77f7d3b94 --- /dev/null +++ b/boards/arm/sensortile_box_pro/sensortile_box_pro.yaml @@ -0,0 +1,20 @@ +identifier: sensortile_box_pro +name: ST SensorTile.box Pro +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - pwm + - spi + - ble + - i2c + - gpio + - usb device + - nvs + - counter +ram: 640 +flash: 2048 +vendor: st diff --git a/boards/arm/sensortile_box_pro/sensortile_box_pro_defconfig b/boards/arm/sensortile_box_pro/sensortile_box_pro_defconfig new file mode 100644 index 000000000000000..7a91dc1c19581d7 --- /dev/null +++ b/boards/arm/sensortile_box_pro/sensortile_box_pro_defconfig @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_STM32U5X=y +CONFIG_SOC_STM32U585XX=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable Clocks +CONFIG_CLOCK_CONTROL=y + +# config USB and USB console +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_LINE_CTRL=y +CONFIG_UART_INTERRUPT_DRIVEN=y + +# Comment out following USB config lines when +# switching console to UART +CONFIG_USB_DEVICE_STACK=y +CONFIG_USB_DEVICE_VID=0x0483 +CONFIG_USB_DEVICE_PID=0x1235 +CONFIG_USB_DEVICE_PRODUCT="Zephyr CDC SensorTile.box PRO" +CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/sensortile_box_pro/support/openocd.cfg b/boards/arm/sensortile_box_pro/support/openocd.cfg new file mode 100644 index 000000000000000..ee58ed51d4369cf --- /dev/null +++ b/boards/arm/sensortile_box_pro/support/openocd.cfg @@ -0,0 +1,44 @@ +source [find interface/stlink-dap.cfg] + +set WORKAREASIZE 0x8000 + +transport select "dapdirect_swd" + +set CHIPNAME STM32U575ZITxQ +set BOARDNAME STILE-BOX-PRO + +# 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 connect_assert_srst +set CONNECT_UNDER_RESET 1 +set CORE_RESET 0 + +# ACCESS PORT NUMBER +set AP_NUM 0 +# GDB PORT +set GDB_PORT 3333 + +# BCTM CPU variables + +source [find target/stm32u5x.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/serpente/serpente_defconfig b/boards/arm/serpente/serpente_defconfig index a2c3ac7def2506d..b670a7b0476c18f 100644 --- a/boards/arm/serpente/serpente_defconfig +++ b/boards/arm/serpente/serpente_defconfig @@ -3,6 +3,8 @@ CONFIG_SOC_SERIES_SAMD21=y CONFIG_SOC_PART_NUMBER_SAMD21E18A=y CONFIG_BOARD_SERPENTE=y +CONFIG_SOC_ATMEL_SAMD_OSC8M=y +CONFIG_SOC_ATMEL_SAMD_OSC8M_AS_MAIN=y CONFIG_CONSOLE=y CONFIG_GPIO=y CONFIG_UART_CONSOLE=y diff --git a/boards/arm/sparkfun_pro_micro_rp2040/doc/index.rst b/boards/arm/sparkfun_pro_micro_rp2040/doc/index.rst index 1999d64def7e824..3fa4fe40b71e248 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 64f3ab61e5f8a16..3bca8b4f384a53f 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 1bd5e226e2a9c33..1d92bcf1cbae3da 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 d5993798ff4773f..a2a8932d78fc582 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 4ec1c6cad43c69f..36aba3492040860 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/sparkfun_thing_plus_nrf9160/doc/index.rst b/boards/arm/sparkfun_thing_plus_nrf9160/doc/index.rst index 72dac6a89000884..8ee7a38cb338e22 100644 --- a/boards/arm/sparkfun_thing_plus_nrf9160/doc/index.rst +++ b/boards/arm/sparkfun_thing_plus_nrf9160/doc/index.rst @@ -91,9 +91,6 @@ Building an application In most cases you'll want to use the ``ns`` target with any of the Zephyr or Nordic based examples. -.. note:: - Trusted Firmware-M (TF-M) and building the ``ns`` target is not supported for this board. - Some of the examples do not use secure mode, so they do not required the ``ns`` suffix. A great example of this is the `hello_world` below. diff --git a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_common.dtsi b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_common.dtsi index b85c00ea5b212e7..2658ee5eaa49066 100644 --- a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_common.dtsi +++ b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_common.dtsi @@ -185,22 +185,19 @@ slot0_partition: partition@10000 { label = "image-0"; }; - slot0_ns_partition: partition@40000 { + slot0_ns_partition: partition@50000 { label = "image-0-nonsecure"; }; slot1_partition: partition@80000 { label = "image-1"; }; - slot1_ns_partition: partition@b0000 { + slot1_ns_partition: partition@c0000 { label = "image-1-nonsecure"; }; - scratch_partition: partition@f0000 { - label = "image-scratch"; - reg = <0x000f0000 0xa000>; - }; - storage_partition: partition@fa000 { + /* 0xf0000 to 0xf7fff reserved for TF-M partitions */ + storage_partition: partition@f8000 { label = "storage"; - reg = <0x000fa000 0x00006000>; + reg = <0x000f8000 0x00008000>; }; }; }; diff --git a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_ns.yaml b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_ns.yaml index 438b2df73928998..65f9eaad326b818 100644 --- a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_ns.yaml +++ b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_ns.yaml @@ -7,7 +7,7 @@ toolchain: - xtools - zephyr ram: 128 -flash: 256 +flash: 192 supported: - i2c - pwm diff --git a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_partition_conf.dtsi b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_partition_conf.dtsi index 2422b2fdc523b76..64591fbf9004d57 100644 --- a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_partition_conf.dtsi +++ b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_partition_conf.dtsi @@ -23,19 +23,19 @@ */ &slot0_partition { - reg = <0x00010000 0x30000>; + reg = <0x00010000 0x40000>; }; &slot0_ns_partition { - reg = <0x00040000 0x40000>; + reg = <0x00050000 0x30000>; }; &slot1_partition { - reg = <0x00080000 0x30000>; + reg = <0x00080000 0x40000>; }; &slot1_ns_partition { - reg = <0x000b0000 0x40000>; + reg = <0x000c0000 0x30000>; }; /* Default SRAM planning when building for nRF9160 with diff --git a/boards/arm/stm32f072_eval/doc/index.rst b/boards/arm/stm32f072_eval/doc/index.rst index 4872f85785b8e08..49b6577935c7c4c 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 3756926ec4cbb75..a2c51e51cddd74c 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 e2910793d720e81..daf0e1f06d39a6d 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 a94083fa2c738a1..5a0dc214e06ed4a 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 d745a9ce8d08ca7..94536f8f05e90d4 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 f83d9615416b97d..4af3bbc0022b328 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 9b500e372fff31a..90981205b5b6776 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 dd100b28865ea2c..79577593ddbf51e 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 8ca0b33912281de..469523eadc2487b 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 c8038a6da729a4f..344746567adfb11 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 69be74a0766323f..8d66962a35f0438 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 d15dc7728c7d32c..12a057ff1ade341 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 b79f9b18a0a0eab..8bd0bd588f10c4a 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/stm32f429i_disc1/board.cmake b/boards/arm/stm32f429i_disc1/board.cmake index 7e8103a64b0622a..402b28d32c035d6 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 1a8defe53405521..9b90abf0dbbb21b 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 60b8c2874f90686..153f0cab3a9595f 100644 --- a/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts +++ b/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts @@ -20,7 +20,7 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,ccm = &ccm0; - zephyr,display = &ili9341; + zephyr,display = <dc; }; sdram2: sdram@d0000000 { @@ -247,3 +247,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 d1426b667d5a664..98fed0614dfe4a3 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 7ba1d7c71e32c45..658f2a7b75e755c 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 8ea4ef9893c19dc..15dadab7fbf0948 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 5ebcc65c392ec41..c6e34cbbe91e3d8 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/stm32f746g_disco/doc/index.rst b/boards/arm/stm32f746g_disco/doc/index.rst index c9b77967be9de1b..714a627ec4a07c2 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/stm32f7508_dk/doc/index.rst b/boards/arm/stm32f7508_dk/doc/index.rst index a3f39f37e5e871f..699285fcd907483 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/stm32f769i_disco/doc/index.rst b/boards/arm/stm32f769i_disco/doc/index.rst index d2183087b955245..203beb6f48a9236 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/stm32g071b_disco/doc/index.rst b/boards/arm/stm32g071b_disco/doc/index.rst index d7071c3d3d2b3f2..2c9cbea31767ee1 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 3e2268446c3cb57..970ec32dd0ab5b2 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 f7806f52dde2738..a41a12f0c821a8d 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/Kconfig.defconfig b/boards/arm/stm32h735g_disco/Kconfig.defconfig index 42de4573d83ce41..72308958d7b37b3 100644 --- a/boards/arm/stm32h735g_disco/Kconfig.defconfig +++ b/boards/arm/stm32h735g_disco/Kconfig.defconfig @@ -8,6 +8,13 @@ if BOARD_STM32H735G_DISCO config BOARD default "stm32h735g_disco" +if NETWORKING + +config NET_L2_ETHERNET + default y + +endif # NETWORKING + config SPI_STM32_INTERRUPT default y depends on SPI diff --git a/boards/arm/stm32h735g_disco/doc/index.rst b/boards/arm/stm32h735g_disco/doc/index.rst index 210756e15675642..e4bf324650be36a 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 29eef0e5326efbe..8443c222abdbc47 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 a679deb18d4f197..c0983f46f4f204c 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 000000000000000..2f480bd7966c464 --- /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 b0b8e82485875c9..00da755afb03e36 100644 --- a/boards/arm/stm32h747i_disco/board.cmake +++ b/boards/arm/stm32h747i_disco/board.cmake @@ -1,11 +1,16 @@ # SPDX-License-Identifier: Apache-2.0 if(CONFIG_BOARD_STM32H747I_DISCO_M7) +board_runner_args(jlink "--device=STM32H747ZI_M7") board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd_stm32h747i_disco_m7.cfg") board_runner_args(openocd --target-handle=_CHIPNAME.cpu0) elseif(CONFIG_BOARD_STM32H747I_DISCO_M4) +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 000000000000000..bd1565960d51705 --- /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 d020a3ed94e48d8..fa668e964c7503d 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_m7.dts b/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts index 8f6f519186d3461..514047c8a55bcbd 100644 --- a/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts +++ b/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts @@ -78,6 +78,16 @@ status = "okay"; }; +&pll2 { + div-m = <5>; + mul-n = <96>; + div-p = <2>; + div-q = <4>; + div-r = <10>; + clocks = <&clk_hse>; /* Assuming 25MHz HSE */ + status = "okay"; +}; + &rcc { clocks = <&pll>; clock-frequency = ; @@ -202,8 +212,12 @@ zephyr_udc0: &usbotg_hs { &sdmmc1 { status = "okay"; + clocks = <&rcc STM32_CLOCK_BUS_AHB3 0x00010000>, + <&rcc STM32_SRC_PLL2_R SDMMC_SEL(1)>; pinctrl-0 = <&sdmmc1_d0_pc8 &sdmmc1_d1_pc9 &sdmmc1_d2_pc10 &sdmmc1_d3_pc11 + &sdmmc1_d4_pb8 &sdmmc1_d5_pb9 + &sdmmc1_d6_pc6 &sdmmc1_d7_pc7 &sdmmc1_ck_pc12 &sdmmc1_cmd_pd2>; pinctrl-names = "default"; cd-gpios = <&gpioi 8 GPIO_ACTIVE_LOW>; diff --git a/boards/arm/stm32h750b_dk/Kconfig.board b/boards/arm/stm32h750b_dk/Kconfig.board new file mode 100644 index 000000000000000..afa014895282129 --- /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 000000000000000..48576f5706d3e01 --- /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 000000000000000..d5b1e5204594a0f --- /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 000000000000000..6500e7b1a4a9147 --- /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 000000000000000..7a01651524020a3 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 000000000000000..6ac1aa15d34d8a4 --- /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 000000000000000..efe4b7b2743413c --- /dev/null +++ b/boards/arm/stm32h750b_dk/stm32h750b_dk.dts @@ -0,0 +1,167 @@ +/* + * 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@0 { + compatible = "st,stm32-qspi-nor"; + reg = <0>; + qspi-max-frequency = <72000000>; + size = ; /* 64 MBytes */ + 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@1 { + compatible = "st,stm32-qspi-nor"; + reg = <1>; + 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 000000000000000..126376b1464edae --- /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 000000000000000..64cab9ff714377c --- /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 000000000000000..e77a5dbb76c7082 --- /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 549594bb3cc8b3c..83d188584265096 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 e9acb61b8207751..b8b781b3fa107a5 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>; @@ -259,13 +261,6 @@ spi-bus-width = ; data-rate = ; status = "okay"; - sfdp-bfp = [ - 53 46 44 50 06 01 02 ff - 00 06 01 10 30 00 00 ff - C2 00 01 04 10 01 00 ff - 84 00 01 02 C0 00 00 ff - 00 00 00 00 - ]; partitions { compatible = "fixed-partitions"; diff --git a/boards/arm/stm32l1_disco/doc/index.rst b/boards/arm/stm32l1_disco/doc/index.rst index 65bb4bc028f47dd..a968cebc7928f4e 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 bd4b2a5a6d5a5b9..65eef57c609f9cc 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 0bd31e72c38c0fd..e8bc81f092b9e8a 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/stm32l4r9i_disco/Kconfig.board b/boards/arm/stm32l4r9i_disco/Kconfig.board new file mode 100644 index 000000000000000..57da0f65fdfa8ca --- /dev/null +++ b/boards/arm/stm32l4r9i_disco/Kconfig.board @@ -0,0 +1,8 @@ +# STM32L4R9I Discovery board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_STM32L4R9I_DISCO + bool "STM32L4R9I Discovery Development Board" + depends on SOC_STM32L4R9XX diff --git a/boards/arm/stm32l4r9i_disco/Kconfig.defconfig b/boards/arm/stm32l4r9i_disco/Kconfig.defconfig new file mode 100644 index 000000000000000..82eafa627443889 --- /dev/null +++ b/boards/arm/stm32l4r9i_disco/Kconfig.defconfig @@ -0,0 +1,11 @@ +# STM32L4R9I Discovery board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_STM32L4R9I_DISCO + +config BOARD + default "stm32l4r9i_disco" + +endif # BOARD_STM32L4R9I_DISCO diff --git a/boards/arm/stm32l4r9i_disco/arduino_r3_connector.dtsi b/boards/arm/stm32l4r9i_disco/arduino_r3_connector.dtsi new file mode 100644 index 000000000000000..29b56539b704ec6 --- /dev/null +++ b/boards/arm/stm32l4r9i_disco/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 &gpioc 4 0>, /* A1 */ + <2 0 &gpioc 3 0>, /* A2 */ + <3 0 &gpiob 0 0>, /* A3 */ + <4 0 &gpioa 0 0>, /* A4 */ + <5 0 &gpioa 5 0>, /* A5 */ + <6 0 &gpioc 0 0>, /* D0 */ + <7 0 &gpioc 1 0>, /* D1 */ + <8 0 &gpiog 11 0>, /* D2 */ + <9 0 &gpiof 10 0>, /* D3 */ + <10 0 &gpiog 6 0>, /* D4 */ + <11 0 &gpioa 1 0>, /* D5 */ + <12 0 &gpiob 4 0>, /* D6 */ + <13 0 &gpioa 4 0>, /* D7 */ + <14 0 &gpioh 15 0>, /* D8 */ + <15 0 &gpioh 13 0>, /* D9 */ + <16 0 &gpioi 0 0>, /* D10 */ + <17 0 &gpiob 15 0>, /* D11 */ + <18 0 &gpiob 14 0>, /* D12 */ + <19 0 &gpiob 13 0>, /* D13 */ + <20 0 &gpiog 8 0>, /* D14 */ + <21 0 &gpiog 7 0>; /* D15 */ + }; +}; + +arduino_i2c: &i2c3 {}; +arduino_spi: &spi2 {}; diff --git a/boards/arm/stm32l4r9i_disco/board.cmake b/boards/arm/stm32l4r9i_disco/board.cmake new file mode 100644 index 000000000000000..c88ae7d0783585e --- /dev/null +++ b/boards/arm/stm32l4r9i_disco/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=STM32L4R9AI" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/stm32l4r9i_disco/doc/img/stm32l4r9i_disco.jpg b/boards/arm/stm32l4r9i_disco/doc/img/stm32l4r9i_disco.jpg new file mode 100644 index 000000000000000..06914737b5b6b4c Binary files /dev/null and b/boards/arm/stm32l4r9i_disco/doc/img/stm32l4r9i_disco.jpg differ diff --git a/boards/arm/stm32l4r9i_disco/doc/index.rst b/boards/arm/stm32l4r9i_disco/doc/index.rst new file mode 100644 index 000000000000000..0f651e2b9ffc254 --- /dev/null +++ b/boards/arm/stm32l4r9i_disco/doc/index.rst @@ -0,0 +1,150 @@ +.. _stm32l4r9i_disco_board: + +ST STM32L4R9I Discovery +####################### + +Overview +******** + +The 32L4R9IDISCOVERY Discovery kit is a complete demonstration and development platform +for STMicroelectronics Arm® Cortex®-M4 core-based STM32L4R9AI microcontroller. + +Leveraging the innovative ultra-low-power oriented features, 640 Kbytes of embedded RAM, +graphics performance (Chrom-ART Accelerator), and DSI controller offered by the STM32L4R9AI, +the 32L4R9IDISCOVERY Discovery kit enables users to easily prototype applications with +state-of-the-art energy efficiency, as well as stunning audio and graphics rendering with direct +support for AMOLED DSI round LCD display. + +For even more user-friendliness, the on-board ST-LINK/V2-1 debugger provides out-of-the-box +programming and debugging capabilities. + +.. image:: img/stm32l4r9i_disco.jpg + :align: center + :alt: STM32L4R9I-DISCO + +More information about the board can be found at the `STM32L4R9I-DISCOVERY website`_. +More information about STM32L4R9 can be found here: + +- `STM32L4R9/S9 on www.st.com`_ +- `STM32L4+ Series reference manual`_ +- `STM32L4R5xx/R7xx/R9xx datasheet`_ + +Supported Features +================== + +The current Zephyr stm32l4r9i_disco board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| FLASH | on-chip | on-chip flash memory; | +| | | external OctoSPI memory | ++-----------+------------+-------------------------------------+ +| ADC | on-chip | ADC Controller | ++-----------+------------+-------------------------------------+ +| RTC | on-chip | Real Time Clock | ++-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++-----------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++-----------+------------+-------------------------------------+ +| PWM | on-chip | pwm | ++-----------+------------+-------------------------------------+ +| SDMMC | on-chip | sd/mmc | ++-----------+------------+-------------------------------------+ + +Other hardware features are not yet supported on Zephyr porting. + +The default configuration can be found in the defconfig file: + + ``boards/arm/stm32l4r9i_disco/stm32l4r9i_disco_defconfig`` + + +Pin Mapping +=========== + +For more details, please refer to `STM32L4R9I-DISCOVERY website`_. + +System Clock +============ + +The STM32L4R9AI 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 120MHz. PLL clock is driven by a 4MHz medium speed internal clock. + +Serial Port +=========== + +The STM32L4R9I Discovery board has up to 6 U(S)ARTs. +The Zephyr console output is assigned to UART2, which is connected to the onboard +ST-LINK Virtual COM port interface. Default communication settings are 115200 8N1. + + +Programming and Debugging +************************* + +Flashing +======== + +The STM32L4R9I Discovery board includes an ST-LINK/V2-1 debug tool. + +Applications for the ``stm32l4r9i_disco`` 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 STM32L4R9I Discovery +----------------------------------------------- + +Connect the STM32L4R9I Discovery 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: stm32l4r9i_disco + :goals: build flash + +You should see the following message in the serial host program: + +.. code-block:: console + + $ Hello World! stm32l4r9i_disco + + +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: stm32l4r9i_disco + :goals: debug + +.. _STM32L4R9I-DISCOVERY website: + https://www.st.com/en/evaluation-tools/32l4r9idiscovery.html + +.. _STM32L4R9/S9 on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32l4r9-s9.html + +.. _STM32L4+ Series reference manual: + https://www.st.com/resource/en/reference_manual/rm0432-stm32l4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + +.. _STM32L4R5xx/R7xx/R9xx datasheet: + https://www.st.com/resource/en/datasheet/stm32l4r5vi.pdf diff --git a/boards/arm/stm32l4r9i_disco/stm32l4r9i_disco.dts b/boards/arm/stm32l4r9i_disco/stm32l4r9i_disco.dts new file mode 100644 index 000000000000000..8a4833e8c972168 --- /dev/null +++ b/boards/arm/stm32l4r9i_disco/stm32l4r9i_disco.dts @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; +#include +#include +#include +#include "arduino_r3_connector.dtsi" + +/ { + model = "STMicroelectronics STM32L4R9I-DISCO board"; + compatible = "st,stm32l4r9i-disco"; + + chosen { + zephyr,console = &usart2; + zephyr,shell-uart = &usart2; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + leds { + compatible = "gpio-leds"; + /* N.B. LD1 (orange) is not wired to MCU */ + green_led: led_2 { + gpios = <&gpioh 4 GPIO_ACTIVE_LOW>; + label = "User LD2"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + joy_sel: joystick_selection { + label = "joystick selection"; + gpios = <&gpioc 13 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &green_led; + sw0 = &joy_sel; + die-temp0 = &die_temp; + volt-sensor0 = &vref; + volt-sensor1 = &vbat; + spi-flash0 = &mx25lm51245; + }; +}; + +&clk_lse { + status = "okay"; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk_hsi { + status = "okay"; +}; + +&clk_msi { + status = "okay"; + msi-range = <6>; + msi-pll-mode; +}; + +&pll { + status = "okay"; + div-m = <1>; + mul-n = <60>; + /* + * WORKAROUND: stm32l4-pll-clock does not allow arbitrary PLLP dividers. + * Disable PLLP completely since it only feeds SAI, which is not active either. + */ + /* div-p = <5>; */ + div-q = <2>; + div-r = <2>; + clocks = <&clk_msi>; +}; + +&rcc { + clocks = <&pll>; + ahb-prescaler = <1>; + clock-frequency = ; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&usart2 { + status = "okay"; + pinctrl-0 = <&usart2_tx_pa2 &usart2_rx_pa3>; + pinctrl-names = "default"; + current-speed = <115200>; +}; + +&lpuart1 { + status = "okay"; + pinctrl-0 = <&lpuart1_tx_pc1 &lpuart1_rx_pc0>; + pinctrl-names = "default"; + current-speed = <115200>; +}; + +&timers3 { + status = "okay"; + + pwm3: pwm { + status = "okay"; + /* + * N.B.: Datasheet indicates that ARD_D11 (wired to PB15) is connected to TIM3_CH2. + * However, this is incorrect as PB15 cannot be muxed to TIM3 (see DS12023). + * Moved ARD_D11 to TIM15_CH2 instead. + */ + pinctrl-0 = <&tim3_ch1_pb4>; + pinctrl-names = "default"; + }; +}; + +&timers5 { + status = "okay"; + + pwm5: pwm { + status = "okay"; + pinctrl-0 = <&tim5_ch2_pa1 &tim5_ch4_pi0>; + pinctrl-names = "default"; + }; +}; + +&timers8 { + status = "okay"; + + pwm8: pwm { + status = "okay"; + pinctrl-0 = <&tim8_ch1n_ph13>; + pinctrl-names = "default"; + }; +}; + +&timers15 { + status = "okay"; + + pwm15: pwm { + status = "okay"; + pinctrl-0 = <&tim15_ch2_pf10 &tim15_ch2_pb15>; + pinctrl-names = "default"; + }; +}; + +&i2c1 { + status = "okay"; + pinctrl-0 = <&i2c1_scl_pb6 &i2c1_sda_pg13>; + pinctrl-names = "default"; + clock-frequency = ; +}; + +&i2c3 { + status = "okay"; + pinctrl-0 = <&i2c3_scl_pg7 &i2c3_sda_pg8>; + pinctrl-names = "default"; + clock-frequency = ; +}; + +&spi2 { + status = "okay"; + pinctrl-0 = <&spi2_sck_pb13 &spi2_miso_pb14 &spi2_mosi_pb15>; + pinctrl-names = "default"; + cs-gpios = <&gpioi 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; +}; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; + status = "okay"; +}; + +&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"; +}; + +&adc1 { + status = "okay"; + pinctrl-0 = <&adc1_in5_pa0 &adc1_in12_pa7 &adc1_in15_pb0 + &adc1_in4_pc3 &adc1_in13_pc4>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <1>; +}; + +zephyr_udc0: &usbotg_fs { + status = "okay"; + pinctrl-0 = <&usb_otg_fs_dm_pa11 &usb_otg_fs_dp_pa12 + &usb_otg_fs_id_pa10>; + pinctrl-names = "default"; +}; + +&die_temp { + status = "okay"; +}; + +&vref { + status = "okay"; +}; + +&vbat { + status = "okay"; +}; + +&octospi2 { + status = "okay"; + pinctrl-0 = <&octospim_p2_clk_pi6 &octospim_p2_ncs_pg12 + &octospim_p2_io0_pi11 &octospim_p2_io1_pi10 + &octospim_p2_io2_pi9 &octospim_p2_io3_ph8 + &octospim_p2_io4_ph9 &octospim_p2_io5_ph10 + &octospim_p2_io6_pg9 &octospim_p2_io7_pg10 + &octospim_p2_dqs_pg15>; + pinctrl-names = "default"; + + mx25lm51245: ospi-nor-flash@0 { + status = "okay"; + compatible = "st,stm32-ospi-nor"; + reg = <0>; + ospi-max-frequency = ; + size = ; /* 512 Mbits = 64 MBytes */ + spi-bus-width = ; + data-rate = ; + four-byte-opcodes; + sfdp-bfp = [ + 53 46 44 50 06 01 02 ff + 00 06 01 10 30 00 00 ff + c2 00 01 04 10 01 00 ff + 84 00 01 02 c0 00 00 ff + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + e5 20 fb ff ff ff ff 1f + 44 eb 08 6b 08 3b 04 bb + fe ff ff ff ff ff 00 ff + ff ff 44 eb 0c 20 0f 52 + 10 d8 00 ff d6 49 c5 00 + 81 df 04 e3 44 03 67 38 + 30 b0 30 b0 f7 bd d5 5c + 4a 9e 29 ff f0 50 f9 85 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 + 7f ef ff ff 21 5c dc ff + ]; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + reg = <0x00000000 DT_SIZE_M(64)>; + }; + }; + }; +}; diff --git a/boards/arm/stm32l4r9i_disco/stm32l4r9i_disco.yaml b/boards/arm/stm32l4r9i_disco/stm32l4r9i_disco.yaml new file mode 100644 index 000000000000000..89ab98c92b108c2 --- /dev/null +++ b/boards/arm/stm32l4r9i_disco/stm32l4r9i_disco.yaml @@ -0,0 +1,25 @@ +identifier: stm32l4r9i_disco +name: ST STM32L4R9I Discovery +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 640 +flash: 2048 +vendor: st +supported: + - adc + - arduino_gpio + - arduino_i2c + - arduino_spi + - gpio + - i2c + - pwm + - rtc + - sdhc + - spi + - uart + - usb + - usb_device diff --git a/boards/arm/stm32l4r9i_disco/stm32l4r9i_disco_defconfig b/boards/arm/stm32l4r9i_disco/stm32l4r9i_disco_defconfig new file mode 100644 index 000000000000000..546bd3379a85471 --- /dev/null +++ b/boards/arm/stm32l4r9i_disco/stm32l4r9i_disco_defconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_STM32L4X=y +CONFIG_SOC_STM32L4R9XX=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable UART +CONFIG_SERIAL=y + +# Enable 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/stm32l4r9i_disco/support/openocd.cfg b/boards/arm/stm32l4r9i_disco/support/openocd.cfg new file mode 100644 index 000000000000000..295299f2fbec9fe --- /dev/null +++ b/boards/arm/stm32l4r9i_disco/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/stm32l562e_dk/CMakeLists.txt b/boards/arm/stm32l562e_dk/CMakeLists.txt index dde73804665192d..f6ca91f1a73b492 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 1fe37f3e0a4f394..3a81889dc71c673 100644 --- a/boards/arm/stm32l562e_dk/Kconfig.defconfig +++ b/boards/arm/stm32l562e_dk/Kconfig.defconfig @@ -8,10 +8,6 @@ if BOARD_STM32L562E_DK config BOARD default "stm32l562e_dk" -# LPTIM clocked by LSE, force tick freq to 4096 for tick accuracy -config SYS_CLOCK_TICKS_PER_SEC - default 4096 if STM32_LPTIM_TIMER - if BT config SPI @@ -21,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 5a4f5845617f15b..16af6cb242b6fe7 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.yaml b/boards/arm/stm32l562e_dk/stm32l562e_dk.yaml index dcb6a01d5dbbef4..dcbe7539d6482d6 100644 --- a/boards/arm/stm32l562e_dk/stm32l562e_dk.yaml +++ b/boards/arm/stm32l562e_dk/stm32l562e_dk.yaml @@ -15,6 +15,7 @@ supported: - dac - adc - spi + - ble - dma - usart - arduino_spi diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi index 14f11ece9a9c1ff..7c91d04cbb57eb6 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,15 +111,16 @@ &spi1 { pinctrl-0 = <&spi1_sck_pg2 &spi1_miso_pg3 &spi1_mosi_pg4>; pinctrl-names = "default"; - cs-gpios = <&gpiog 5 (GPIO_ACTIVE_HIGH | 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>; + reset-gpios = <&gpiog 8 GPIO_ACTIVE_LOW>; + spi-max-frequency = ; + spi-hold-cs; }; }; diff --git a/boards/arm/stm32u5a9j_dk/Kconfig.board b/boards/arm/stm32u5a9j_dk/Kconfig.board new file mode 100644 index 000000000000000..8482aa58f0447a3 --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/Kconfig.board @@ -0,0 +1,8 @@ +# STM32U5A9J Discovery Kit board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_STM32U5A9J_DK + bool "STM32U5A9J Discovery Kit Development Board" + depends on SOC_STM32U5A9XX diff --git a/boards/arm/stm32u5a9j_dk/Kconfig.defconfig b/boards/arm/stm32u5a9j_dk/Kconfig.defconfig new file mode 100644 index 000000000000000..8124e0227409ab9 --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/Kconfig.defconfig @@ -0,0 +1,11 @@ +# STM32U5A9J DISCOVERY KIT board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_STM32U5A9J_DK + +config BOARD + default "stm32u5a9j_dk" + +endif # BOARD_STM32U5A9J_DK diff --git a/boards/arm/stm32u5a9j_dk/board.cmake b/boards/arm/stm32u5a9j_dk/board.cmake new file mode 100644 index 000000000000000..dadc06c643e0895 --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/board.cmake @@ -0,0 +1,11 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(stm32cubeprogrammer "--erase" "--port=swd" "--reset-mode=hw") + +board_runner_args(openocd "--tcl-port=6666") +board_runner_args(openocd --cmd-pre-init "gdb_report_data_abort enable") +board_runner_args(openocd "--no-halt") + +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/arm/stm32u5a9j_dk/doc/img/bottom_view.jpg b/boards/arm/stm32u5a9j_dk/doc/img/bottom_view.jpg new file mode 100644 index 000000000000000..4d1c1dca173bbc3 Binary files /dev/null and b/boards/arm/stm32u5a9j_dk/doc/img/bottom_view.jpg differ diff --git a/boards/arm/stm32u5a9j_dk/doc/img/top_view.jpg b/boards/arm/stm32u5a9j_dk/doc/img/top_view.jpg new file mode 100644 index 000000000000000..5d3c40350612a29 Binary files /dev/null and b/boards/arm/stm32u5a9j_dk/doc/img/top_view.jpg differ diff --git a/boards/arm/stm32u5a9j_dk/doc/index.rst b/boards/arm/stm32u5a9j_dk/doc/index.rst new file mode 100644 index 000000000000000..23859666df7abc5 --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/doc/index.rst @@ -0,0 +1,198 @@ +.. _stm32u5a9j_dk_board: + +ST STM32U5A9J Discovery Kit +########################### + +Overview +******** + +The STM32U5A9J-DK Discovery kit is a complete demonstration and development +platform for the STM32U5A9NJH6Q microcontroller, featuring an Arm® Cortex®-M33 +core with Arm® TrustZone®. + +Leveraging the innovative ultra-low-power oriented features, 2.5 Mbytes of +embedded SRAM, 4 Mbytes of embedded flash memory, and rich graphics features, +the STM32U5A9J-DK Discovery kit enables users to easily prototype applications +with state-of-the-art energy efficiency, as well as providing stunning and +optimized graphics rendering with the support of the 2.5D NeoChrom Accelerator, +Chrom-ART Accelerator, and Chrom-GRC™ MMU. + +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 a 2.47-inch RGB 480x480 pixels TFT round LCD module with MIPI DSI® +interface and capacitive touch panel, USB Type-C® HS, Octo-SPI flash memory +device, Hexadeca-SPI PSRAM memory device, eMMC flash memory device, +Time-of-Flight and gesture detection sensor, temperature sensor, and two 2.54 mm +pitch double-row flexible expansion connectors for easy prototyping with +daughterboards for specific applications (USART, LPUART, two SPIs, SAI, three +I2C, SDMMC, ADCs, timers, and GPIOs). + +The STM32U5A9J-DK Discovery kit integrates an STLINK-V3E embedded in-circuit +debugger and programmer for the STM32 microcontroller with a USB Virtual COM +port bridge and comes with the STM32CubeU5 MCU Package, which provides an STM32 +comprehensive software HAL library as well as various software examples. + +.. image:: img/top_view.jpg + :align: center + :alt: STM32U5A9J-DK Top View + +.. image:: img/bottom_view.jpg + :align: center + :alt: STM32U5A9J-DK Bottom View + +More information about the board can be found at the `STM32U5A9J-DK website`_. +More information about STM32U5A9NJH6Q can be found here: + +- `STM32U5A9NJ on www.st.com`_ +- `STM32U5 Series reference manual`_ +- `STM32U5Axxx datasheet`_ + +Supported Features +================== + +The current Zephyr stm32u5a9j_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 | ++-----------+------------+-------------------------------------+ +| LPUART | on-chip | low power uart | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| RNG | on-chip | True Random number generator | ++-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++-----------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++-----------+------------+-------------------------------------+ +| FLASH | on-chip | flash memory | ++-----------+------------+-------------------------------------+ +| ADC | on-chip | adc | ++-----------+------------+-------------------------------------+ +| SDMMC | on-chip | flash memory | ++-----------+------------+-------------------------------------+ +| WATCHDOG | on-chip | independent watchdog | ++-----------+------------+-------------------------------------+ +| PWM | on-chip | pwm | ++-----------+------------+-------------------------------------+ + +Other hardware features have not been enabled yet for this board. + +The default configuration per core can be found in the defconfig file: +``boards/arm/stm32u5a9j_dk/stm32u5a9j_dk_defconfig`` + +Pin Mapping +=========== + +For more details please refer to `STM32U5A9J-DK board User Manual`_. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- USART_1 TX/RX : PA9/PA10 (ST-Link Virtual Port Com) +- LD3 : PE0 +- LD4 : PE1 +- User Button: PC13 +- USART_3 TX/RX : PB10/PB11 +- LPUART_1 TX/RX : PG7/PG8 +- I2C1 SCL/SDA : PG14/PG13 +- I2C2 SCL/SDA : PF1/PF0 +- I2C6 SCL/SDA : PD1/PD0 +- SPI2 SCK/MISO/MOSI/CS : PB13/PD3/PD4/PB12 +- SPI3 SCK/MISO/MOSI/CS : PG9/PG10/PG11/PG15 +- ADC1 : channel5 PA0, channel14 PC5 +- ADC2 : channel9 PA4 +- ADC4 : channel5 PF14 + +System Clock +============ + +The STM32U5A9J-DK Discovery kit relies on an HSE oscillator (16 MHz crystal) +and an LSE oscillator (32.768 kHz crystal) as clock references. +Using the HSE (instead of HSI) is mandatory to manage the DSI interface for +the LCD module and the USB high‑speed interface. + +Serial Port +=========== + +The STM32U5A9J Discovery kit has up to 4 USARTs, 2 UARTs, and 1 LPUART. +The Zephyr console output is assigned to USART1 which connected to the onboard +ST-LINK/V3.0. Virtual COM port interface. Default communication settings are +115200 8N1. + + +Programming and Debugging +************************* + +STM32U5A9J Discovery kit includes an ST-LINK/V3 embedded debug tool interface. +This probe allows to flash and debug the board using various tools. + +Flashing +======== + +Board is configured to be flashed using west STM32CubeProgrammer runner. +Installation of `STM32CubeProgrammer`_ is then required to flash the board., + +Connect the STM32U5A9J Discovery board to your host computer using the USB +port, then run a serial host program to connect with your Discovery +board. For example: + +.. code-block:: console + + $ minicom -D /dev/ttyACM0 -b 115200 + +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: stm32u5a9j_dk + :goals: build flash + +You should see the following message on the console: + +.. code-block:: console + + Hello World! stm32u5a9j_dk + +Debugging +========= + +Default debugger for this board is openocd. It could be used in the usual way +with "west debug" command. +Here is an example for the :zephyr:code-sample:`blinky` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: stm32u5a9j_dk + :goals: debug + + +.. _STM32U5A9J-DK website: + https://www.st.com/en/evaluation-tools/stm32u5a9j-dk.html + +.. _STM32U5A9J-DK board User Manual: + https://www.st.com/resource/en/user_manual/um2967-discovery-kit-with-stm32u5a9nj-mcu-stmicroelectronics.pdf + +.. _STM32U5A9NJ on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32u5a9nj.html + +.. _STM32U5 Series reference manual: + https://www.st.com/resource/en/reference_manual/rm0456-stm32u5-series-armbased-32bit-mcus-stmicroelectronics.pdf + +.. _STM32U5Axxx datasheet: + https://www.st.com/resource/en/datasheet/stm32u5a9nj.pdf + +.. _STM32CubeProgrammer: + https://www.st.com/en/development-tools/stm32cubeprog.html + +.. _STM32U5A9J_DK board schematics: + https://www.st.com/resource/en/schematic_pack/mb1829-u5a9njq-b01-schematic.pdf diff --git a/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts new file mode 100644 index 000000000000000..6f80a4061a49e4a --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "STMicroelectronics STM32U5A9J DISCOVERY KIT board"; + compatible = "st,stm32u5a9j-dk"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + leds { + compatible = "gpio-leds"; + green_led_0: led_3 { + gpios = <&gpioe 0 GPIO_ACTIVE_HIGH>; + label = "User LD3"; + }; + red_led_0: led_4 { + gpios = <&gpioe 1 GPIO_ACTIVE_HIGH>; + label = "User LD4"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: button_0 { + label = "User"; + gpios = <&gpioc 13 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + zephyr,code = ; + }; + }; + + dsi_lcd_qsh_030: connector_dsi_lcd { + compatible = "st,dsi-lcd-qsh-030"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <4 0 &gpioe 8 0>, /* TOUCH_INT */ + <22 0 &gpiod 8 0>, /* SPI chip SEL */ + <24 0 &gpiob 13 0>, /* SPI CLK */ + <26 0 &gpiod 4 0>, /* SPI MOSI */ + <28 0 &gpiod 11 0>, /* SPI DCX */ + <35 0 &gpioe 5 0>, /* SCLK/MCLK */ + <37 0 &gpioe 4 0>, /* LRCLK */ + <40 0 &gpioh 4 0>, /* I2C5_SDA */ + <43 0 &gpioi 7 0>, /* SWIRE */ + <44 0 &gpioh 5 0>, /* I2C5_SCL */ + <49 0 &gpiof 11 0>, /* DSI_TE */ + <53 0 &gpioi 6 0>, /* LCD_BL_CTRL */ + <57 0 &gpiod 5 0>; /* DSI_RESET */ + }; + + aliases { + led0 = &green_led_0; + led1 = &red_led_0; + sw0 = &user_button; + sdhc0 = &sdmmc1; + watchdog0 = &iwdg; + die-temp0 = &die_temp; + volt-sensor0 = &vref1; + volt-sensor1 = &vbat4; + }; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk_hse { + clock-frequency = ; + status = "okay"; +}; + +&clk_msis { + status = "okay"; + msi-range = <4>; /* 4MHz (reset value) */ + msi-pll-mode; +}; + +&pll1 { + div-m = <1>; + mul-n = <80>; + div-p = <2>; + div-q = <2>; + div-r = <2>; + clocks = <&clk_msis>; + status = "okay"; +}; + +&rcc { + clocks = <&pll1>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; + apb3-prescaler = <1>; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +uart0: &usart3 { + pinctrl-0 = <&usart3_tx_pb10 &usart3_rx_pb11>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&lpuart1 { + pinctrl-0 = <&lpuart1_tx_pg7 &lpuart1_rx_pg8>; + pinctrl-names = "default"; + current-speed = <9600>; + status = "okay"; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_scl_pg14 &i2c1_sda_pg13>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&i2c2 { + pinctrl-0 = <&i2c2_scl_pf1 &i2c2_sda_pf0>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&i2c6 { + pinctrl-0 = <&i2c6_scl_pd1 &i2c6_sda_pd0>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&spi2 { + pinctrl-0 = <&spi2_sck_pb13 &spi2_miso_pd3 &spi2_mosi_pd4>; + pinctrl-names = "default"; + cs-gpios = <&gpiob 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; +}; + +&spi3 { + pinctrl-0 = <&spi3_sck_pg9 &spi3_miso_pg10 &spi3_mosi_pg11>; + pinctrl-names = "default"; + cs-gpios = <&gpiog 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; +}; + +&timers1 { + st,prescaler = <1>; + status = "okay"; + + pwm1: pwm { + status = "okay"; + pinctrl-0 = <&tim1_ch2_pe11>; + pinctrl-names = "default"; + }; +}; + +&timers2 { + st,prescaler = <1>; + status = "okay"; + + pwm2: pwm { + status = "okay"; + pinctrl-0 = <&tim2_ch4_pa3>; + pinctrl-names = "default"; + }; +}; + +&sdmmc1 { + pinctrl-0 = <&sdmmc1_d0_pc8 &sdmmc1_d1_pc9 + &sdmmc1_d2_pc10 &sdmmc1_d3_pc11 + &sdmmc1_d4_pb8 &sdmmc1_d5_pb9 + &sdmmc1_d6_pc6 &sdmmc1_d7_pc7 + &sdmmc1_ck_pc12 &sdmmc1_cmd_pd2>; + pinctrl-names = "default"; + status = "okay"; +}; + +&sdmmc2 { + pinctrl-0 = <&sdmmc2_d0_pb14 &sdmmc2_d1_pb15 + &sdmmc2_d2_pb3 &sdmmc2_d3_pb4 + &sdmmc2_ck_pd6 &sdmmc2_cmd_pd7>; + pinctrl-names = "default"; + status = "okay"; +}; + +&adc1 { + pinctrl-0 = <&adc1_in5_pa0 &adc1_in14_pc5>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <1>; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + channel@5 { + reg = <0x5>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <14>; + }; + + channel@e { + reg = <0xe>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <14>; + }; +}; + +&adc4 { + pinctrl-0 = <&adc4_in5_pf14>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <1>; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + channel@5 { + reg = <0x5>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * Following flash partition is dedicated to the use of bootloader + */ + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_K(1952)>; + }; + slot1_partition: partition@1f8000 { + label = "image-1"; + reg = <0x001f8000 DT_SIZE_K(1960)>; + }; + storage_partition: partition@3e2000 { + label = "storage"; + reg = <0x003e2000 DT_SIZE_K(120)>; + }; + }; +}; + +&iwdg { + status = "okay"; +}; + +&rng { + status = "okay"; +}; + +&die_temp { + status = "okay"; +}; + +&vref1 { + status = "okay"; +}; + +&vbat4 { + status = "okay"; +}; diff --git a/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.yaml b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.yaml new file mode 100644 index 000000000000000..82ada8651e9014c --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.yaml @@ -0,0 +1,23 @@ +identifier: stm32u5a9j_dk +name: ST STM32U5A9J-DK Discovery Kit +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - led + - button + - adc + - uart + - usart + - lpuart + - watchdog + - spi + - i2c + - flash + - sdmmc +ram: 2496 +flash: 4096 +vendor: st diff --git a/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk_defconfig b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk_defconfig new file mode 100644 index 000000000000000..71e92cf0450d6a0 --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk_defconfig @@ -0,0 +1,28 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +# Set SoC present on the board +CONFIG_SOC_SERIES_STM32U5X=y +CONFIG_SOC_STM32U5A9XX=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable serial +CONFIG_SERIAL=y + +# Enable console +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/stm32u5a9j_dk/support/openocd.cfg b/boards/arm/stm32u5a9j_dk/support/openocd.cfg new file mode 100644 index 000000000000000..23e2409440fecae --- /dev/null +++ b/boards/arm/stm32u5a9j_dk/support/openocd.cfg @@ -0,0 +1,46 @@ +source [find interface/stlink-dap.cfg] + +set WORKAREASIZE 0x8000 + +transport select "dapdirect_swd" + +set CHIPNAME STM32U5A9NJHxQ +set BOARDNAME STM32U5A9J_DK + +# 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 connect_assert_srst +set CONNECT_UNDER_RESET 1 +set CORE_RESET 0 + +# ACCESS PORT NUMBER +set AP_NUM 0 +# GDB PORT +set GDB_PORT 3333 + +# BCTM CPU variables + +source [find target/stm32u5x.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 +} + +gdb_memory_map disable diff --git a/boards/arm/stm32vl_disco/doc/index.rst b/boards/arm/stm32vl_disco/doc/index.rst index 006c8854bb4ab31..7819200bafb30e0 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 000000000000000..28ca74d81a95081 --- /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 000000000000000..5ce31881bd079a4 --- /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 000000000000000..47fc12f130886e8 --- /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 000000000000000..0e9cc26ac2013eb 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 000000000000000..61b701066014d5b --- /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 000000000000000..4f4fb99cea013de --- /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 000000000000000..63c75d4473fb1fc --- /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 000000000000000..9fdd732848efc42 --- /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 000000000000000..2ad582703684ce1 --- /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 000000000000000..4fe8c22fd7cfa27 --- /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 000000000000000..cedb62395be1394 --- /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 000000000000000..47fc12f130886e8 --- /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 000000000000000..6def853b748ae2c 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 000000000000000..90561ee12753368 --- /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 000000000000000..d494b7024dc7c63 --- /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 000000000000000..2e3667f18d5494e --- /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 000000000000000..9fdd732848efc42 --- /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 000000000000000..2ad582703684ce1 --- /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 87e1e7ded414afc..4d9964bb5216fb1 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 b/boards/arm/thingy53_nrf5340/Kconfig index a907b074688b464..116fd1c8edb3125 100644 --- a/boards/arm/thingy53_nrf5340/Kconfig +++ b/boards/arm/thingy53_nrf5340/Kconfig @@ -56,7 +56,7 @@ config DOMAIN_CPUNET_BOARD 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_rpmsg on the nRF5340_cpunet for + another board. For example hci_ipc on the nRF5340_cpunet for Bluetooth applications. endif # BOARD_THINGY53_NRF5340_CPUAPP || BOARD_THINGY53_NRF5340_CPUAPP_NS diff --git a/boards/arm/thingy53_nrf5340/Kconfig.defconfig b/boards/arm/thingy53_nrf5340/Kconfig.defconfig index e4d9e63b7f17db7..12f1e5bbdc9b13b 100644 --- a/boards/arm/thingy53_nrf5340/Kconfig.defconfig +++ b/boards/arm/thingy53_nrf5340/Kconfig.defconfig @@ -59,11 +59,12 @@ endif # BOARD_THINGY53_NRF5340_CPUAPP_NS if !TRUSTED_EXECUTION_SECURE choice BT_HCI_BUS_TYPE - default BT_RPMSG if BT + default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE - default 4096 if BT_RPMSG +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 4096 if BT_HCI_IPC config BT_HAS_HCI_VS default BT diff --git a/boards/arm/thingy53_nrf5340/doc/index.rst b/boards/arm/thingy53_nrf5340/doc/index.rst index 3a77deee968ffba..4544ea7ed795d45 100644 --- a/boards/arm/thingy53_nrf5340/doc/index.rst +++ b/boards/arm/thingy53_nrf5340/doc/index.rst @@ -22,9 +22,6 @@ The nrf5340dk_nrf5340_cpuapp build target provides support for the application core on the nRF5340 SoC. The nrf5340dk_nrf5340_cpunet build target provides support for the network core on the nRF5340 SoC. -.. note:: - Trusted Firmware-M (TF-M) and building the ``ns`` target is not supported for this board. - The `Nordic Semiconductor Infocenter`_ contains the processor's information and the datasheet. diff --git a/boards/arm/thingy53_nrf5340/thingy53_nrf5340_common.dtsi b/boards/arm/thingy53_nrf5340/thingy53_nrf5340_common.dtsi index 341bb1305e19229..694a6960584e47d 100644 --- a/boards/arm/thingy53_nrf5340/thingy53_nrf5340_common.dtsi +++ b/boards/arm/thingy53_nrf5340/thingy53_nrf5340_common.dtsi @@ -13,7 +13,7 @@ zephyr,uart-mcumgr = &cdc_acm_uart; zephyr,bt-mon-uart = &cdc_acm_uart; zephyr,bt-c2h-uart = &cdc_acm_uart; - zephyr,bt-hci-rpmsg-ipc = &ipc0; + zephyr,bt-hci-ipc = &ipc0; nordic,802154-spinel-ipc = &ipc0; zephyr,ieee802154 = &ieee802154; }; diff --git a/boards/arm/thingy53_nrf5340/thingy53_nrf5340_cpunet.dts b/boards/arm/thingy53_nrf5340/thingy53_nrf5340_cpunet.dts index c88a8ab4f6a8a9b..895803a8623fad3 100644 --- a/boards/arm/thingy53_nrf5340/thingy53_nrf5340_cpunet.dts +++ b/boards/arm/thingy53_nrf5340/thingy53_nrf5340_cpunet.dts @@ -19,7 +19,7 @@ zephyr,uart-mcumgr = &uart0; zephyr,bt-mon-uart = &uart0; zephyr,bt-c2h-uart = &uart0; - zephyr,bt-hci-rpmsg-ipc = &ipc0; + zephyr,bt-hci-ipc = &ipc0; nordic,802154-spinel-ipc = &ipc0; zephyr,sram = &sram1; zephyr,flash = &flash1; diff --git a/boards/arm/twr_ke18f/doc/index.rst b/boards/arm/twr_ke18f/doc/index.rst index 336099ddca0cb86..04aa94f0dfe73df 100644 --- a/boards/arm/twr_ke18f/doc/index.rst +++ b/boards/arm/twr_ke18f/doc/index.rst @@ -113,11 +113,11 @@ accelerometer and magnetometer for sensor values (``CONFIG_FXOS8700_TRIGGER_NONE=y``). In order to support FXOS8700 triggers (interrupts) the 0 ohm resistors -``R47`` and and ``R57`` must be mounted on the TWR-KE18F board. The +``R47`` and ``R57`` must be mounted on the TWR-KE18F board. The devicetree must also be modified to describe the FXOS8700 interrupt GPIOs: -.. code-block:: none +.. code-block:: devicetree /dts-v1/; diff --git a/boards/arm/twr_ke18f/twr_ke18f-pinctrl.dtsi b/boards/arm/twr_ke18f/twr_ke18f-pinctrl.dtsi index 4e8f4849f75e742..d16cb81f89697b1 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 2495acc5e4103c5..06e2deaf3d4dd12 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 810d96c2ae602c6..6118c0c0b113283 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 070730c69d2c566..d06986a8afa2982 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 68b3755123b2895..ef145eabe54086e 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 d7a21c98b444e78..404678ad95299f4 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 000000000000000..314c7f98d5e80a5 --- /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 000000000000000..044df50c0c592f4 --- /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 000000000000000..5cb17a1b6c289e8 --- /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 000000000000000..ddd2bdafb8fd04a 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 000000000000000..e89daf9c32461c8 --- /dev/null +++ b/boards/arm/ucans32k1sic/doc/index.rst @@ -0,0 +1,196 @@ +.. _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 +============ ========== ================================ + +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 000000000000000..d2c30dc56617fb9 --- /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 000000000000000..941d2c03954b9e7 --- /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 000000000000000..db901876f1d684f --- /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 000000000000000..2bb216e63aedcc6 --- /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 000000000000000..6996a12d6d006f5 --- /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 000000000000000..96926263e21092e --- /dev/null +++ b/boards/arm/ucans32k1sic/ucans32k1sic.yaml @@ -0,0 +1,22 @@ +# 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 diff --git a/boards/arm/ucans32k1sic/ucans32k1sic_defconfig b/boards/arm/ucans32k1sic/ucans32k1sic_defconfig new file mode 100644 index 000000000000000..8580c7155cb12f6 --- /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 143c28cff93d5bc..fd067dbf8400e6d 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 80e7af563fca3a4..7673e510ebfae6c 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 f36ae79dbb4a64b..0f0c261460a1009 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 2c260552f07a0b2..e5bf38ec422334e 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 a54a2829cd76544..4aef3b4c0663c92 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 4c8f4fcc0c114cf..8a1c4b221bd4957 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 619d63eb60eff84..5f60afdddb5d026 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 23e75ab03aa5686..5ea0bde7748169d 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/verdin_imx8mp_m7/Kconfig.board b/boards/arm/verdin_imx8mp_m7/Kconfig.board new file mode 100644 index 000000000000000..fb86601179c6675 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/Kconfig.board @@ -0,0 +1,9 @@ +# VERDIN_IMX8MP_M7 board + +# Copyright (c) 2023 Toradex +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_VERDIN_IMX8MP_M7 + bool "Toradex iMX8M Plus M7" + depends on SOC_SERIES_IMX8ML_M7 + select SOC_PART_NUMBER_MIMX8ML8DVNLZ diff --git a/boards/arm/verdin_imx8mp_m7/Kconfig.defconfig b/boards/arm/verdin_imx8mp_m7/Kconfig.defconfig new file mode 100644 index 000000000000000..3c3ab2db770b285 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/Kconfig.defconfig @@ -0,0 +1,18 @@ +# VERDIN_IMX8MP_M7 board defconfig + +# Copyright (c) 2023 Toradex +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_VERDIN_IMX8MP_M7 + +config BOARD + default "verdin_imx8mp_m7" + +if !XIP +config FLASH_SIZE + default 0 +config FLASH_BASE_ADDRESS + default 0 +endif + +endif # BOARD_VERDIN_IMX8MP_M7 diff --git a/boards/arm/verdin_imx8mp_m7/board.cmake b/boards/arm/verdin_imx8mp_m7/board.cmake new file mode 100644 index 000000000000000..546ba82f8a9c799 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/board.cmake @@ -0,0 +1,11 @@ +# +# Copyright (c) 2023, Toradex +# +# SPDX-License-Identifier: Apache-2.0 +# + +board_set_debugger_ifnset(jlink) +board_set_flasher_ifnset(jlink) + +board_runner_args(jlink "--device=MIMX8ML8_M7") +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/verdin_imx8mp_m7/doc/index.rst b/boards/arm/verdin_imx8mp_m7/doc/index.rst new file mode 100644 index 000000000000000..455acb8c290aaa8 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/doc/index.rst @@ -0,0 +1,304 @@ +.. _verdin_imx8mp_m7: + +Toradex Verdin iMX8M Plus SoM +############################# + +Overview +******** + +The Verdin iMX8M Plus is a Computer on Module (CoM) developed by Toradex. It is based on the NXP® +i.MX 8M Plus family of processors (or System on Chips - SoCs). + +The Verdin iMX8M Plus family consists of: + ++-------------------------------------------------+-----------------------+ +| CoM | SoC | ++=================================================+=======================+ +| Verdin iMX8M Plus Quad 8GB Wi-Fi / Bluetooth IT | i.MX 8M Plus Quad | ++-------------------------------------------------+-----------------------+ +| Verdin iMX8M Plus Quad 4GB Wi-Fi / Bluetooth IT | i.MX 8M Plus Quad | ++-------------------------------------------------+-----------------------+ +| Verdin iMX8M Plus Quad 4GB IT | i.MX 8M Plus Quad | ++-------------------------------------------------+-----------------------+ +| Verdin iMX8M Plus Quad 2GB Wi-Fi / Bluetooth IT | i.MX 8M Plus Quad | ++-------------------------------------------------+-----------------------+ +| Verdin iMX8M Plus QuadLite 1GB IT | i.MX 8M Plus QuadLite | ++-------------------------------------------------+-----------------------+ + +Quoting NXP: + + The i.MX 8M Plus family focuses on machine learning and vision, advanced multimedia, and + industrial automation with high reliability. It is built to meet the needs of Smart Home, + Building, City and Industry 4.0 applications. + +The Verdin iMX8M Plus integrates a total of 4 Arm Cortex™-A53 CPUs, operating at 1.6 GHz, alongside +a single Arm Cortex™-M7F microcontroller operating at 800 MHz. + +.. figure:: verdin_imx8mp_front.jpg + :align: center + :alt: Toradex Verdin iMX8M Plus + + Toradex Verdin iMX8M Plus (Credit: Toradex) + +Regarding the Cortex-A53 cluster, it employs the ARMv8-A architecture as a mid-range and +energy-efficient processor. With four cores in this cluster, each core is equipped with its own L1 +memory system. Moreover, the cluster incorporates a unified L2 cache that offers supplementary +functions. This cache is housed within a single APR region. Facilitating debugging processes, the +cores support both real-time trace through the ETM system and static debugging via JTAG. +Furthermore, the platform features support for real-time trace capabilities, achieved through ARM's +CoreSight ETM modules, and also enables cross-triggering by utilizing CTI and CTM modules. + +The Arm® Cortex®-M7 microcontroller is indicated for Real-time control, combining high-performance +with a minimal interrupt latency. It stands out for its compatibility with existing Cortex-M profile +processors. The microcontroller employs an efficient in-order super-scalar pipeline, allowing +dual-issued instructions such as load/load and load/store pairs, thanks to its multiple memory +interfaces. These interfaces encompass Tightly-Coupled Memory (TCM), Harvard caches, and an AXI +master interface. The Arm Cortex-M7 Platform boasts features like a 32 KB L1 Instruction Cache, 32 +KB L1 Data Cache, Floating Point Unit (FPU) with FPv5 architecture support, and an Internal Trace +(TRC) mechanism. Furthermore, the chip supports 160 IRQs, and integrates crucial Arm CoreSight +components including ETM and CTI, dedicated to facilitating debug and trace functions. + +Hardware +******** + +- SoC name: NXP® i.MX 8M Plus +- CPU Type: 4x Arm Cortex™-A53 (1.6 GHz) +- Microcontroller: 1x Arm Cortex™-M7F (800 MHz) + +- Memory: + + - RAM -> A53: 1GB, 2GB, 4GB or 8GB + - RAM -> M7: 3x32KB (TCML, TCMU, OCRAM_S), 1x128KB (OCRAM) and 1x256MB (DDR) + - Flash -> A53: Up to 32GB eMMC + +- Connectivity: + + - USB 3.1: 1x Host / 1x OTG (Gen 1) + - USB 2.0: 1x Host / 1x OTG + - Ethernet Gigabit with TSN (+2nd RGMII) + - Wi-Fi Dual-band 802.11ac 2x2 MU-MIMO + - Bluetooth 5 + - 5x I2C + - 3x SPI + - 1 QSPI + - 4x UART + - Up to 92 GPIO + - 4x Analog Input + - 2x CAN (FlexCAN) + +- Multimedia: + + - Neural Processing Unit (NPU) + - Image Signal Processor (ISP) + - 2D and 3D acceleration + - HDMI, MIPI-DSI and MIPI-CSI interface + +For more information about the Verdin iMX8M Plus and the i.MX 8M Plus SoC refer to these links: + +- `i.MX 8M Plus Applications Processor page`_ +- `Verdin iMX8M Plus homepage`_ +- `Verdin iMX8M Plus developer page`_ +- `Verdin Development Board developer page`_ +- `Verdin iMX8M Plus Datasheet`_ +- `Verdin Development Board Datasheet`_ + +Supported Features +================== + +The Zephyr verdin_imx8mp_m7 board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| SYSTICK | on-chip | systick | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | clock_control | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | GPIO output | +| | | GPIO input | ++-----------+------------+-------------------------------------+ + +The default configuration can be found in the defconfig file: + +- :zephyr_file:`boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm_defconfig`, if you choose to use + the ITCM memory. + +- :zephyr_file:`boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr_defconfig`, if you choose to use + the DDR memory. + +It is recommended to disable peripherals used by the M7 core on the Linux host. + +Other hardware features are not currently supported by the port. + +Connections and IOs +=================== + +UART +---- + +Zephyr is configured to use the UART4 by default, which is connected to the FTDI USB converter on +most Toradex carrier boards. + +This is also the UART connected to WiFi/BT chip in modules that have the WiFi/BT chip. Therefore, if +UART4 is used, WiFI/BT will not work properly. + +If the WiFi/BT is needed, then another UART should be used for Zephyr (UART1 for example). You can +change the UART by changing the ``zephyr,console`` and ``zephyr,shell-uart`` in the +:zephyr_file:`boards/arm/verdin_imx8mp_m7_itcm.dts` or +:zephyr_file:`boards/arm/verdin_imx8mp_m7_ddr.dts` file. + ++---------------+-----------------+---------------------------+ +| Board Name | SoC Name | Usage | ++===============+=================+===========================+ +| UART_1 | UART1 | General purpose UART | ++---------------+-----------------+---------------------------+ +| UART_4 | UART4 | Cortex-M4 debug UART | ++---------------+-----------------+---------------------------+ + +GPIO +---- + +All the GPIO banks available are enabled in the :zephyr_file:`dts/arm/nxp/nxp_imx8ml_m7.dtsi`. + +System Clock +============ + +The M7 Core is configured to run at a 800 MHz clock speed. + +Serial Port +=========== + +The i.MX8M Plus SoC has four UARTs. UART_4 is configured for the console and the remaining are not +used/tested. + +Programming and Debugging +************************* + +The Verdin iMX8M Plus board doesn't have QSPI flash for the M7, and it needs to be started by the +A53 core. The A53 core is responsible to load the M7 binary application into the RAM, put the M7 in +reset, set the M7 Program Counter and Stack Pointer, and get the M7 out of reset. The A53 can +perform these steps at bootloader level or after the Linux system has booted. + +The M7 can use up to 3 different RAMs (currently, only two configurations are supported: ITCM and +DDR). These are the memory mapping for A53 and M7: + ++------------+-------------------------+------------------------+-----------------------+----------------------+ +| Region | Cortex-A53 | Cortex-M7 (System Bus) | Cortex-M7 (Code Bus) | Size | ++============+=========================+========================+=======================+======================+ +| OCRAM | 0x00900000-0x0098FFFF | 0x20200000-0x2028FFFF | 0x00900000-0x0098FFFF | 576KB | ++------------+-------------------------+------------------------+-----------------------+----------------------+ +| DTCM | 0x00800000-0x0081FFFF | 0x20000000-0x2001FFFF | | 128KB | ++------------+-------------------------+------------------------+-----------------------+----------------------+ +| ITCM | 0x007E0000-0x007FFFFF | | 0x00000000-0x0001FFFF | 128KB | ++------------+-------------------------+------------------------+-----------------------+----------------------+ +| OCRAM_S | 0x00180000-0x00188FFF | 0x20180000-0x20188FFF | 0x00180000-0x00188FFF | 36KB | ++------------+-------------------------+------------------------+-----------------------+----------------------+ +| DDR | 0x80000000-0x803FFFFF | 0x80200000-0x803FFFFF | 0x80000000-0x801FFFFF | 2MB | ++------------+-------------------------+------------------------+-----------------------+----------------------+ + +For more information about memory mapping see the `i.MX 8M Plus Applications Processor Reference +Manual`_ (section 2.1 to 2.3) + +At compilation time you have to choose which RAM will be used. To facilitate this process, there are +two targets available: + +- ``verdin_imx8mp_m7_itcm``, which uses the ITCM configuration. +- ``verdin_imx8mp_m7_ddr``, which uses the DDR configuration. + + +Starting the Cortex-M7 via U-Boot +================================= + +Load and run Zephyr on M7 from A53 using u-boot by copying the compiled ``zephyr.bin`` to the first +FAT partition of the SD card and plug the SD card into the board. Power it up and stop the u-boot +execution at prompt. + +Load the M7 binary onto the desired memory and start its execution using: + +ITCM +==== + +Loading the binary from an EXT4 partition: + +.. code-block:: shell + + ext4load mmc 2:2 ${loadaddr} //zephyr.bin + cp.b ${loadaddr} 0x7e0000 + bootaux 0x7e0000 + +DDR +=== + +Loading the binary from an EXT4 partition: + +.. code-block:: shell + + ext4load mmc 2:2 ${loadaddr} //zephyr.bin + cp.b ${loadaddr} 0x80000000 + bootaux 0x80000000 + +Debugging +========= + +Toradex Verdin iMX8M Plus SoM can be debugged by connecting an external JLink JTAG debugger to the +X56 debug connector and to the PC, or simply connecting a USB-C to X66 on the Verdin Development +Board. Then, the application can be debugged using the usual way. + +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: verdin_imx8mp_m7_ddr + :goals: debug + +Open a serial terminal, step through the application in your debugger, and you +should see the following message in the terminal: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.4.0-2300-g03905f7e55d2 *** + Hello World! verdin_imx8mp_m7_ddr + +References +========== + +- `How to Load Compiled Binaries into Cortex-M`_ +- `Cortex-M JTAG Debugging`_ +- `NXP website`_ + +.. _NXP website: + https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/evaluation-kit-for-the-i-mx-8m-plus-applications-processor:8MPLUSLPD4-EVK + +.. _i.MX 8M Plus Applications Processor Reference Manual: + https://www.nxp.com/webapp/Download?colCode=IMX8MPRM + +.. _How to Load Compiled Binaries into Cortex-M: + https://developer.toradex.com/software/real-time/cortex-m/how-to-load-binaries + +.. _Cortex-M JTAG Debugging: + https://developer.toradex.com/software/real-time/cortex-m/cortexm-jtag-debugging/ + +.. _i.MX 8M Plus Applications Processor page: + https://www.nxp.com/products/processors-and-microcontrollers/arm-processors/i-mx-applications-processors/i-mx-8-applications-processors/i-mx-8m-plus-arm-cortex-a53-machine-learning-vision-multimedia-and-industrial-iot:IMX8MPLUS + +.. _Verdin iMX8M Plus homepage: + https://www.toradex.com/computer-on-modules/verdin-arm-family/nxp-imx-8m-plus + +.. _Verdin iMX8M Plus developer page: + https://developer.toradex.com/hardware/verdin-som-family/modules/verdin-imx8m-plus + +.. _Verdin Development Board developer page: + https://developer.toradex.com/hardware/verdin-som-family/carrier-boards/verdin-development-board/ + +.. _Verdin iMX8M Plus Datasheet: + https://docs.toradex.com/110977-verdin_imx8m_plus_v1.1_datasheet.pdf + +.. _Verdin Development Board Datasheet: + https://docs.toradex.com/109463-verdin_development_board_datasheet_v1.1.pdf diff --git a/boards/arm/verdin_imx8mp_m7/doc/verdin_imx8mp_front.jpg b/boards/arm/verdin_imx8mp_m7/doc/verdin_imx8mp_front.jpg new file mode 100644 index 000000000000000..e5089eace4b0e24 Binary files /dev/null and b/boards/arm/verdin_imx8mp_m7/doc/verdin_imx8mp_front.jpg differ diff --git a/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7-pinctrl.dtsi b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7-pinctrl.dtsi new file mode 100644 index 000000000000000..bb195dc66d0c5e6 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7-pinctrl.dtsi @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Toradex + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + uart1_default: uart1_default { + group0 { + drive-strength = "x1"; + pinmux = <&iomuxc_uart1_rxd_uart_rx_uart1_rx>, + <&iomuxc_uart1_txd_uart_tx_uart1_tx>; + slew-rate = "slow"; + }; + }; + + uart4_default: uart4_default { + group0 { + bias-pull-up; + drive-strength = "x1"; + pinmux = <&iomuxc_uart4_rxd_uart_rx_uart4_rx>, + <&iomuxc_uart4_txd_uart_tx_uart4_tx>; + slew-rate = "slow"; + }; + }; +}; diff --git a/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.dts b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.dts new file mode 100644 index 000000000000000..861077246fd04d1 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.dts @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Toradex + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "verdin_imx8mp_m7-pinctrl.dtsi" +#include + +/ { + model = "Toradex Verdin iMX8M Plus M7"; + compatible = "nxp,mimx8mp_evk"; + + chosen { + /* DDR */ + zephyr,flash = &ddr_code; + zephyr,sram = &ddr_sys; + + zephyr,console = &uart4; + zephyr,shell-uart = &uart4; + }; +}; + +&gpio3 { + status = "okay"; +}; + +&mailbox0 { + status = "okay"; +}; + +&uart1 { + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; + +&uart4 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart4_default>; + pinctrl-names = "default"; +}; diff --git a/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.yaml b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.yaml new file mode 100644 index 000000000000000..fc64d8c3db8859d --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr.yaml @@ -0,0 +1,18 @@ +# +# Copyright (c) 2023 Toradex +# +# SPDX-License-Identifier: Apache-2.0 +# + +identifier: verdin_imx8mp_m7_ddr +name: Toradex Verdin iMX8M Plus (DDR) +type: mcu +arch: arm +ram: 2048 +flash: 2048 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - uart diff --git a/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr_defconfig b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr_defconfig new file mode 100644 index 000000000000000..7c0d4073679355c --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_ddr_defconfig @@ -0,0 +1,16 @@ +# +# Copyright (c) 2023 Toradex +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SOC_SERIES_IMX8ML_M7=y +CONFIG_SOC_MIMX8ML8=y +CONFIG_BOARD_VERDIN_IMX8MP_M7=y +CONFIG_CLOCK_CONTROL=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_XIP=y +CONFIG_CODE_DDR=y +CONFIG_PINCTRL=y diff --git a/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm.dts b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm.dts new file mode 100644 index 000000000000000..5744928f8a7f9d6 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm.dts @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Toradex + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "verdin_imx8mp_m7-pinctrl.dtsi" +#include + +/ { + model = "Toradex Verdin iMX8M Plus M7"; + compatible = "nxp,mimx8mp_evk"; + + chosen { + /* TCM */ + zephyr,flash = &itcm; + zephyr,sram = &dtcm; + + zephyr,console = &uart4; + zephyr,shell-uart = &uart4; + }; +}; + +&gpio3 { + status = "okay"; +}; + +&mailbox0 { + status = "okay"; +}; + +&uart1 { + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; + +&uart4 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart4_default>; + pinctrl-names = "default"; +}; diff --git a/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm.yaml b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm.yaml new file mode 100644 index 000000000000000..8db4c170c5de939 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm.yaml @@ -0,0 +1,18 @@ +# +# Copyright (c) 2023 Toradex +# +# SPDX-License-Identifier: Apache-2.0 +# + +identifier: verdin_imx8mp_m7_itcm +name: Toradex Verdin iMX8M Plus (ITCM) +type: mcu +arch: arm +ram: 128 +flash: 128 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - uart diff --git a/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm_defconfig b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm_defconfig new file mode 100644 index 000000000000000..52c354abc1f95a9 --- /dev/null +++ b/boards/arm/verdin_imx8mp_m7/verdin_imx8mp_m7_itcm_defconfig @@ -0,0 +1,16 @@ +# +# Copyright (c) 2023 Toradex +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SOC_SERIES_IMX8ML_M7=y +CONFIG_SOC_MIMX8ML8=y +CONFIG_BOARD_VERDIN_IMX8MP_M7=y +CONFIG_CLOCK_CONTROL=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_XIP=y +CONFIG_CODE_ITCM=y +CONFIG_PINCTRL=y diff --git a/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi b/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi index 3f27e5c3a337589..d25bffa04c58d75 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 000000000000000..9c863d899dc2dc1 --- /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 000000000000000..5e569b40cc9e413 --- /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 000000000000000..e95d4d3767f655b --- /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 000000000000000..d592fd2c85f68b3 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 000000000000000..63d63370f765e75 --- /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 000000000000000..a99189804571e0c --- /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 000000000000000..761354420c6160a --- /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 000000000000000..c14cb0b7d649d7b --- /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 000000000000000..85246c0ef1ddf43 --- /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 000000000000000..ec36f85040cf66e --- /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/Kconfig.board b/boards/arm/weact_stm32g431_core/Kconfig.board new file mode 100644 index 000000000000000..9886fd64702779b --- /dev/null +++ b/boards/arm/weact_stm32g431_core/Kconfig.board @@ -0,0 +1,9 @@ +# +# Copyright (c) 2023 Andreas Sandberg +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BOARD_WEACT_STM32G431_CORE + bool "WeAct Studio STM32G431 Core Board" + depends on SOC_STM32G431XX diff --git a/boards/arm/weact_stm32g431_core/Kconfig.defconfig b/boards/arm/weact_stm32g431_core/Kconfig.defconfig new file mode 100644 index 000000000000000..25d65455013564e --- /dev/null +++ b/boards/arm/weact_stm32g431_core/Kconfig.defconfig @@ -0,0 +1,12 @@ +# +# Copyright (c) 2023 Andreas Sandberg +# +# SPDX-License-Identifier: Apache-2.0 +# + +if BOARD_WEACT_STM32G431_CORE + +config BOARD + default "weact_stm32g431_core" + +endif diff --git a/boards/arm/weact_stm32g431_core/board.cmake b/boards/arm/weact_stm32g431_core/board.cmake new file mode 100644 index 000000000000000..5ef1ab31d07a39e --- /dev/null +++ b/boards/arm/weact_stm32g431_core/board.cmake @@ -0,0 +1,11 @@ +# +# Copyright (c) 2023 Andreas Sandberg +# +# SPDX-License-Identifier: Apache-2.0 +# + +board_runner_args(dfu-util "--pid=0483:df11" "--alt=0" "--dfuse") + +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) diff --git a/boards/arm/weact_stm32g431_core/doc/index.rst b/boards/arm/weact_stm32g431_core/doc/index.rst new file mode 100644 index 000000000000000..2d367ba280827e8 --- /dev/null +++ b/boards/arm/weact_stm32g431_core/doc/index.rst @@ -0,0 +1,147 @@ +.. _weact_stm32g431_core: + +WeAct Studio STM32G431 Core Board +################################# + +The WeAct STM32G431 Core Board is a low-cost bare-bones STM32G431-based development +board. See the `STM32G431CB website`_ for more information about the MCU. More information +about the board, including schematics, is available from the `WeAct GitHub`_. + +Modifications USB-C Power Delivery +********************************** + +The board does not support USB-C PD in its standard configuration. To enable USB-C PD, CC1 +and CC2 need to be disconnected from their pull-down resistors and be connected to PB6 and +PB4 respectively. Dead battery support requires PA9 and PA10 to be routed to CC1 and +CC2. VBUS also needs to be connected to the MCU through a voltage divider. + +The pull-downs are disconnected by removing the zero-Ohm resistors on SB8 and SB9 next to +the USB-C connector. SB3, SB5, SB6, and SB7 then need to be closed to connect the CCx +lines to the MCU. The voltage divider is connected to PB2 by closing SB4. + +After these modifications have been made, PA9, PA10, PB2, PB4, and PB6 should be +considered reserved for USB-C and not available for other applications. + +.. warning:: + The internal USB DFU boot loader may not work correctly with machines that respect USB + PD signaling unless dead battery support has been enabled. A USB-C to USB-A adapter or + programming using the SWD port can be used as a workaround. + + +Supported Features +================== + +The Zephyr weact_stm32g431_core board configuration supports the following hardware +features: + ++------------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++============+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++------------+------------+-------------------------------------+ +| UART | on-chip | serial port | ++------------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++------------+------------+-------------------------------------+ +| ADC | on-chip | ADC Controller | ++------------+------------+-------------------------------------+ +| USB | on-chip | USB device | ++------------+------------+-------------------------------------+ +| UCPD | on-chip | ucpd | ++------------+------------+-------------------------------------+ + +The default configuration can be found in the defconfig file: + + ``boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig`` + +Pin Mapping +=========== + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- UART_2 TX/RX : PA2/PA3 +- UCPD1 CCx : PB6/PB4 (not connected by default) +- UCPD1 DBCCx : PA9/PA10 (not connected by default) +- BUTTON (User) : PC13 +- BUTTON (BOOT0) : PB8 +- LED0 : PC6 +- ADC (VBUS) : PB2 + +The ADC is disabled by default since the VBUS voltage divider is not connected in the +board's standard configuration. + + +Hardware Configuration +---------------------- ++---------------+---------+-----------------------------------------------+ +| Solder bridge | Default | Description | ++===============+=========+===============================================+ +| SB1/SB2 | Open | Route PC14/PC15 (LSE) to header | ++---------------+---------+-----------------------------------------------+ +| SB6/SB7 | Open | Connect PB4/PB6 (UCPD1_CCx) to USB-C CCx pins | ++---------------+---------+-----------------------------------------------+ +| SB3/SB5 | Open | Connect PA9/PA10 (UCPD1_DBCCx) to to PB6/PB4 | ++---------------+---------+-----------------------------------------------+ +| SB4 | Open | Connect PB2 to VBUS voltage divider | ++---------------+---------+-----------------------------------------------+ +| SB8/SB9 | Closed | Connect USB-CCx to pull-down resistors | ++---------------+---------+-----------------------------------------------+ +| SB10 | Open | VBUS protection diode bypass | ++---------------+---------+-----------------------------------------------+ + + +Clock Sources +------------- + +The board has two external oscillators. The frequency of the slow clock (LSE) is 32.768 +kHz. The frequency of the main clock (HSE) is 8 MHz. + +The default configuration sources the system clock from the PLL, which is derived from +HSE, and is set at 144 MHz. The 48 MHz clock used by the USB interface is derived from the +PLL instead of the internal 48 MHz oscillator. + +Programming and Debugging +************************* + +The MCU is normally programmed using the ROM bootloader or the exposed SWD port. + +Please note that some laptops may not detect the ROM bootloader correctly if the CCx +pull-downs have been disconnected by opening SB8 and SB9 unless dead battery support has +been enabled by closing SB3 and SB5. A USB-C to USB-A adapter can be used as a workaround +if this is a problem. + +Flashing an Application +======================= + +Connect a USB-C cable and the board should power ON. Force the board into DFU mode by +keeping the BOOT0 switch pressed while pressing and releasing the NRST switch. + +The dfu-util runner is supported on this board and so a sample can be built and tested +easily. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: weact_stm32g431_core + :goals: build flash + +Debugging +========= + +The board can be debugged by installing the included 100 mil (0.1 inch) header, and +attaching an SWD debugger to the 3V3 (3.3V), GND, SCK, and DIO pins on that header. + + +References +********** + +.. target-notes:: + +.. _WeAct GitHub: + https://github.com/WeActStudio/WeActStudio.STM32G431CoreBoard + +.. _STM32G431CB website: + https://www.st.com/en/microcontrollers-microprocessors/stm32g431cb.html + +.. _STM32F401x reference manual: + https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf diff --git a/boards/arm/weact_stm32g431_core/support/openocd.cfg b/boards/arm/weact_stm32g431_core/support/openocd.cfg new file mode 100644 index 000000000000000..d936f7d353423bc --- /dev/null +++ b/boards/arm/weact_stm32g431_core/support/openocd.cfg @@ -0,0 +1,7 @@ +source [find interface/stlink.cfg] + +transport select hla_swd + +source [find target/stm32g4x.cfg] + +reset_config srst_only diff --git a/boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts b/boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts new file mode 100644 index 000000000000000..ca6dfcf656935bc --- /dev/null +++ b/boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2023 Andreas Sandberg + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include +#include + +/ { + model = "WeAct Studio STM32G431 Core Board"; + compatible = "weact,stm32g431-core"; + + chosen { + zephyr,console = &usart2; + zephyr,shell-uart = &usart2; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + aliases { + led0 = &led_0; + mcuboot-button0 = &button_0; + mcuboot-led0 = &led_0; + sw0 = &button_0; + sw1 = &button_1; + usbc-port0 = &usbc1; + watchdog0 = &iwdg; + }; + + leds { + compatible = "gpio-leds"; + led_0: led0 { + gpios = <&gpioc 6 GPIO_ACTIVE_HIGH>; + label = "Status LED"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + button_0: button0 { + label = "User"; + gpios = <&gpioc 13 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; + zephyr,code = ; + }; + button_1: button1 { + label = "Boot0"; + gpios = <&gpiob 8 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + }; + + vbus1: vbus { + compatible = "zephyr,usb-c-vbus-adc"; + status = "disabled"; + io-channels = <&adc2 12>; + output-ohms = <10000>; + full-ohms = <(100000 + 10000)>; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + usbc1: usbc-port@1 { + compatible = "usb-c-connector"; + status = "disabled"; + reg = <1>; + tcpc = <&ucpd1>; + vbus = <&vbus1>; + data-role = "device"; + power-role = "sink"; + sink-pdos = ; + }; + }; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_lse { + status = "okay"; +}; + +&clk_hsi { + status = "disabled"; +}; + +&clk_hse { + status = "okay"; + clock-frequency = ; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&pll { + status = "okay"; + div-m = <2>; + mul-n = <72>; + div-p = <2>; + div-q = <6>; + div-r = <2>; + clocks = <&clk_hse>; +}; + +&rtc { + status = "okay"; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; +}; + +stm32_lp_tick_source: &lptim1 { + status = "okay"; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, + <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* 4KiB of storage at the end of the 128KiB FLASH */ + storage_partition: partition@1f000 { + label = "storage"; + reg = <0x0001f000 DT_SIZE_K(4)>; + }; + }; +}; + +&iwdg { + status = "okay"; +}; + +&usart2 { + status = "okay"; + pinctrl-0 = <&usart2_tx_pa2 &usart2_rx_pa3>; + pinctrl-names = "default"; + + current-speed = <115200>; +}; + +&adc2 { + pinctrl-0 = <&adc2_in12_pb2>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <4>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@c { + reg = <12>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,vref-mv = <3300>; + }; +}; + +&ucpd1 { + psc-ucpdclk = <1>; + hbitclkdiv = <27>; + pinctrl-0 = <&ucpd1_cc1_pb6 &ucpd1_cc2_pb4>; + pinctrl-names = "default"; +}; + +zephyr_udc0: &usb { + pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; + pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00800000>, + <&rcc STM32_SRC_PLL_Q CLK48_SEL(2)>; + status = "okay"; +}; diff --git a/boards/arm/weact_stm32g431_core/weact_stm32g431_core.yaml b/boards/arm/weact_stm32g431_core/weact_stm32g431_core.yaml new file mode 100644 index 000000000000000..91886ad0ea51ad3 --- /dev/null +++ b/boards/arm/weact_stm32g431_core/weact_stm32g431_core.yaml @@ -0,0 +1,20 @@ +identifier: weact_stm32g431_core +name: WeAct Studio STM32G431 Core Board +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 32 +flash: 128 +supported: + - counter + - gpio + - nvs + - pinctrl + - tcpc + - uart + - usb_device + - watchdog +vendor: weact diff --git a/boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig b/boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig new file mode 100644 index 000000000000000..0c9d0e2a1856838 --- /dev/null +++ b/boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig @@ -0,0 +1,21 @@ +# +# Copyright (c) 2023 Andreas Sandberg +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SOC_SERIES_STM32G4X=y +CONFIG_SOC_STM32G431XX=y + +CONFIG_CLOCK_CONTROL=y +CONFIG_PINCTRL=y + +CONFIG_ARM_MPU=y +CONFIG_HW_STACK_PROTECTION=y + +CONFIG_GPIO=y + +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/arm/wio_terminal/doc/index.rst b/boards/arm/wio_terminal/doc/index.rst index 56a13748ac605df..4b11a461323eabc 100644 --- a/boards/arm/wio_terminal/doc/index.rst +++ b/boards/arm/wio_terminal/doc/index.rst @@ -180,7 +180,8 @@ debugged using an SWD probe such as the Segger J-Link. .. zephyr-app-commands:: :zephyr-app: samples/basic/button :board: wio_terminal - :goals: flash -r openocd + :goals: flash + :flash-args: -r openocd :compact: #. Start debugging: diff --git a/boards/arm/wio_terminal/wio_terminal.dts b/boards/arm/wio_terminal/wio_terminal.dts index 2e2fe7500a0da67..99e07373526d47e 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>; diff --git a/boards/arm/xiao_ble/board.cmake b/boards/arm/xiao_ble/board.cmake index 67f5aee98e4a674..a6aa2ac40a72181 100644 --- a/boards/arm/xiao_ble/board.cmake +++ b/boards/arm/xiao_ble/board.cmake @@ -9,3 +9,4 @@ include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/uf2.board.cmake) +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) diff --git a/boards/arm/xiao_ble/doc/index.rst b/boards/arm/xiao_ble/doc/index.rst index 9966f9136442db6..d4d4266311baee7 100644 --- a/boards/arm/xiao_ble/doc/index.rst +++ b/boards/arm/xiao_ble/doc/index.rst @@ -112,8 +112,8 @@ necessary software. Flashing -------- -Follow the instructions in the :ref:`jlink-external-debug-probe` page to install -and configure all the necessary software. Then build and flash applications as +Setup and connect a supported debug probe (JLink, instructions at :ref:`jlink-external-debug-probe` or +BlackMagic Probe). Then build and flash applications as usual (see :ref:`build_an_application` and :ref:`application_run` for more details). @@ -156,6 +156,8 @@ Debugging Refer to the :ref:`jlink-external-debug-probe` page to learn about debugging boards with a Segger IC. +Debugging using a BlackMagic Probe is also supported. + Testing the LEDs in the XIAO BLE (Sense) **************************************** diff --git a/boards/arm/xmc45_relax_kit/Kconfig.defconfig b/boards/arm/xmc45_relax_kit/Kconfig.defconfig index e6f0add4859f245..0296bc64ff79c5c 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 17669cedcbe1fc3..6d75146046ea5e9 100644 --- a/boards/arm/xmc45_relax_kit/doc/index.rst +++ b/boards/arm/xmc45_relax_kit/doc/index.rst @@ -55,6 +55,14 @@ The Relax Kit development board configuration supports the following hardware fe +-----------+------------+-----------------------+ | PWM | on-chip | pwm | +-----------+------------+-----------------------+ +| 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 04156e2890ceb6b..936733ea02a83a8 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 ec05ae1aa789d33..6b1519a455383d6 100644 --- a/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts +++ b/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts @@ -22,6 +22,7 @@ led0 = &led1; die-temp0 = &die_temp; pwm-led0 = &pwm_led1; + watchdog0 = &wdt0; }; leds { @@ -132,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 520632af5c675f3..031d9dc5a6c22fe 100644 --- a/boards/arm/xmc45_relax_kit/xmc45_relax_kit.yaml +++ b/boards/arm/xmc45_relax_kit/xmc45_relax_kit.yaml @@ -12,6 +12,8 @@ supported: - gpio - 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 da18e0230b1d746..98978ffd5409df4 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 fea191f4c30b73f..8fb2ce9997ad5e7 100644 --- a/boards/arm/xmc47_relax_kit/doc/index.rst +++ b/boards/arm/xmc47_relax_kit/doc/index.rst @@ -58,6 +58,14 @@ The Relax Kit development board configuration supports the following hardware fe +-----------+------------+-----------------------+ | PWM | on-chip | pwm | +-----------+------------+-----------------------+ +| 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 83d92d7ee51068c..e6688a7ebb24772 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 71f6ce2d536f96a..19cad242f1f450d 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts @@ -21,6 +21,7 @@ led0 = &led1; die-temp0 = &die_temp; pwm-led0 = &pwm_led1; + watchdog0 = &wdt0; }; leds { @@ -47,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 { @@ -174,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 61ab8ca25c403be..72fa356ef0cb0e2 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml @@ -14,6 +14,8 @@ supported: - uart - 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 8059b39fe902163..c8271b2ff0eb796 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 68ef6a664e89fb4..b6e39f0dab35502 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 1e0dfa4a9b2ff0c..ed63f35d1012fa7 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 4bc1e1ce9f23723..701401f569b35e8 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/mimx8mn_evk/doc/index.rst b/boards/arm64/mimx8mn_evk/doc/index.rst index 546df0d5c2d4502..b9620176b6eb1d2 100644 --- a/boards/arm64/mimx8mn_evk/doc/index.rst +++ b/boards/arm64/mimx8mn_evk/doc/index.rst @@ -7,7 +7,7 @@ Overview ******** i.MX8M Nano LPDDR4 EVK board is based on NXP i.MX8M Nano applications -processor, composed of a quad Cortex®-A53 cluster and a single Cortex®-M47 core. +processor, composed of a quad Cortex®-A53 cluster and a single Cortex®-M7 core. Zephyr OS is ported to run on the Cortex®-A53 core. - Board features: diff --git a/boards/arm64/mimx93_evk/doc/index.rst b/boards/arm64/mimx93_evk/doc/index.rst index 7ff38891d2235bf..67997a3fbbea723 100644 --- a/boards/arm64/mimx93_evk/doc/index.rst +++ b/boards/arm64/mimx93_evk/doc/index.rst @@ -168,7 +168,7 @@ Firstly, we need to explain a few Jailhouse concepts that will be referred to la cell can utilize. * **Root cell**: refers to the cell in which Linux is running. This is the main cell which - will contain all the hardware resources that Linux will utilize and will be used used to assign + will contain all the hardware resources that Linux will utilize and will be used to assign resources to the inmates. The inmates CANNOT use resources such as the CPU that haven't been assigned to the root cell. diff --git a/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi b/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi index 50186a49b0ad08c..31e35907f86d6ad 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi +++ b/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi @@ -7,13 +7,80 @@ #include &pinctrl { + uart1_default: uart1_default { + group0 { + pinmux = <&iomuxc1_uart1_rxd_lpuart_rx_lpuart1_rx>, + <&iomuxc1_uart1_txd_lpuart_tx_lpuart1_tx>; + bias-pull-up; + slew-rate = "slightly_fast"; + drive-strength = "x5"; + }; + }; + uart2_default: uart2_default { group0 { - pinmux = <&iomuxc_uart2_rxd_uart_rx_uart2_rx>, - <&iomuxc_uart2_txd_uart_tx_uart2_tx>; + pinmux = <&iomuxc1_uart2_rxd_lpuart_rx_lpuart2_rx>, + <&iomuxc1_uart2_txd_lpuart_tx_lpuart2_tx>; bias-pull-up; slew-rate = "slightly_fast"; 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 4ace06656712fbf..421ad5e3c71ca27 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55.dts +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55.dts @@ -28,6 +28,49 @@ 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 { + status = "disabled"; + current-speed = <115200>; + /* clocks = <&ccm IMX_CCM_UART4_CLK 0x6c 24>; */ + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; }; &lpuart2 { @@ -37,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 72e4c677fc0c729..d4fc0bc7ae61bc0 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 2bcf6198a10e1b8..fb60fdfd9bb7f6e 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig @@ -7,6 +7,9 @@ CONFIG_AARCH64_IMAGE_HEADER=y CONFIG_ARMV8_A_NS=y +# MMU Options +CONFIG_MAX_XLAT_TABLES=64 + # Cache Options CONFIG_CACHE_MANAGEMENT=y CONFIG_DCACHE_LINE_SIZE_DETECT=y @@ -19,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/roc_rk3568_pc/CMakeLists.txt b/boards/arm64/roc_rk3568_pc/CMakeLists.txt new file mode 100644 index 000000000000000..9881313609aae2c --- /dev/null +++ b/boards/arm64/roc_rk3568_pc/CMakeLists.txt @@ -0,0 +1 @@ +# SPDX-License-Identifier: Apache-2.0 diff --git a/boards/arm64/roc_rk3568_pc/Kconfig.board b/boards/arm64/roc_rk3568_pc/Kconfig.board new file mode 100644 index 000000000000000..97844de31fd4475 --- /dev/null +++ b/boards/arm64/roc_rk3568_pc/Kconfig.board @@ -0,0 +1,8 @@ +# Copyright 2022 HNU-ESNL +# Copyright 2022 openEuler SIG-Zephyr +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ROC_RK3568_PC + bool "Rockchip ROC-RK3568-PC" + depends on SOC_SERIES_RK3568 + select ARM64 diff --git a/boards/arm64/roc_rk3568_pc/Kconfig.defconfig b/boards/arm64/roc_rk3568_pc/Kconfig.defconfig new file mode 100644 index 000000000000000..9ad4f73bd2b02c8 --- /dev/null +++ b/boards/arm64/roc_rk3568_pc/Kconfig.defconfig @@ -0,0 +1,10 @@ +# Copyright 2022 HNU-ESNL +# Copyright 2022 openEuler SIG-Zephyr +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_ROC_RK3568_PC + +config BOARD + default "roc_rk3568_pc" + +endif # BOARD_ROC_RK3568_PC diff --git a/boards/arm64/roc_rk3568_pc/board.cmake b/boards/arm64/roc_rk3568_pc/board.cmake new file mode 100644 index 000000000000000..9881313609aae2c --- /dev/null +++ b/boards/arm64/roc_rk3568_pc/board.cmake @@ -0,0 +1 @@ +# SPDX-License-Identifier: Apache-2.0 diff --git a/boards/arm64/roc_rk3568_pc/doc/index.rst b/boards/arm64/roc_rk3568_pc/doc/index.rst new file mode 100644 index 000000000000000..ae999409545d760 --- /dev/null +++ b/boards/arm64/roc_rk3568_pc/doc/index.rst @@ -0,0 +1,142 @@ +.. _roc_rk3568_pc: + +Firefly ROC-RK3568-PC (Quad-core Cortex-A55) +############################################ + +Overview +******** + +The ROC-RK3568-PC is a Quad-Core 64-Bit Mini Computer, which supports 4G large RAM. M.2 +and SATA3.0 interfaces enables expansion with large hard drives. +Providing dual Gigabit Ethernet ports, it supports WiFi 6 wireless transmission. +Control Port can be connected with RS485/RS232 devices. + +RK3568 quad-core 64-bit Cortex-A55 processor, with brand new ARM v8.2-A architecture, +has frequency up to 2.0GHz. Zephyr OS is ported to run on it. + + +- Board features: + + - RAM: 4GB LPDDR4 + - Storage: + + - 32GB eMMC + - M.2 PCIe 3.0 x 1 (Expand with 2242 / 2280 NVMe SSD) + - TF-Card Slot + - Wireless: + + - Supports WiFi 6 (802.11 AX) + - Supports BT5.0 + - USB: + + - One USB 3.0 + - Two USB 2.0 + - One Type-C + - Ethernet + - M.2 PCIe3.0 (Expand with NVMe SSD) + - LEDs: + + - 1x Power status LED + - Debug + + - UART debug ports for board + + +Supported Features +================== + +The Zephyr roc_rk3568_pc board configuration supports the following hardware +features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| GIC-v3 | on-chip | interrupt controller | ++-----------+------------+-------------------------------------+ +| ARM TIMER | on-chip | system clock | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port | ++-----------+------------+-------------------------------------+ + +Devices +======== +System Clock +------------ + +This board configuration uses a system clock frequency of 24 MHz. +Cortex-A55 Core runs up to 2.0 GHz. + +Serial Port +----------- + +This board configuration uses a single serial communication channel with the +CPU's UART2. + +Programming and Debugging +************************* + +Use U-Boot to load the zephyr.bin to the memory and kick it: + +.. code-block:: console + + tftp 0x40000000 zephyr.bin; dcache flush; icache flush; dcache off; icache off; go 0x40000000 + +Use this configuration to run basic Zephyr applications and kernel tests, +for example, with the :zephyr:code-sample:`synchronization` sample: + +.. zephyr-app-commands:: + :zephyr-app: samples/synchronization + :host-os: unix + :board: roc_rk3568_pc + :goals: run + +This will build an image with the synchronization sample app, boot it and +display the following ram console output: + +.. code-block:: console + + *** Booting Zephyr OS build bc695c6df5eb *** + thread_a: Hello World from cpu 0 on roc_rk3568_pc! + thread_b: Hello World from cpu 0 on roc_rk3568_pc! + thread_a: Hello World from cpu 0 on roc_rk3568_pc! + thread_b: Hello World from cpu 0 on roc_rk3568_pc! + + +roc_rk3568_pc_smp support, use this configuration to run Zephyr smp applications and subsys tests, +for example, with the :zephyr:code-sample:`synchronization` sample: + +.. zephyr-app-commands:: + :zephyr-app: samples/synchronization + :host-os: unix + :board: roc_rk3568_pc_smp + :goals: run + +This will build an image with the shell_module sample app, boot it and +display the following ram console output: + +.. code-block:: console + + *** Booting Zephyr OS build bc695c6df5eb *** + I/TC: Secondary CPU 1 initializing + I/TC: Secondary CPU 1 switching to normal world boot + I/TC: Secondary CPU 2 initializing + I/TC: Secondary CPU 2 switching to normal world boot + I/TC: Secondary CPU 3 initializing + I/TC: Secondary CPU 3 switching to normal world boot + Secondary CPU core 1 (MPID:0x100) is up + Secondary CPU core 2 (MPID:0x200) is up + Secondary CPU core 3 (MPID:0x300) is up + + thread_a: Hello World from cpu 0 on roc_rk3568_pc! + thread_b: Hello World from cpu 1 on roc_rk3568_pc! + thread_a: Hello World from cpu 0 on roc_rk3568_pc! + thread_b: Hello World from cpu 1 on roc_rk3568_pc! + +References +========== + +More information can refer to Firefly official website: +`Firefly website`_. + +.. _Firefly website: + https://en.t-firefly.com/product/industry/rocrk3568pc.html?theme=pc diff --git a/boards/arm64/roc_rk3568_pc/roc_rk3568_pc.dts b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc.dts new file mode 100644 index 000000000000000..0e2d01372294e53 --- /dev/null +++ b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc.dts @@ -0,0 +1,33 @@ +/* + * Copyright 2022 HNU-ESNL + * Copyright 2022 openEuler SIG-Zephyr + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include + +/ { + model = "Firefly ROC-RK3568-PC"; + compatible = "rockchip,rk3568"; + + chosen { + zephyr,console = &uart2; + zephyr,shell-uart = &uart2; + zephyr,sram = &sram0; + }; + + sram0: memory@40000000 { + device_type = "memory"; + compatible = "mmio-sram"; + reg = <0x40000000 DT_SIZE_M(1)>; + }; + +}; + +&uart2 { + status = "okay"; + current-speed = <1500000>; +}; diff --git a/boards/arm64/roc_rk3568_pc/roc_rk3568_pc.yaml b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc.yaml new file mode 100644 index 000000000000000..82f35f567d5dfe8 --- /dev/null +++ b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc.yaml @@ -0,0 +1,12 @@ +identifier: roc_rk3568_pc +name: Rockchip ROC RK3568 PC +type: mcu +arch: arm64 +toolchain: + - zephyr + - cross-compile +ram: 1024 +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_defconfig b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_defconfig new file mode 100644 index 000000000000000..d85c08d24e7119b --- /dev/null +++ b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_defconfig @@ -0,0 +1,26 @@ +# Copyright 2021 HNU-ESNL +# Copyright 2022 openEuler SIG-Zephyr +# SPDX-License-Identifier: Apache-2.0 + +# Platform Configuration +CONFIG_SOC_SERIES_RK3568=y +CONFIG_SOC_RK3568=y +CONFIG_BOARD_ROC_RK3568_PC=y +CONFIG_ARM_ARCH_TIMER=y + +# Serial Drivers +CONFIG_SERIAL=y +CONFIG_UART_NS16550=y +CONFIG_UART_INTERRUPT_DRIVEN=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# ARMv8 NS world with cache management +CONFIG_ARMV8_A_NS=y +CONFIG_CACHE_MANAGEMENT=y + +# Clock support +CONFIG_CLOCK_CONTROL=y +CONFIG_TICKLESS_KERNEL=y diff --git a/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_smp.dts b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_smp.dts new file mode 100644 index 000000000000000..41d10fb440279cd --- /dev/null +++ b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_smp.dts @@ -0,0 +1,8 @@ +/* + * Copyright 2022 HNU-ESNL + * Copyright 2022 openEuler SIG-Zephyr + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "roc_rk3568_pc.dts" diff --git a/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_smp.yaml b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_smp.yaml new file mode 100644 index 000000000000000..07120b871fa5812 --- /dev/null +++ b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_smp.yaml @@ -0,0 +1,14 @@ +identifier: roc_rk3568_pc_smp +name: Rockchip ROC RK3568 PC SMP +type: mcu +arch: arm64 +toolchain: + - zephyr + - cross-compile +ram: 1024 +supported: + - smp +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_smp_defconfig b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_smp_defconfig new file mode 100644 index 000000000000000..3ffc3f25b416e87 --- /dev/null +++ b/boards/arm64/roc_rk3568_pc/roc_rk3568_pc_smp_defconfig @@ -0,0 +1,36 @@ +# Copyright 2022 HNU-ESNL +# Copyright 2022 openEuler SIG-Zephyr +# SPDX-License-Identifier: Apache-2.0 + +# Platform Configuration +CONFIG_SOC_SERIES_RK3568=y +CONFIG_SOC_RK3568=y +CONFIG_BOARD_ROC_RK3568_PC=y +CONFIG_ARM_ARCH_TIMER=y + +# Serial Drivers +CONFIG_SERIAL=y +CONFIG_UART_NS16550=y +CONFIG_UART_INTERRUPT_DRIVEN=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# SMP support +CONFIG_SMP=y +CONFIG_MP_MAX_NUM_CPUS=4 +CONFIG_MAX_THREAD_BYTES=4 + +# ARMv8 NS world with cache management +CONFIG_ARMV8_A_NS=y +CONFIG_CACHE_MANAGEMENT=y +CONFIG_DCACHE=y + +# PSCI support +CONFIG_PM_CPU_OPS=y +CONFIG_PM_CPU_OPS_PSCI=y + +# Clock support +CONFIG_CLOCK_CONTROL=y +CONFIG_TICKLESS_KERNEL=y diff --git a/boards/arm64/rpi_4b/doc/index.rst b/boards/arm64/rpi_4b/doc/index.rst index cdc9d9cc1482dc7..a3222f368b75d52 100644 --- a/boards/arm64/rpi_4b/doc/index.rst +++ b/boards/arm64/rpi_4b/doc/index.rst @@ -16,31 +16,56 @@ Supported Features The Raspberry Pi 4 Model B board configuration supports the following hardware features: -+-----------+------------+--------------------------------------+ -| Interface | Controller | Driver/Component | -+===========+============+======================================+ -| GIC-400 | on-chip | GICv2 interrupt controller | -+-----------+------------+--------------------------------------+ -| UART | on-chip | Mini uart serial port | -+-----------+------------+--------------------------------------+ +.. list-table:: + :header-rows: 1 + + * - Peripheral + - Kconfig option + - Devicetree compatible + * - GIC-400 + - N/A + - :dtcompatible:`arm,gic-v2` + * - GPIO + - :kconfig:option:`CONFIG_GPIO` + - :dtcompatible:`brcm,bcm2711-gpio` + * - UART (Mini UART) + - :kconfig:option:`CONFIG_SERIAL` + - :dtcompatible:`brcm,bcm2711-aux-uart` Other hardware features have not been enabled yet for this board. The default configuration can be found in the defconfig file: - ``boards/arm/rpi_4b/rpi_4b_defconfig`` + ``boards/arm64/rpi_4b/rpi_4b_defconfig`` Programming and Debugging ************************* -Flashing -======== +TF Card +======= + +Prepare a TF card with MBR and FAT32. In the root directory of the TF card: + +1. Download and place these firmware files: + + * `bcm2711-rpi-4-b.dtb `_ + * `bootcode.bin `_ + * `start4.elf `_ + +2. Copy ``build/zephyr/zephyr.bin`` +3. Create a ``config.txt``: + + .. code-block:: text -1. Install Raspberry Pi OS using Raspberry Pi Imager. see . + kernel=zephyr.bin + arm_64bit=1 + enable_uart=1 + uart_2ndstage=1 -2. add `kernel=zephyr.bin` in `config.txt`. see +Insert the card and power on the board. You should see the following output on +the serial console (GPIO 14/15): -.. code-block:: console +.. code-block:: text - *** Booting Zephyr OS build XXXXXXXXXXXX *** - Hello World! Raspberry Pi 4 Model B! + *** Booting Zephyr OS build XXXXXXXXXXXX *** + Hello World! Raspberry Pi 4 Model B! diff --git a/boards/arm64/rpi_4b/rpi_4b.dts b/boards/arm64/rpi_4b/rpi_4b.dts index 371ca3c09e8a539..e7e1faad4357bf6 100644 --- a/boards/arm64/rpi_4b/rpi_4b.dts +++ b/boards/arm64/rpi_4b/rpi_4b.dts @@ -7,17 +7,36 @@ /dts-v1/; #include +#include + / { model = "Raspberry Pi 4 Model B"; compatible = "raspberrypi,4-model-b", "brcm,bcm2838"; #address-cells = <1>; #size-cells = <1>; + aliases { + led0 = &led_act; + }; + chosen { zephyr,console = &uart1; zephyr,shell-uart = &uart1; zephyr,sram = &sram0; }; + + leds { + compatible = "gpio-leds"; + + led_act: led-act { + gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; /* GPIO 42 */ + label = "ACT"; + }; + }; +}; + +&gpio1 { + status = "okay"; }; &uart1 { diff --git a/boards/arm64/xenvm/xenvm_defconfig b/boards/arm64/xenvm/xenvm_defconfig index ff8597199e7ad1c..39e8a20767cb270 100644 --- a/boards/arm64/xenvm/xenvm_defconfig +++ b/boards/arm64/xenvm/xenvm_defconfig @@ -16,3 +16,5 @@ CONFIG_LOG=y CONFIG_LOG_MODE_MINIMAL=n CONFIG_USERSPACE=n + +CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME=y diff --git a/boards/arm64/xenvm/xenvm_gicv3_defconfig b/boards/arm64/xenvm/xenvm_gicv3_defconfig index 59a0c306cb7acc6..7b6b9afa888e1a5 100644 --- a/boards/arm64/xenvm/xenvm_gicv3_defconfig +++ b/boards/arm64/xenvm/xenvm_gicv3_defconfig @@ -15,3 +15,5 @@ CONFIG_LOG=y CONFIG_LOG_MODE_MINIMAL=n CONFIG_USERSPACE=n + +CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME=y diff --git a/boards/common/intel_adsp.board.cmake b/boards/common/intel_adsp.board.cmake deleted file mode 100644 index 813ece3fb995dc4..000000000000000 --- 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 743eef573994ba5..74de78449c6d6c7 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/common/nxp_s32dbg.board.cmake b/boards/common/nxp_s32dbg.board.cmake new file mode 100644 index 000000000000000..edd49ea305fd4cb --- /dev/null +++ b/boards/common/nxp_s32dbg.board.cmake @@ -0,0 +1,6 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +board_set_flasher_ifnset(nxp_s32dbg) +board_set_debugger_ifnset(nxp_s32dbg) +board_finalize_runner_args(nxp_s32dbg) diff --git a/boards/common/stub.dts b/boards/common/stub.dts new file mode 100644 index 000000000000000..ebb8b852a92ad57 --- /dev/null +++ b/boards/common/stub.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/* empty stub file provided for systems not using devicetree */ + +/dts-v1/; + +#include + +/ { + +}; diff --git a/boards/deprecated.cmake b/boards/deprecated.cmake index f238347203a8cd0..270d5f5e1a92739 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 3749da567ea10e1..083fb0e93b11bf9 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 80eab182050dac5..91a9444d00b24ec 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 c3a91d2ec9cfd23..db4daf5256ac5fb 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 000000000000000..c34480514523f50 --- /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 000000000000000..e1e1f8d725e8f35 --- /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 000000000000000..b2e57dc674edd54 --- /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 576e4b9b6376e09..54e800cd327362d 100644 --- a/boards/posix/common/natsim_config.cmake +++ b/boards/posix/common/natsim_config.cmake @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -set(zephyr_build_path ${CMAKE_BINARY_DIR}/zephyr) +set(zephyr_build_path ${APPLICATION_BINARY_DIR}/zephyr) get_property(CCACHE GLOBAL PROPERTY RULE_LAUNCH_COMPILE) target_link_options(native_simulator INTERFACE @@ -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 a790845afd856a6..0e20283324cfb1b 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 cac21706293c9d4..fcc6734d2a60843 100644 --- a/boards/posix/doc/arch_soc.rst +++ b/boards/posix/doc/arch_soc.rst @@ -65,9 +65,9 @@ This port is designed and tested to run in Linux. The 32 bit version of this port does not directly work in Windows Subsystem for Linux (WSL) because WSL does not support native 32-bit binaries. - You may want to consider WSL2, or, if using native_posix, - you can also just use the native_posix_64 - target: Check :ref:`32 and 64bit versions`. + You may want to consider WSL2, or, if using :ref:`native_sim `, + you can also just use the ``native_sim_64`` + target: Check :ref:`32 and 64bit versions`. Otherwise `with some tinkering `_ it should be possible to make it work. @@ -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 ========== @@ -323,7 +343,7 @@ SOC and board layers This description applies to all current POSIX arch based boards on tree, but it is not a requirement for another board to follow what is described here. -When the executable process is started (that is the the board +When the executable process is started (that is the board :c:func:`main`, which is the linux executable C :c:func:`main`), first, early initialization steps are taken care of (command line argument parsing, initialization of the HW models, etc). @@ -391,7 +411,7 @@ Busy waits ========== Busy waits work thanks to provided board functionality. -This does not need to be the same for all boards, but both native_posix and the +This does not need to be the same for all boards, but both native_sim and the nrf52_bsim board work similarly thru the combination of a board specific `arch_busy_wait()` and a special fake HW timer (provided by the board). diff --git a/boards/posix/doc/bsim_boards_design.rst b/boards/posix/doc/bsim_boards_design.rst index f69a27a57619aec..6165f76a438dcb5 100644 --- a/boards/posix/doc/bsim_boards_design.rst +++ b/boards/posix/doc/bsim_boards_design.rst @@ -3,21 +3,27 @@ Bsim boards ########### -This page covers the design, architecture and rationale, of the -:ref:`nrf52_bsim`, :ref:`nrf5340bsim` and other similar bsim boards. -Particular details on the nRF52 and nRF5340 simulation boards, including how to use them, -can be found in their respective documentation. -These boards are postfixed with `_bsim` as they use BabbleSim_ -(shortened bsim). +**Available bsim boards** -These boards use the `native simulator`_ and the :ref:`POSIX architecture` to build -and execute the embedded code natively on Linux. +* :ref:`Simulated nRF52833 (nrf52_bsim)` +* :ref:`Simulated nRF5340 (nrf5340bsim)` -.. contents:: +.. contents:: Table of contents :depth: 2 :backlinks: entry :local: +This page covers the design, architecture and rationale, of the +nrf5x_bsim boards and other similar bsim boards. +These boards are postfixed with `_bsim` as they use BabbleSim_ +(shortened bsim), to simulate the radio environment. +These boards use the `native simulator`_ and the :ref:`POSIX architecture` to build +and execute the embedded code natively on Linux. + +Particular details on the :ref:`nRF52` and :ref:`nRF5340` +simulation boards, including how to use them, +can be found in their respective documentation. + .. _BabbleSim: https://BabbleSim.github.io @@ -52,9 +58,12 @@ These tests are run in workstation, that is, without using real embedded HW. The intention being to be able to run tests much faster than real time, without the need for real HW, and in a deterministic/reproducible fashion. -Unlike native_posix, bsim boards do not interact directly with any host +Unlike :ref:`native_sim `, bsim boards do not interact directly with any host peripherals, and their execution is independent of the host load, or timing. +These boards are also designed to be used as prototyping and development environments, +which can help developing applications or communication stacks. + .. _bsim_boards_tests: Different types of tests and how the bsim boards relate to them @@ -95,13 +104,13 @@ to these boards. an special driver that handles the EDTT communication (its RPC transport) and an embedded application that handles the RPC calls themselves, while the python test scripts provide the test logic. - - Using Zephyr's native_posix board: It also allows integration testing of + - Using Zephyr's :ref:`native_sim ` board: It also allows integration testing of the embedded code, but without any specific HW. In that way, many embedded components which are dependent on the HW would not be suited for testing in that platform. Just like the bsim boards, this Zephyr target board can be used with or without Zephyr's ztest system and twister. - The native_posix board shares the :ref:`POSIX architecture` - with the bsim boards. + The :ref:`native_sim ` board shares the :ref:`POSIX architecture`, + and native simulator runner with the bsim boards. - Zephyr's ztest infrastructure and Zephyr's twister: Based on dedicated embedded test applications build with the code under test. @@ -120,35 +129,37 @@ Layering: Zephyr's arch, soc and board layers The basic architecture layering of these boards is as follows: +- The `native simulator`_ runner is used to execute the code in your host. - The architecture, SOC and board components of Zephyr are replaced with simulation specific ones. - The architecture (arch) is the Zephyr :ref:`POSIX architecture` layer. - The SOC layer is the soc_inf layer. And the board layer is dependent on + The SOC layer is `inf_clock`. And the board layer is dependent on the specific device we are simulating. - The POSIX architecture provides an adaptation from the Zephyr arch API - (which handles mostly the thread context switching) to the Linux kernel. + (which handles mostly the thread context switching) to the native simulator + CPU thread emulation. See :ref:`POSIX arch architecture` -- The soc_inf layer provides the overall CPU "simulation" and the handling of - control between the "CPU simulation" (Zephyr threads) and the HW models thread - ( See `Threading`_ ) +- The SOC `inf_clock` layer provides an adaptation to the native simulator CPU "simulation" + and the handling of control between the "CPU simulation" (Zephyr threads) and the + HW models thread ( See `Threading`_ ). - The board layer provides all SOC/ IC specific content, including - (or linking to) HW models, IRQ handling, busy wait API - (see :ref:`posix_busy_wait`), and Zephyr's printk backend. + selecting the HW models which are built in the native simulator runner context, IRQ handling, + busy wait API (see :ref:`posix_busy_wait`), and Zephyr's printk backend. Note that in a normal Zephyr target interrupt handling and a custom busy wait would be provided by the SOC layer, but abusing Zephyr's layering, and for the - soc_inf layer to be generic, these were delegated to the board. + `inf_clock` layer to be generic, these were delegated to the board. The board layer provides other test specific functionality like bs_tests hooks, trace control, etc, and - by means of the native simulator, provides the :c:func:`main` entry point for the linux + by means of the native simulator, provides the :c:func:`main` entry point for the Linux program, command line argument handling, and the overall time scheduling of the simulated device. - Note that the POSIX arch and soc_inf expect a set of APIs being provided by + Note that the POSIX arch and `inf_clock` soc expect a set of APIs being provided by the board. This includes the busy wait API, a basic tracing API, the interrupt controller and interrupt handling APIs, :c:func:`posix_exit`, - and :c:func:`posix_get_hw_cycle` (see posix_board_if.h and posix_soc_if.h ). + and :c:func:`posix_get_hw_cycle` (see :file:`posix_board_if.h` and :file:`posix_soc_if.h`). -.. figure:: layering.svg +.. figure:: layering_natsim.svg :align: center :alt: Zephyr layering in native & bsim builds :figclass: align-center @@ -156,12 +167,15 @@ 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 soc_inf design. +are inherited from the POSIX arch and `inf_clock` design. + +Similarly, they inherit the POSIX architecture +:ref:`unsupported features set `. .. _Threading: @@ -228,7 +242,7 @@ can use to exchange data. About using Zephyr APIs ======================= -Note that even though bsim board code is linked with the Zephyr kernel, +Note that even though part of the bsim board code is linked with the Zephyr kernel, one should in general not call Zephyr APIs from the board code itself. In particular, one should not call Zephyr APIs from the original/HW models thread as the Zephyr code would be called from the wrong context, @@ -242,13 +256,14 @@ which relies on the bs_trace API. Instead, for tracing the bs_trace API should be used directly. The same applies to other Zephyr APIs, including the entropy API, etc. -posix_print backend -=================== +posix_print and nsi_print backends +================================== -The bsim board provides a backend for the posix_print API which is expected by the posix ARCH -and soc inf (POSIX) code. -It simply routes the printk strings to the bs_trace bsim API. -Any message printed to the posix_print API, which is also the default printk backend, +The bsim board provides a backend for the ``posix_print`` API which is expected by the posix +ARCH and `inf_clock` code, and for the ``nsi_print`` API expected by the native simulator. + +These simply route this API calls into the ``bs_trace`` bsim API. +Any message printed to these APIs, and by extension by default to Zephyr's ``printk``, will be printed to the console (stdout) together with all other device messages. .. _bsim_boards_bs_tests: @@ -271,12 +286,12 @@ callbacks are assigned to the respective hooks. There is a set of one time hooks at different levels of initialization of the HW and Zephyr OS, a hook to process possible command line arguments, and, a hook that can be used to sniff or capture interrupts. -bs_tests also provides a hook which will be called from the embedded application +`bs_tests` also provides a hook which will be called from the embedded application :c:func:`main`, but this will only work if the main application supports it, that is, if the main app is a version for simulation which calls :c:func:`bst_main` when running in the bsim board. -Apart from these hooks, the bs_tests system provides facilities to build a +Apart from these hooks, the `bs_tests` system provides facilities to build a dedicated test "task". This will be executed in the HW models thread context, but will have access to all SW variables. This task will be driven with a special timer which can be configured to produce either periodic or one time @@ -286,12 +301,16 @@ at specific points in time. This can be combined with Babblesim's tb_defs macros to build quite complex test tasks which can wait for a given amount of time, for conditions to be fulfilled, etc. -Note: When writing the tests with bs_tests one needs to be aware that other +Note when writing the tests with `bs_tests` one needs to be aware that other bs tests will probably be built with the same application, and that therefore the tests should not be registering initialization or callback functions using NATIVE_TASKS or Zephyr's PRE/POST kernel driver initialization APIs as this will execute even if the test is not selected. -Instead the equivalent bs_tests provided hooks should be used. +Instead the equivalent `bs_tests` provided hooks should be used. + +Note also that, for AMP targets like the :ref:`nrf5340bsim `, each embedded MCU has +its own separate `bs_tests` built with that MCU. You can select if and what test is used +for each MCU separatedly with the command line options. Command line argument parsing ============================= diff --git a/boards/posix/doc/layering_natsim.svg b/boards/posix/doc/layering_natsim.svg new file mode 100644 index 000000000000000..535ad934e5e19fd --- /dev/null +++ b/boards/posix/doc/layering_natsim.svg @@ -0,0 +1,582 @@ + + + + + + + + + + + + + Sheet.1 + CPU/SOC + + + + CPU/SOC + Sheet.2 + HW peripherals + + + + HW peripherals + Sheet.3 + Drivers + + + + Drivers + Sheet.4 + Architecture/SOC dependent layer + + + + Architecture/SOC dependent layer + Sheet.5 + Zephyr Kernel + + + + ZephyrKernel + Sheet.6 + Application + + + + Application + Sheet.7 + Host OS Kernel (i.e. Linux) + + + + Host OS Kernel (i.e. Linux) Sheet.7Host OS Kernel (i.e. Linux)Overall scheduler & entry pointCPUemulationSheet.8HW models / host HW API adaptationPOSIX archand SOC + Sheet.9 + Drivers + + + + Drivers + Sheet.11 + Zephyr Kernel + + + + ZephyrKernel + Sheet.12 + Application + + + + Application + Sheet.13 + Normal Zephyr layering + + + + Normal Zephyr layering native simulator runner contextEmbedded CPU SW (Zephyr) context +native_sim & _bsimboards Zephyr layeringHW models /Host APIadaptation diff --git a/boards/posix/native_posix/CMakeLists.txt b/boards/posix/native_posix/CMakeLists.txt index d9b37953e776593..20210a46a81d89f 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/doc/index.rst b/boards/posix/native_posix/doc/index.rst index 73e3eb4110de389..61e6c1643278310 100644 --- a/boards/posix/native_posix/doc/index.rst +++ b/boards/posix/native_posix/doc/index.rst @@ -11,14 +11,28 @@ Native POSIX execution (native_posix) Overview ******** -This is a :ref:`POSIX architecture` based board. -With it, a Zephyr application can be compiled together with -the Zephyr kernel, creating a normal Linux executable. +``native_posix`` is the predecessor of :ref:`native_sim`. +Just like with :ref:`native_sim` you can build your Zephyr application +with the Zephyr kernel, creating a normal Linux executable with your host tooling, +and can debug and instrument it like any other Linux program. + +But unlike with :ref:`native_sim` you are limited to only using the host C library. +:ref:`native_sim` supports all ``native_posix`` use cases. + +.. note:: + + | If you are a new user, you are encouraged to use :ref:`native_sim` directly. + | If you have been using native_posix you are recommended to start using + :ref:`native_sim` instead. + | If needed, :ref:`native_sim` includes a compatibility mode + :kconfig:option:`CONFIG_NATIVE_SIM_NATIVE_POSIX_COMPAT`, + which will set its configuration to mimic a native_posix's like configuration. This board does not intend to simulate any particular HW, but it provides a few peripherals such as an Ethernet driver, display, UART, etc., to enable developing and testing application code which would require them. -See `Peripherals`_ for more information. +This board supports the same :ref:`peripherals` +:ref:`and backends as native_sim`. .. _native_posix_deps: @@ -36,15 +50,16 @@ Important limitations This board inherits :ref:`the limitations of its architecture` +Moreover, being limited to build only with the host C library, it is not possible to build +applications with the :ref:`Zephyr POSIX OS abstraction`, as there would be symbol +collisions between the host OS and this abstraction layer. + .. _native_posix_how_to_use: How to use it ************* -Compiling -========= - -Specify the native_posix board target to build a native POSIX application: +To build, simply specify the ``native_posix`` board as target: .. zephyr-app-commands:: :zephyr-app: samples/hello_world @@ -53,92 +68,20 @@ Specify the native_posix board target to build a native POSIX application: :goals: build :compact: -Running -======= - -The result of the compilation is an executable (zephyr.exe) placed in the -zephyr/ subdirectory of the build folder. -Run the zephyr.exe executable as you would any other Linux console application. - -.. code-block:: console - - $ ./build/zephyr/zephyr.exe - # Press Ctrl+C to exit - -This executable accepts several command line options depending on the -compilation configuration. -You can run it with the ``--help`` command line switch to get a list of -available options:: - - $ ./build/zephyr/zephyr.exe --help - -Note that the Zephyr kernel does not actually exit once the application is -finished. It simply goes into the idle loop forever. -Therefore you must stop the application manually (Ctrl+C in Linux). - -Application tests using the ``ztest`` framework will exit after all -tests have completed. - -If you want your application to gracefully finish when it reaches some point, -you may add a conditionally compiled (:kconfig:option:`CONFIG_ARCH_POSIX`) call to -``posix_exit(int status)`` at that point. - -.. _native_posix_debug: - -Debugging -========= - -Since the Zephyr executable is a native application, it can be debugged and -instrumented as any other native program. The program is compiled with debug -information, so it can be run directly in, for example, ``gdb`` or instrumented -with ``valgrind``. - -Because the execution of your Zephyr application is normally deterministic -(there are no asynchronous or random components), you can execute the -code multiple times and get the exact same result. Instrumenting the -code does not affect its execution. - -To ease debugging you may want to compile your code without optimizations -(e.g., -O0) by setting :kconfig:option:`CONFIG_NO_OPTIMIZATIONS`. - -.. _native_posix_asan: - -Address Sanitizer (ASan) -======================== - -You can also build Zephyr with the `Address Sanitizer`_. To do this, set -:kconfig:option:`CONFIG_ASAN`, for example, in the application project file, or in the -``west build`` or ``cmake`` command line invocation. - -Note that you will need the ASan library installed in your system. -In Debian/Ubuntu this is ``libasan1``. - -.. _Address Sanitizer: - https://github.com/google/sanitizers/wiki/AddressSanitizer - -Undefined Behavior Sanitizer (UBSan) -==================================== - -You can also build Zephyr with the `Undefined Behavior Sanitizer`_. To do this, set -:kconfig:option:`CONFIG_UBSAN`, for example, in the application project file, or in the -``west build`` or ``cmake`` command line invocation. - -.. _Undefined Behavior Sanitizer: - https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html - -Coverage reports -================ - -See -:ref:`coverage reports using the POSIX architecture`. +Now you have a Linux executable, ``./build/zephyr/zephyr.exe``, you can use just like any +other Linux program. +You can run, debug, build it with sanitizers or with coverage just like with +:ref:`native_sim`. +Please check :ref:`native_sim's how to` for more info. .. _native_posix32_64: 32 and 64bit versions ********************* -native_posix comes with two targets: A 32 bit and 64 bit version. +Just like :ref:`native_sim`, ``native_posix`` comes with two targets: +A 32 bit and 64 bit version. The 32 bit version, ``native_posix``, is the default target, which will compile your code for the ILP32 ABI (i386 in a x86 or x86_64 system) where pointers and longs are 32 bits. @@ -151,394 +94,3 @@ one with a 32bit userspace. The 64 bit version, ``native_posix_64``, compiles your code targeting the LP64 ABI (x86-64 in x86 systems), where pointers and longs are 64 bits. You can use this target if you cannot compile or run 32 bit binaries. - -If you are using another 32 bit POSIX arch target you may also override its ABI -target and pointer bit width by setting :kconfig:option:`CONFIG_64BIT`. - - -Rationale for this port and comparison with other options -********************************************************* - -The native_posix board shares the overall -:ref:`intent of the POSIX architecture`, -while being a HW agnostic test platform which in some cases utilizes the host -OS peripherals. -It does not intend to model any particular HW, and as such can only be used -to develop and test application code which is far decoupled from the HW. - -For developing and testing SW which requires specific HW, while retaining the -benefits of the POSIX architecture other solutions like the -:ref:`bsim boards` -should be considered. - -Check the :ref:`POSIX architecture comparison ` -with other development and test options for more insights. - -.. _native_posix_architecture: - -Architecture -************ - -This board is based on the POSIX architecture port of Zephyr and shares -:ref:`its basic architecture` regarding threading -and CPU/HW scheduling. - -This board does not try to emulate any particular embedded CPU or SOC. -The code is compiled natively for the host system (typically x86). - -About time in native_posix -========================== - -Normally simulated time runs fully decoupled from the real host time -and as fast as the host compute power would allow. -This is desirable when running in a debugger or testing in batch, but not if -interacting with external interfaces based on the real host time. - -The Zephyr kernel is only aware of the simulated time as provided by the -HW models. Therefore any normal Zephyr thread will also know only about -simulated time. - -The only link between the simulated time and the real/host time, if any, -is created by the clock and timer model. - -This model can be configured to slow down the execution of native_posix to -real time. -You can do this with the ``--rt`` and ``--no-rt`` options from the command line. -The default behavior is set with -:kconfig:option:`CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME`. -Note that all this model does is wait before raising the -next system tick interrupt until the corresponding real/host time. -If, for some reason, native_posix runs slower than real time, all this -model can do is "catch up" as soon as possible by not delaying the -following ticks. -So if the host load is too high, or you are running in a debugger, you will -see simulated time lagging behind the real host time. -This solution ensures that normal runs are still deterministic while -providing an illusion of real timeness to the observer. - -When locked to real time, simulated time can also be set to run faster or -slower than real time. -This can be controlled with the ``--rt-ratio=`` and ``-rt-drift=`` -command line options. Note that both of these options control the same -underlying mechanism, and that ``drift`` is by definition equal to -``ratio - 1``. -It is also possible to adjust this clock speed on the fly with -:c:func:`native_rtc_adjust_clock()`. - -In this way if, for example, ``--rt-ratio=2`` is given, the simulated time -will advance at twice the real time speed. -Similarly if ``--rt-drift=-100e-6`` is given, the simulated time will progress -100ppm slower than real time. -Note that these 2 options have no meaning when running in non real-time -mode. - -How simulated time and real time relate to each other ------------------------------------------------------ - -Simulated time (``st``) can be calculated from real time (``rt``) as - -``st = (rt - last_rt) * ratio + last_st`` - -And vice-versa: - -``rt = (st - last_st) / ratio + last_rt`` - -Where ``last_rt`` and ``last_st`` are respectively the real time and the -simulated time when the last clock ratio adjustment took place. - -All times are kept in microseconds. - -.. _native_posix_peripherals: - -Peripherals -*********** - -The following peripherals are currently provided with this board: - -**Interrupt controller**: - A simple yet generic interrupt controller is provided. It can nest interrupts - and provides interrupt priorities. Interrupts can be individually masked or - unmasked. SW interrupts are also supported. - -**Clock, timer and system tick model** - This model provides the system tick timer. By default - :kconfig:option:`CONFIG_SYS_CLOCK_TICKS_PER_SEC` configures it to tick every 10ms. - - This peripheral driver also provides the needed functionality for this - architecture-specific :c:func:`k_busy_wait`. - - Please refer to the section `About time in native_posix`_ for more - information. - -**UART/Serial** - Two optional native UART drivers are available: - - **PTTY driver (UART_NATIVE_POSIX)** - With this driver, one or two Zephyr UART devices can be created. These - can be connected to the Linux process stdin/stdout or a newly created - pseudo-tty. For more information refer to the section `PTTY UART`_. - - **TTY driver (UART_NATIVE_TTY)** - An UART driver for interacting with host-attached serial port devices - (eg. USB to UART dongles). For more information refer to the section - `TTY UART`_. - -**Real time clock** - The real time clock model provides a model of a constantly powered clock. - By default this is initialized to the host time at boot. - - This RTC can also be set to start from time 0 with the ``--rtc-reset`` command - line option. - - It is possible to offset the RTC clock value at boot with the - ``--rtc-offset=`` option, - or to adjust it dynamically with the function :c:func:`native_rtc_offset`. - - After start, this RTC advances with the simulated time, and is therefore - affected by the simulated time speed ratio. - See `About time in native_posix`_ for more information. - - The time can be queried with the functions :c:func:`native_rtc_gettime_us` - and :c:func:`native_rtc_gettime`. Both accept as parameter the clock source: - - - ``RTC_CLOCK_BOOT``: It counts the simulated time passed since boot. - It is not subject to offset adjustments - - ``RTC_CLOCK_REALTIME``: RTC persistent time. It is affected by - offset adjustments. - - ``RTC_CLOCK_PSEUDOHOSTREALTIME``: A version of the real host time, - as if the host was also affected by the clock speed ratio and offset - adjustments performed to the simulated clock and this RTC. Normally - this value will be a couple of hundredths of microseconds ahead of the - simulated time, depending on the host execution speed. - This clock source should be used with care, as depending on the actual - execution speed of native_posix and the host load, - it may return a value considerably ahead of the simulated time. - -**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 - with the same random seed. - You can change this random seed value by using the command line option: - ``--seed=`` where the value specified is a 32-bit integer - such as 97229 (decimal), 0x17BCD (hex), or 0275715 (octal). - -**Ethernet driver**: - A simple TAP based ethernet driver is provided. The driver will create - a **zeth** network interface to the host system. One can communicate with - Zephyr via this network interface. Multiple TAP based network interfaces can - be created if needed. The IP address configuration can be specified for each - network interface instance. - See :kconfig:option:`CONFIG_ETH_NATIVE_POSIX_SETUP_SCRIPT` option for more details. - The :zephyr:code-sample:`eth-native-posix` sample app provides - some use examples and more information about this driver configuration. - - Note that this device can only be used with Linux hosts, and that the user - needs elevated permissions. - -**Bluetooth controller**: - It's possible to use the host's Bluetooth adapter as a Bluetooth - controller for Zephyr. To do this the HCI device needs to be passed as - a command line option to ``zephyr.exe``. For example, to use ``hci0``, - use ``sudo zephyr.exe --bt-dev=hci0``. Using the device requires root - privileges (or the CAP_NET_ADMIN POSIX capability, to be exact) so - ``zephyr.exe`` needs to be run through ``sudo``. The chosen HCI device - must be powered down and support Bluetooth Low Energy (i.e. support the - Bluetooth specification version 4.0 or greater). - - Another possibility is to use a HCI TCP server which acts as a - :ref:`virtual Bluetooth controller` over TCP. - To connect to a HCI TCP server its IP address and port number must - be specified. For example, to connect to a HCI TCP server with IP - address 127.0.0.0 and port number 1020 use ``zephyr.exe --bt-dev=127.0.0.1:1020``. - This alternative option is mainly aimed for testing Bluetooth connectivity over - a virtual Bluetooth controller that does not depend on the Linux Bluetooth - stack and its HCI interface. - -**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_posix `. - -**Display driver**: - A display driver is provided that creates a window on the host machine to - render display content. - - This driver requires a 32-bit version of the `SDL2`_ library on the host - machine and ``pkg-config`` settings to correctly pickup the SDL2 install path - and compiler flags. - - On a Ubuntu 18.04 host system, for example, install the ``pkg-config`` and - ``libsdl2-dev:i386`` packages, and configure the pkg-config search path with - these commands:: - - $ 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 POSIX board devicetree or Kconfig settings under - :kconfig:option:`CONFIG_FLASH_SIMULATOR`. - - By default the binary data is located in the file *flash.bin* in the current - working directory. The location of this file can be changed through the - command line parameter *--flash*. The flash data will be stored in raw format - and the file will be truncated to match the size specified in the devicetree - configuration. In case the file does not exists the driver will take care of - creating the file, else the existing file is used. - - The flash content can be accessed from the host system, as explained in the - `Host based flash access`_ section. - -PTTY UART -********* - -This driver can be configured with :kconfig:option:`CONFIG_UART_NATIVE_POSIX` -to instantiate up to two UARTs. By default only one UART is enabled. -With :kconfig:option:`CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE` -you can enable the second one. - -For the first UART, it can link it to a new -pseudoterminal (i.e. ``/dev/pts``), or map the UART input and -output to the executable's ``stdin`` and ``stdout``. -This is chosen by selecting either -:kconfig:option:`CONFIG_NATIVE_UART_0_ON_OWN_PTY` or -:kconfig:option:`CONFIG_NATIVE_UART_0_ON_STDINOUT` -For interactive use with the :ref:`shell_api`, choose the first (OWN_PTY) option. -The second (STDINOUT) option can be used with the shell for automated -testing, such as when piping other processes' output to control it. -This is because the shell subsystem expects access to a raw terminal, -which (by default) a normal Linux terminal is not. - -When :kconfig:option:`CONFIG_NATIVE_UART_0_ON_OWN_PTY` is chosen, the name of the -newly created UART pseudo-terminal will be displayed in the console. -If you want to interact with it manually, you should attach a terminal emulator -to it. This can be done, for example with the command:: - - $ xterm -e screen /dev/ & - -where ``/dev/`` should be replaced with the actual TTY device. - -You may also chose to automatically attach a terminal emulator to the first UART -by passing the command line option ``-attach_uart`` to the executable. -The command used for attaching to the new shell can be set with the command line -option ``-attach_uart_cmd=<"cmd">``. Where the default command is given by -:kconfig:option:`CONFIG_NATIVE_UART_AUTOATTACH_DEFAULT_CMD`. -Note that the default command assumes both ``xterm`` and ``screen`` are -installed in the system. - -This driver only supports poll mode. Interrupt and async mode are not supported. -Neither runtime configuration or line control are supported. - -.. _native_tty_uart: - -TTY UART -******** - -With this driver an application can use the polling UART API (``uart_poll_out``, -``uart_poll_in``) to write and read characters to and from a connected serial -port device. - -This driver is automatically enabled when a devicetree contains a node -with ``"zephyr,native-tty-uart"`` compatible property and ``okay`` status, such -as one below:: - - uart { - status = "okay"; - compatible = "zephyr,native-tty-uart"; - serial-port = "/dev/ttyUSB0"; - current-speed = <115200>; - }; - -Interaction with serial ports can be configured in several different ways: - -* The default serial port and baud rate can be set via the device tree - properties ``serial-port`` and ``current-speed`` respectively. The - ``serial-port`` property is optional. -* Serial port and baud rate can also be set via command line options ``X_port`` - and ``X_baud`` respectively, where ``X`` is a name of a node. Command line - options override values from the devicetree. -* The rest of the configuration options such as number of data and stop bits, - parity, as well as baud rate can be set at runtime with ``uart_configure``. - -Multiple instances of such uart drivers are supported. - -The :zephyr:code-sample:`uart-native-tty` sample app provides a working example of the -driver. - -This driver only supports poll mode. Interrupt and async mode are not supported. -It has runtime configuration support, but no line control support. - -Subsystems backends -******************* - -Apart from its own peripherals, the native_posix 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: - -**Console backend**: - A console backend which by default is configured to - redirect any :c:func:`printk` write to the native host application's - ``stdout``. - - This driver is selected by default if the `PTTY UART`_ is not compiled in. - Otherwise :kconfig:option:`CONFIG_UART_CONSOLE` will be set to select the UART as - console backend. - -**Logger backend**: - A backend which prints all logger output to the process ``stdout``. - It supports timestamping, which can be enabled with - :kconfig:option:`CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP`; and colored output which can - be enabled with :kconfig:option:`CONFIG_LOG_BACKEND_SHOW_COLOR` and controlled - with the command line options ``--color``, ``--no-color`` and - ``--force-color``. - - In native_posix, by default, the logger is configured with - :kconfig:option:`CONFIG_LOG_MODE_IMMEDIATE`. - - This backend can be selected with :kconfig:option:`CONFIG_LOG_BACKEND_NATIVE_POSIX` - and is enabled by default unless the native_posix UART is compiled in. - In this later case, by default, the logger is set to output to the - `PTTY UART`_. - -**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 ` - -Host based flash access -*********************** - -If a flash device is present, the file system partitions on the flash -device can be exposed through the host file system by enabling -:kconfig:option:`CONFIG_FUSE_FS_ACCESS`. This option enables a FUSE -(File system in User space) layer that maps the Zephyr file system calls to -the required UNIX file system calls, and provides access to the flash file -system partitions with normal operating system commands such as ``cd``, -``ls`` and ``mkdir``. - -By default the partitions are exposed through the directory *flash* in the -current working directory. This directory can be changed via the command line -option *--flash-mount*. As this directory operates as a mount point for FUSE -you have to ensure that it exists before starting the native POSIX board. - -On exit, the native POSIX board application will take care of unmounting the -directory. In the unfortunate case that the native POSIX board application -crashes, you can cleanup the stale mount point by using the program -``fusermount``:: - - $ fusermount -u flash - -Note that this feature requires a 32-bit version of the FUSE library, with a -minimal version of 2.6, on the host system and ``pkg-config`` settings to -correctly pickup the FUSE install path and compiler flags. - -On a Ubuntu 18.04 host system, for example, install the ``pkg-config`` and -``libfuse-dev:i386`` packages, and configure the pkg-config search path with -these commands:: - - $ sudo apt-get install pkg-config libfuse-dev:i386 - $ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig diff --git a/boards/posix/native_posix/hw_counter.c b/boards/posix/native_posix/hw_counter.c index 77218a7ada41a83..eb02fd00807984d 100644 --- a/boards/posix/native_posix/hw_counter.c +++ b/boards/posix/native_posix/hw_counter.c @@ -17,6 +17,7 @@ static bool counter_running; static uint64_t counter_value; static uint64_t counter_target; static uint64_t counter_period; +static uint64_t counter_wrap; /** * Initialize the counter with prescaler of HW @@ -28,6 +29,7 @@ void hw_counter_init(void) counter_value = 0; counter_running = false; counter_period = NEVER; + counter_wrap = NEVER; } void hw_counter_triggered(void) @@ -38,7 +40,7 @@ void hw_counter_triggered(void) } hw_counter_timer = hwm_get_time() + counter_period; - counter_value = counter_value + 1; + counter_value = (counter_value + 1) % counter_wrap; if (counter_value == counter_target) { hw_irq_ctrl_set_irq(COUNTER_EVENT_IRQ); @@ -54,6 +56,16 @@ void hw_counter_set_period(uint64_t period) counter_period = period; } +/* + * Set the count value at which the counter will wrap + * The counter will count up to (counter_wrap-1), i.e.: + * 0, 1, 2,.., (counter_wrap - 1), 0 + */ +void hw_counter_set_wrap_value(uint64_t wrap_value) +{ + counter_wrap = wrap_value; +} + /** * Starts the counter. It must be previously configured with * hw_counter_set_period() and hw_counter_set_target(). @@ -82,6 +94,11 @@ void hw_counter_stop(void) hwm_find_next_timer(); } +bool hw_counter_is_started(void) +{ + return counter_running; +} + /** * Returns the current counter value. */ @@ -90,6 +107,14 @@ uint64_t hw_counter_get_value(void) return counter_value; } +/** + * Resets the counter value. + */ +void hw_counter_reset(void) +{ + counter_value = 0; +} + /** * Configures the counter to generate an interrupt * when its count value reaches target. diff --git a/boards/posix/native_posix/hw_counter.h b/boards/posix/native_posix/hw_counter.h index 5cd6dd2e57784b9..efbb7e39e293f1f 100644 --- a/boards/posix/native_posix/hw_counter.h +++ b/boards/posix/native_posix/hw_counter.h @@ -18,9 +18,12 @@ void hw_counter_triggered(void); void hw_counter_set_period(uint64_t period); void hw_counter_set_target(uint64_t counter_target); +void hw_counter_set_wrap_value(uint64_t wrap_value); void hw_counter_start(void); void hw_counter_stop(void); +bool hw_counter_is_started(void); uint64_t hw_counter_get_value(void); +void hw_counter_reset(void); #ifdef __cplusplus } diff --git a/boards/posix/native_posix/hw_models_top.c b/boards/posix/native_posix/hw_models_top.c index ebd582fb0b93273..ba2f7d6584c3210 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 47d3333277efefc..ea50d0f949c7b63 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 75af8bdb1fd2f9f..74a3c30049b5c6c 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 7d10c080474411e..d3ba08cc9a62be8 100644 --- a/boards/posix/native_posix/native_posix.yaml +++ b/boards/posix/native_posix/native_posix.yaml @@ -10,6 +10,8 @@ toolchain: - llvm supported: - can + - counter + - dma - eeprom - netif:eth - usb_device @@ -18,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 62d3b168497703f..544dac9cc2aa81c 100644 --- a/boards/posix/native_posix/native_posix_64.yaml +++ b/boards/posix/native_posix/native_posix_64.yaml @@ -10,6 +10,8 @@ toolchain: - llvm 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 34a538f4c60b306..5ddf0e5f143c4e5 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 aabbd4d794f4e42..ddf76a5f157ae6a 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 5286de1b4257a8f..64579fc4631a934 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -3,18 +3,33 @@ Native simulator - native_sim ############################# +.. contents:: + :depth: 1 + :backlinks: entry + :local: + Overview ******** -The native_sim board is an evolution of :ref:`native_posix`. -Just like with :ref:`native_posix` you can build your Zephyr application -with the Zephyr kernel, creating a normal Linux executable with your host tooling, -and can debug and instrument it like any other Linux program. +The ``native_sim`` board is a :ref:`POSIX architecture` based board. +With it, a Zephyr application can be compiled together with +the Zephyr kernel, and libraries, creating a normal Linux executable. -native_sim is based on the +``native_sim`` is based on the `native simulator `_ and the :ref:`POSIX architecture`. +This board does not intend to simulate any particular HW, but it provides +a few peripherals such as an Ethernet driver, display, UART, etc., to enable +developing and testing application code which would require them. +See `Peripherals`_ for more information. + +.. note:: + + | ``native_sim`` is an evolution of the older :ref:`native_posix`. + | Some components, code, options names, and documentation will still use the old native_posix + names. But all components which worked with native_posix will work with native_sim. + Host system dependencies ************************ @@ -23,16 +38,27 @@ Please check the .. _nativesim_important_limitations: -Important limitations -********************* +Important limitations and unsupported features +********************************************** -Native_sim is based on the :ref:`POSIX architecture`, and therefore +``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 ************* -To build, simply specify the native_sim board as target: +Compiling +========= + +To build, simply specify the ``native_sim`` board as target: .. zephyr-app-commands:: :zephyr-app: samples/hello_world @@ -41,17 +67,96 @@ To build, simply specify the native_sim board as target: :goals: build :compact: -Now you have a Linux executable, ``./build/zephyr/zephyr.exe``, you can use just like any -other Linux program. +Running +======= + +The result of the compilation is an executable (``zephyr.exe``) placed in the +``zephyr/`` subdirectory of the ``build`` folder. +Run the ``zephyr.exe`` executable as you would any other Linux console application. + +.. code-block:: console + + $ ./build/zephyr/zephyr.exe + # Press Ctrl+C to exit + +This executable accepts several command line options depending on the +compilation configuration. +You can run it with the ``--help`` command line switch to get a list of +available options. + +.. code-block:: console + + $ ./build/zephyr/zephyr.exe --help + +Note that the Zephyr kernel does not actually exit once the application is +finished. It simply goes into the idle loop forever. +Therefore you must stop the application manually (Ctrl+C in Linux). + +Application tests using the :ref:`ztest framework` will exit after all +tests have completed. + +If you want your application to gracefully finish when it reaches some point, +you may add a conditionally compiled (:kconfig:option:`CONFIG_ARCH_POSIX`) call to +``nsi_exit(int status)`` at that point. + +.. _native_sim_debug: + +Debugging +========= -You can run, debug, build it with sanitizers or with coverage just like with -:ref:`native_posix `. -Please check :ref:`native_posix's how to` for more info. +Since the Zephyr executable is a native application, it can be debugged and +instrumented as any other native program. The program is compiled with debug +information, so it can be run directly in, for example, ``gdb`` or instrumented +with ``valgrind``. + +Because the execution of your Zephyr application is normally deterministic +(there are no asynchronous or random components), you can execute the +code multiple times and get the exact same result. Instrumenting the +code does not affect its execution. + +To ease debugging you may want to compile your code without optimizations +(e.g., ``-O0``) by setting :kconfig:option:`CONFIG_NO_OPTIMIZATIONS`. + +For ease of debugging consider using an IDE as GUI for your debugger. + +.. _native_sim_asan: + +Address Sanitizer (ASan) +======================== + +You can also build Zephyr with the `Address Sanitizer`_. To do this, set +:kconfig:option:`CONFIG_ASAN`, for example, in the application project file, or in the +``west build`` or ``cmake`` command line invocation. + +Note that you will need the ASan library installed in your system. +In Debian/Ubuntu this is ``libasan1``. + +.. _Address Sanitizer: + https://github.com/google/sanitizers/wiki/AddressSanitizer + +Undefined Behavior Sanitizer (UBSan) +==================================== + +You can also build Zephyr with the `Undefined Behavior Sanitizer`_. To do this, set +:kconfig:option:`CONFIG_UBSAN`, for example, in the application project file, or in the +``west build`` or ``cmake`` command line invocation. + +.. _Undefined Behavior Sanitizer: + https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html + +Coverage reports +================ + +See +:ref:`coverage reports using the POSIX architecture`. + + +.. _native_sim32_64: 32 and 64bit versions -********************* +===================== -Just like native_posix, native_sim comes with two targets: A 32 bit and 64 bit version. +native_sim comes with two targets: A 32 bit and 64 bit version. The 32 bit version, ``native_sim``, is the default target, which will compile your code for the ILP32 ABI (i386 in a x86 or x86_64 system) where pointers and longs are 32 bits. @@ -70,61 +175,531 @@ You can use this target if you cannot compile or run 32 bit binaries. C library choice **************** -Unlike native_posix, native_sim may be compiled with a choice of C libraries. +native_sim may be compiled with a choice of C libraries. By default it will be compiled with the host C library (:kconfig:option:`CONFIG_EXTERNAL_LIBC`), but you can also select to build it with :kconfig:option:`CONFIG_MINIMAL_LIBC` or with :kconfig:option:`CONFIG_PICOLIBC`. +If you select some feature which are not compatible with the host C library, +:ref:`Picolibc ` will be selected by default instead. -When building with either :ref:`MINIMAL` or :ref:`PICO` libC +When building with either :ref:`minimal ` or :ref:`Picolibc` you will build your code in a more similar way as when building for the embedded target, you will be able to test your code interacting with that C library, and there will be no conflicts with the :ref:`POSIX OS abstraction` shim, but, accessing the host for test purposes from your embedded code will be more difficult, and you will have a limited choice of -:ref:`drivers and backends to chose from`. +:ref:`drivers and backends to chose from`. + +Rationale for this port and comparison with other options +********************************************************* + +The native_sim board shares the overall +:ref:`intent of the POSIX architecture`, +while being a HW agnostic test platform which in some cases utilizes the host +OS peripherals. +It does not intend to model any particular HW, and as such can only be used +to develop and test application code which is far decoupled from the HW. + +For developing and testing SW which requires specific HW, while retaining the +benefits of the POSIX architecture other solutions like the +:ref:`bsim boards` +should be considered. + +Check the :ref:`POSIX architecture comparison ` +with other development and test options for more insights. + +.. _native_sim_architecture: Architecture ************ -:ref:`native_posix's architecture description` as well as the -:ref:`POSIX architecture description` are directly -applicable to native_sim. +This board is based on the POSIX architecture port of Zephyr and shares +:ref:`its basic architecture` regarding threading +and CPU/HW scheduling. -If you are interested on the inner workigns of the native simulator itself, you can check +If you are interested on the inner workings of the native simulator itself, you can check `its documentation `_. +This board does not try to emulate any particular embedded CPU or SOC. +The code is compiled natively for the host system (typically x86). + +About time in native_sim +======================== + +Normally simulated time runs fully decoupled from the real host time +and as fast as the host compute power would allow. +This is desirable when running in a debugger or testing in batch, but not if +interacting with external interfaces based on the real host time. + +The Zephyr kernel is only aware of the simulated time as provided by the +HW models. Therefore any normal Zephyr thread will also know only about +simulated time. + +The only link between the simulated time and the real/host time, if any, +is created by the clock and timer model. + +This model can be configured to slow down the execution of native_sim to +real time. +You can do this with the ``--rt`` and ``--no-rt`` options from the command line. +The default behavior is set with +:kconfig:option:`CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME`. + +Note that all this model does is wait before raising the +next system tick interrupt until the corresponding real/host time. +If, for some reason, native_sim runs slower than real time, all this +model can do is "catch up" as soon as possible by not delaying the +following ticks. +So if the host load is too high, or you are running in a debugger, you will +see simulated time lagging behind the real host time. +This solution ensures that normal runs are still deterministic while +providing an illusion of real timeness to the observer. + +When locked to real time, simulated time can also be set to run faster or +slower than real time. +This can be controlled with the ``--rt-ratio=`` and ``-rt-drift=`` +command line options. Note that both of these options control the same +underlying mechanism, and that ``drift`` is by definition equal to +``ratio - 1``. +It is also possible to adjust this clock speed on the fly with +:c:func:`native_rtc_adjust_clock()`. + +In this way if, for example, ``--rt-ratio=2`` is given, the simulated time +will advance at twice the real time speed. +Similarly if ``--rt-drift=-100e-6`` is given, the simulated time will progress +100ppm slower than real time. +Note that these 2 options have no meaning when running in non real-time +mode. + +How simulated time and real time relate to each other +----------------------------------------------------- + +Simulated time (``st``) can be calculated from real time (``rt``) as + +.. math:: + st = (rt - last\_rt) \times ratio + last\_st + +And vice-versa: + +.. math:: + rt = (st - last\_st) / ratio + last\_rt + +Where ``last_rt`` and ``last_st`` are respectively the real time and the +simulated time when the last clock ratio adjustment took place. + +All times are kept in microseconds. + .. _native_sim_peripherals: -Peripherals, subsystems backends and host based flash access -************************************************************ +Peripherals +*********** + +The following peripherals are currently provided with this board: + +**Interrupt controller** + A simple yet generic interrupt controller is provided. It can nest interrupts + and provides interrupt priorities. Interrupts can be individually masked or + unmasked. SW interrupts are also supported. + +**Clock, timer and system tick model** + This model provides the system tick timer. By default + :kconfig:option:`CONFIG_SYS_CLOCK_TICKS_PER_SEC` configures it to tick every 10ms. + + Please refer to the section `About time in native_sim`_ for more + information. + +**UART/Serial** + Two optional native UART drivers are available: + + **PTTY driver (UART_NATIVE_POSIX)** + With this driver, one or two Zephyr UART devices can be created. These + can be connected to the Linux process stdin/stdout or a newly created + pseudo-tty. For more information refer to the section `PTTY UART`_. + + **TTY driver (UART_NATIVE_TTY)** + An UART driver for interacting with host-attached serial port devices + (eg. USB to UART dongles). For more information refer to the section + `TTY UART`_. + +**Real time clock** + The real time clock model provides a model of a constantly powered clock. + By default this is initialized to the host time at boot. + + This RTC can also be set to start from time 0 with the ``--rtc-reset`` command + line option. + + It is possible to offset the RTC clock value at boot with the + ``--rtc-offset=`` option, + or to adjust it dynamically with the function :c:func:`native_rtc_offset`. + + After start, this RTC advances with the simulated time, and is therefore + affected by the simulated time speed ratio. + See `About time in native_sim`_ for more information. + + The time can be queried with the functions :c:func:`native_rtc_gettime_us` + and :c:func:`native_rtc_gettime`. Both accept as parameter the clock source: + + - ``RTC_CLOCK_BOOT``: It counts the simulated time passed since boot. + It is not subject to offset adjustments + - ``RTC_CLOCK_REALTIME``: RTC persistent time. It is affected by + offset adjustments. + - ``RTC_CLOCK_PSEUDOHOSTREALTIME``: A version of the real host time, + as if the host was also affected by the clock speed ratio and offset + adjustments performed to the simulated clock and this RTC. Normally + this value will be a couple of hundredths of microseconds ahead of the + simulated time, depending on the host execution speed. + This clock source should be used with care, as depending on the actual + 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 + with the same random seed. + You can change this random seed value by using the command line option: + :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** + network interface can be created by the ``net-setup.sh`` script found in + the `net-tools`_ zephyr project repository. User can communicate with the + Zephyr instance via the **zeth** network interface. Multiple TAP based + network interfaces can be created if needed. The IP address configuration + can be specified for each network interface instance. + + Note that this device can only be used with Linux hosts. + +.. _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 + controller for Zephyr. To do this the HCI device needs to be passed as + a command line option to ``zephyr.exe``. For example, to use ``hci0``, + use ``sudo zephyr.exe --bt-dev=hci0``. Using the device requires root + privileges (or the CAP_NET_ADMIN POSIX capability, to be exact) so + ``zephyr.exe`` needs to be run through ``sudo``. The chosen HCI device + must be powered down and support Bluetooth Low Energy (i.e. support the + Bluetooth specification version 4.0 or greater). + + Another possibility is to use a HCI TCP server which acts as a + :ref:`virtual Bluetooth controller` over TCP. + To connect to a HCI TCP server its IP address and port number must + be specified. For example, to connect to a HCI TCP server with IP + address 127.0.0.0 and port number 1020 use ``zephyr.exe --bt-dev=127.0.0.1:1020``. + This alternative option is mainly aimed for testing Bluetooth connectivity over + 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. + + This driver requires a 32-bit version of the `SDL2`_ library on the host + machine and ``pkg-config`` settings to correctly pickup the SDL2 install path + and compiler flags. + + On a Ubuntu 22.04 host system, for example, install the ``pkg-config`` and + ``libsdl2-dev:i386`` packages, and configure the pkg-config search path with + these commands: + + .. 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 + +.. _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 + working directory. The location of this file can be changed through the + command line parameter ``--flash``. The flash data will be stored in raw format + and the file will be truncated to match the size specified in the devicetree + 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 +========= + +This driver can be configured with :kconfig:option:`CONFIG_UART_NATIVE_POSIX` +to instantiate up to two UARTs. By default only one UART is enabled. +With :kconfig:option:`CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE` +you can enable the second one. + +For the first UART, it can link it to a new +pseudoterminal (i.e. :file:`/dev/pts{}`), or map the UART input and +output to the executable's ``stdin`` and ``stdout``. +This is chosen by selecting either +:kconfig:option:`CONFIG_NATIVE_UART_0_ON_OWN_PTY` or +:kconfig:option:`CONFIG_NATIVE_UART_0_ON_STDINOUT` +For interactive use with the :ref:`shell_api`, choose the first (OWN_PTY) option. +The second (STDINOUT) option can be used with the shell for automated +testing, such as when piping other processes' output to control it. +This is because the shell subsystem expects access to a raw terminal, +which (by default) a normal Linux terminal is not. + +When :kconfig:option:`CONFIG_NATIVE_UART_0_ON_OWN_PTY` is chosen, the name of the +newly created UART pseudo-terminal will be displayed in the console. +If you want to interact with it manually, you should attach a terminal emulator +to it. This can be done, for example with the command: + +.. code-block:: console + + $ xterm -e screen /dev/ & + +where :file:`/dev/tty{}` should be replaced with the actual TTY device. + +You may also chose to automatically attach a terminal emulator to the first UART +by passing the command line option ``-attach_uart`` to the executable. +The command used for attaching to the new shell can be set with the command line +option ``-attach_uart_cmd=<"cmd">``. Where the default command is given by +:kconfig:option:`CONFIG_NATIVE_UART_AUTOATTACH_DEFAULT_CMD`. +Note that the default command assumes both ``xterm`` and ``screen`` are +installed in the system. + +This driver only supports poll mode. Interrupt and async mode are not supported. +Neither runtime configuration or line control are supported. + +.. _native_tty_uart: + +TTY UART +======== + +With this driver an application can use the polling UART API (``uart_poll_out``, +``uart_poll_in``) to write and read characters to and from a connected serial +port device. + +This driver is automatically enabled when a devicetree contains a node +with ``"zephyr,native-tty-uart"`` compatible property and ``okay`` status, such +as one below. + +.. code-block:: dts + + uart { + status = "okay"; + compatible = "zephyr,native-tty-uart"; + serial-port = "/dev/ttyUSB0"; + current-speed = <115200>; + }; + +Interaction with serial ports can be configured in several different ways: + +* The default serial port and baud rate can be set via the device tree + properties ``serial-port`` and ``current-speed`` respectively. The + ``serial-port`` property is optional. +* Serial port and baud rate can also be set via command line options ``X_port`` + and ``X_baud`` respectively, where ``X`` is a name of a node. Command line + options override values from the devicetree. +* The rest of the configuration options such as number of data and stop bits, + parity, as well as baud rate can be set at runtime with ``uart_configure``. + +Multiple instances of such uart drivers are supported. + +The :zephyr:code-sample:`uart-native-tty` sample app provides a working example of the +driver. + +This driver only supports poll mode. Interrupt and async mode are not supported. +It has runtime configuration support, but no line control support. + +.. _native_sim_backends: + +Subsystems backends +******************* + +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 + ``stdout``. + + This driver is selected by default if the `PTTY UART`_ is not compiled in. + 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 + :kconfig:option:`CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP`; and colored output which can + be enabled with :kconfig:option:`CONFIG_LOG_BACKEND_SHOW_COLOR` and controlled + with the command line options ``--color``, ``--no-color`` and + ``--force-color``. + + In native_sim, by default, the logger is configured with + :kconfig:option:`CONFIG_LOG_MODE_IMMEDIATE`. + + This backend can be selected with :kconfig:option:`CONFIG_LOG_BACKEND_NATIVE_POSIX` + and is enabled by default unless the PTTY UART is compiled in. + 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 +*********************** + +If a flash device is present, the file system partitions on the flash +device can be exposed through the host file system by enabling +:kconfig:option:`CONFIG_FUSE_FS_ACCESS`. This option enables a FUSE +(File system in User space) layer that maps the Zephyr file system calls to +the required UNIX file system calls, and provides access to the flash file +system partitions with normal operating system commands such as ``cd``, +``ls`` and ``mkdir``. + +By default the partitions are exposed through the directory :file:`flash/` in the +current working directory. This directory can be changed via the command line +option ``--flash-mount``. As this directory operates as a mount point for FUSE +you have to ensure that it exists before starting the native_sim board. + +On exit, the native_sim board application will take care of unmounting the +directory. In the unfortunate case that the native_sim board application +crashes, you can cleanup the stale mount point by using the program +``fusermount``: + +.. code-block:: console + + $ fusermount -u flash + +Note that this feature requires a 32-bit version of the FUSE library, with a +minimal version of 2.6, on the host system and ``pkg-config`` settings to +correctly pickup the FUSE install path and compiler flags. + +On a Ubuntu 22.04 host system, for example, install the ``pkg-config`` and +``libfuse-dev:i386`` packages, and configure the pkg-config search path with +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 + +.. _native_sim_peripherals_c_compat: + +Peripherals and backends C library compatibility +************************************************ -Today, native_sim supports the exact same -:ref:`peripherals and backends as native_posix`, -with the only caveat that some of these are, so far, only available when compiling with the -host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`). +Today, some native_sim peripherals and backends are, so far, only available when compiling with the +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`, host libC - 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 3ad8058eb5b9cd3..38462b4b14a4281 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 a2b5dc0299bf7e2..6c943606f3fb4a6 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 b27a9bd540d2d02..682049c63caf49a 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 daa76cdab92c95b..999b52aa16b7049 100644 --- a/boards/posix/native_sim/native_sim.yaml +++ b/boards/posix/native_sim/native_sim.yaml @@ -10,6 +10,7 @@ toolchain: - llvm supported: - can + - counter - eeprom - netif:eth - usb_device @@ -18,4 +19,6 @@ supported: - spi - gpio - rtc +testing: + default: true vendor: zephyr diff --git a/boards/posix/native_sim/native_sim_64.yaml b/boards/posix/native_sim/native_sim_64.yaml index 487f623894dabdd..52841d23b2b3ea2 100644 --- a/boards/posix/native_sim/native_sim_64.yaml +++ b/boards/posix/native_sim/native_sim_64.yaml @@ -10,6 +10,7 @@ toolchain: - llvm supported: - can + - counter - eeprom - netif:eth - usb_device diff --git a/boards/posix/nrf_bsim/CMakeLists.txt b/boards/posix/nrf_bsim/CMakeLists.txt index a9c8f68417147c7..3ff7d632d4f2a62 100644 --- a/boards/posix/nrf_bsim/CMakeLists.txt +++ b/boards/posix/nrf_bsim/CMakeLists.txt @@ -26,6 +26,11 @@ zephyr_library_sources( common/trace_hook.c ) +# Include sync_rtc from real SOC code if enabled +zephyr_library_sources_ifdef(CONFIG_NRF53_SYNC_RTC + ${ZEPHYR_BASE}/soc/arm/nordic_nrf/nrf53/sync_rtc.c + ) + target_sources(native_simulator INTERFACE common/bsim_args_runner.c common/bsim_extra_cpu_if_stubs.c @@ -35,6 +40,12 @@ target_sources(native_simulator INTERFACE common/trace_hook.c ) +if (CONFIG_IPC_SERVICE AND CONFIG_BOARD_NRF5340BSIM_NRF5340_CPUAPP) + zephyr_library_sources( + ipc_backend.c + ) +endif() + zephyr_include_directories( soc common @@ -62,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 206203175215f31..c9a855d2111dbaa 100644 --- a/boards/posix/nrf_bsim/Kconfig +++ b/boards/posix/nrf_bsim/Kconfig @@ -8,6 +8,8 @@ if SOC_SERIES_BSIM_NRFXX # must be read also from here. source "soc/arm/nordic_nrf/Kconfig.peripherals" +source "boards/$(ARCH)/common/extra_args/Kconfig" + endif # SOC_SERIES_BSIM_NRFXX @@ -17,18 +19,40 @@ 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 + +if BOARD_NRF5340BSIM_NRF5340_CPUAPP + +# Replica of the option provided by the BOARD_NRF5340DK_NRF5340_CPUAPP board so samples can be +# reused as is +config BOARD_ENABLE_CPUNET + bool "NRF53 Network MCU" + +endif # BOARD_NRF5340BSIM_NRF5340_CPUNET + +if SOC_SERIES_BSIM_NRF53X + +# Let's reuse the RTC sync options so applications which use it can be reused as is +source "soc/arm/nordic_nrf/nrf53/Kconfig.sync_rtc" + +endif # SOC_SERIES_BSIM_NRF53X diff --git a/boards/posix/nrf_bsim/Kconfig.board b/boards/posix/nrf_bsim/Kconfig.board index 4a701c9acdc5d79..fcfbae4d4e762af 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 5dc756611175e1a..d4e48ada7ad3b86 100644 --- a/boards/posix/nrf_bsim/Kconfig.defconfig +++ b/boards/posix/nrf_bsim/Kconfig.defconfig @@ -6,7 +6,9 @@ config BUILD_OUTPUT_BIN default n config BUILD_OUTPUT_EXE - default y + # When the IPC service is used, the net core image requires the application core image, as it needs + # access to its IPC buffer. Without it, the executable cannot be built. + default y if !(BOARD_NRF5340BSIM_NRF5340_CPUNET && IPC_SERVICE && (NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS = "")) config OUTPUT_PRINT_MEMORY_USAGE default n @@ -42,6 +44,30 @@ config BT_CTLR default y if BOARD_NRF52_BSIM || BOARD_NRF5340BSIM_NRF5340_CPUNET depends on BT +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 + +if BOARD_NRF5340BSIM_NRF5340_CPUAPP || BOARD_NRF5340BSIM_NRF5340_CPUNET + +config MBOX_NRFX_IPC + default MBOX + +endif # BOARD_NRF5340BSIM_NRF5340_CPUAPP || BOARD_NRF5340BSIM_NRF5340_CPUNET + +if BOARD_NRF5340BSIM_NRF5340_CPUAPP + +config IPC_SERVICE_BACKEND_RPMSG_SHMEM_RESET + default y if IPC_SERVICE_BACKEND_RPMSG + +choice BT_HCI_BUS_TYPE + default BT_HCI_IPC +endchoice + +endif # BOARD_NRF5340BSIM_NRF5340_CPUAPP + # The 15.4 driver Tx encryption is currently not functional with this # simulated board => we disable it by default. With this Openthread will normally # default to encrypt packets on its own. @@ -61,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 1b7e7a85c0cf1a3..d75a187aa610990 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 29e0d15dd2ee743..2e84ca812fe75fa 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/common/bstests_entry.c b/boards/posix/nrf_bsim/common/bstests_entry.c index 3e771195478881c..c1f08deb9cd5c68 100644 --- a/boards/posix/nrf_bsim/common/bstests_entry.c +++ b/boards/posix/nrf_bsim/common/bstests_entry.c @@ -10,6 +10,7 @@ #include "bs_tracing.h" #include "bstests.h" #include "bs_oswrap.h" +#include "nsi_host_trampolines.h" /* * Result of the testcase execution. @@ -230,7 +231,7 @@ uint8_t bst_delete(void) while (test_list_top) { struct bst_test_list *tmp = test_list_top->next; - free(test_list_top); + nsi_host_free(test_list_top); test_list_top = tmp; } diff --git a/boards/posix/nrf_bsim/common/phy_sync_ctrl.c b/boards/posix/nrf_bsim/common/phy_sync_ctrl.c index fc4a7992837efde..b7b6c507d4f93b9 100644 --- a/boards/posix/nrf_bsim/common/phy_sync_ctrl.c +++ b/boards/posix/nrf_bsim/common/phy_sync_ctrl.c @@ -214,6 +214,13 @@ NSI_TASK(phy_sync_ctrl_register_args, PRE_BOOT_1, 10); void phy_sync_ctrl_connect_to_2G4_phy(void) { + static bool ever_run; + + if (ever_run) { + return; + } + ever_run = true; + bs_trace_raw(9, "%s: Connecting to phy...\n", __func__); hwll_connect_to_phy(bsim_args_get_2G4_device_nbr(), bsim_args_get_simid(), @@ -223,6 +230,13 @@ void phy_sync_ctrl_connect_to_2G4_phy(void) void phy_sync_ctrl_pre_boot2(void) { + static bool ever_run; + + if (ever_run) { + return; + } + ever_run = true; + if (((sync_args.start_offset > 0) && (sync_args.delay_init)) || sync_args.sync_preinit) { /* Delay the next steps until the simulation time has @@ -235,6 +249,13 @@ void phy_sync_ctrl_pre_boot2(void) void phy_sync_ctrl_pre_boot3(void) { + static bool ever_run; + + if (ever_run) { + return; + } + ever_run = true; + /* * If sync_preboot was set, we sync with the phy * right before booting the CPU diff --git a/boards/posix/nrf_bsim/doc/nrf52_bsim.rst b/boards/posix/nrf_bsim/doc/nrf52_bsim.rst index f8b7cad6628491b..78c8e5c327963e9 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. @@ -182,7 +183,7 @@ Check the :ref:`native simulator C library choice section`, the resulting +Just like with :ref:`native_sim`, the resulting executables are Linux native applications. Therefore they can be debugged or instrumented with the same tools as any other native application, like for example ``gdb`` or ``valgrind``. @@ -191,7 +192,7 @@ The same :ref:`code coverage analysis means from the POSIX arch` are inherited in this board. Similarly, the -:ref:`address and undefined behavior sanitizers can be used as in native_posix`. +:ref:`address and undefined behavior sanitizers can be used as in native_sim`. Note that BabbleSim will run fine if one or several of its components are diff --git a/boards/posix/nrf_bsim/doc/nrf5340bsim.rst b/boards/posix/nrf_bsim/doc/nrf5340bsim.rst index 5364cd0a307199a..f2ece408e08859f 100644 --- a/boards/posix/nrf_bsim/doc/nrf5340bsim.rst +++ b/boards/posix/nrf_bsim/doc/nrf5340bsim.rst @@ -28,29 +28,26 @@ core on the simulated nRF5340 SOC. These boards include models of some of the nRF5340 SOC peripherals: -* Radio -* Timers * AAR (Accelerated Address Resolver) * AES CCM & AES ECB encryption HW * CLOCK (Clock control) * DPPI (Distributed Programmable Peripheral Interconnect) * EGU (Event Generator Unit) * FICR (Factory Information Configuration Registers) +* IPC (Interprocessor communication) +* MUTEX (Mutual exclusive peripheral) * NVMC (Non-Volatile Memory Controller / Flash) +* RADIO * RNG (Random Number Generator) * RTC (Real Time Counter) * TEMP (Temperature sensor) +* TIMER * UICR (User Information Configuration Registers) and will use the same drivers as the nrf5340dk targets for these. For more information on what is modelled to which level of detail, check the `HW models implementation status`_. -.. note:: - - The IPC and MUTEX peripherals are not yet present in these models. Therefore communication - between the cores using Zephyr's IPC driver is not yet possible. - Note that unlike a real nrf5340 device, the nrf5340bsim boards have unlimited RAM and flash for code. @@ -96,16 +93,17 @@ built with either Zephyr's build system or another native simulator compatible b you can provide that image to the Zephyr build of the second image using :kconfig:option:`CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS`. +You can also use :ref:`System build (sysbuild) ` to build your dual MCU executable. +The best way to understand how, may be to look into how this is done in one of the examples +in the tree. For example, for :ref:`the nrf53_sync_rtc sample `, +:zephyr_file:`samples/boards/nrf/nrf53_sync_rtc/sysbuild.cmake`. + .. note:: These libraries/images are **not** embedded images. You cannot use them for embedded devices, and cannot use an embedded image to assemble a native executable. -.. note:: - - OpenAMP is not yet supported in these boards. - TrustZone, TF-M and other security considerations ************************************************* diff --git a/boards/posix/nrf_bsim/ipc_backend.c b/boards/posix/nrf_bsim/ipc_backend.c new file mode 100644 index 000000000000000..4f14924a44a5fd7 --- /dev/null +++ b/boards/posix/nrf_bsim/ipc_backend.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Here we define the shared memory buffers for the RPMSG IPC back-end in simulation. + * In real HW, these are booked in RAM thru device tree configuration. + * In this simulated target, we just define them at build time to have the size defined + * in device tree. + * + * Note that this file is only compiled as part of the application core image, and therefore + * when the network core is built with the IPC service, we cannot produce an executable + * with the network core image alone, as we would lack this buffer during linking. + */ + +#include "nsi_cpu_if.h" +#include + +#define DT_DRV_COMPAT zephyr_ipc_openamp_static_vrings + +#define DEFINE_BACKEND_BUFFER(i) \ + NATIVE_SIMULATOR_IF \ + char IPC##i##_shm_buffer[DT_REG_SIZE(DT_INST_PHANDLE(i, memory_region))]; + +DT_INST_FOREACH_STATUS_OKAY(DEFINE_BACKEND_BUFFER) diff --git a/boards/posix/nrf_bsim/irq_handler.c b/boards/posix/nrf_bsim/irq_handler.c index 24c00a4f79cf770..2d6ad4f66b7c431 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 9c01240540eb7b8..8410c80fb74974e 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; @@ -54,6 +56,7 @@ /delete-node/ spi@40004000; /delete-node/ spi@40023000; /delete-node/ spi@4002f000; + /delete-node/ nfct@40005000; /delete-node/ watchdog@40010000; /delete-node/ acl@4001e000; /delete-node/ usbd@40027000; @@ -97,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 5b29b9740098f2d..17aba03864e0be3 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 42231465cea194f..953e8c1aa931e6d 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 b967c0106534c01..72194f3b0e1b68f 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; @@ -45,7 +41,11 @@ }; chosen { + zephyr,entropy = &rng_hci; zephyr,flash = &flash0; + zephyr,bt-hci-ipc = &ipc0; + nordic,802154-spinel-ipc = &ipc0; + zephyr,ieee802154 = &ieee802154; }; soc { @@ -57,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; @@ -78,10 +74,8 @@ /delete-node/ pwm@24000; /delete-node/ pdm@26000; /delete-node/ i2s@28000; - /delete-node/ mbox@2a000; /delete-node/ qspi@2b000; /delete-node/ nfct@2d000; - /delete-node/ mutex@30000; /delete-node/ qdec@33000; /delete-node/ qdec@34000; /delete-node/ usbd@36000; @@ -97,7 +91,6 @@ }; /delete-node/ cpus; - /delete-node/ ipc; /delete-node/ sw-pwm; }; @@ -118,3 +111,8 @@ }; }; }; + +/* We re-use the IPC shared buffer definition from the real HW. But note the start address of the + * buffer won't be used. + */ +#include <../boards/arm/nrf5340dk_nrf5340/nrf5340_shared_sram_planning_conf.dtsi> diff --git a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.yaml b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.yaml index 822368df0d39c15..448d4f330c3bfdf 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 138cde81ef1564a..93e3ee271634e85 100644 --- a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.dts +++ b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.dts @@ -21,12 +21,13 @@ /delete-property/ wdt-0; /delete-property/ i2c-0; /delete-property/ spi-0; - /delete-property/ uart-0; /delete-property/ gpio-0; /delete-property/ gpio-1; }; chosen { + zephyr,bt-hci-ipc = &ipc0; + nordic,802154-spinel-ipc = &ipc0; zephyr,ieee802154 = &ieee802154; /delete-property/ zephyr,flash-controller; zephyr,flash = &flash1; @@ -37,10 +38,8 @@ /delete-node/ memory@21000000; /delete-node/ gpiote@4100a000; /delete-node/ watchdog@4100b000; - /delete-node/ mbox@41012000; /delete-node/ i2c@41013000; /delete-node/ spi@41013000; - /delete-node/ uart@41013000; /delete-node/ acl@41080000; /delete-node/ vmc@41081000; /delete-node/ gpio@418c0500; @@ -48,7 +47,6 @@ }; /delete-node/ cpus; - /delete-node/ ipc; /delete-node/ sw-pwm; }; @@ -75,3 +73,8 @@ }; }; }; + +/* We re-use the IPC shared buffer definition from the real HW. But note the start address of the + * buffer won't be used. + */ +#include <../boards/arm/nrf5340dk_nrf5340/nrf5340_shared_sram_planning_conf.dtsi> diff --git a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.yaml b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.yaml index 4e305c095d36bcd..4cd71ff3566d19b 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 000000000000000..08252b57feeff42 --- /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/arm/nordic_nrf/common/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 000000000000000..a77778de6530b04 --- /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 085eb9696a8c4cd..5b58e01fbfdb6d3 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.dts b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.dts index bc39000962b4115..58c916130571abd 100644 --- a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.dts +++ b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.dts @@ -211,3 +211,7 @@ &wdt { status = "okay"; }; + +&dma0 { + status = "okay"; +}; diff --git a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.yaml b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.yaml index 6d5233e3cd8a7d8..5716d7e6e13ee0e 100644 --- a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.yaml +++ b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.yaml @@ -15,6 +15,7 @@ supported: - watchdog - mbox - flash + - dma testing: ignore_tags: - bluetooth diff --git a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig index 3f7f1f727c6c0b9..edbe7118c643012 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/adp_xc7k_ae350/doc/index.rst b/boards/riscv/adp_xc7k_ae350/doc/index.rst index 8c6d7fc14f82d3a..c12c04cabc40d94 100644 --- a/boards/riscv/adp_xc7k_ae350/doc/index.rst +++ b/boards/riscv/adp_xc7k_ae350/doc/index.rst @@ -66,6 +66,24 @@ The ``adp_xc7k_ae350`` board configuration supports the following hardware featu +----------------+------------+----------------------+ | UART | on-chip | serial | +----------------+------------+----------------------+ +| COUNTER | on-chip | counter | ++----------------+------------+----------------------+ +| SPI | on-chip | spi | ++----------------+------------+----------------------+ +| I2C | on-chip | i2c | ++----------------+------------+----------------------+ +| EEPROM | on-chip | eeprom | ++----------------+------------+----------------------+ +| FLASH | on-chip | flash | ++----------------+------------+----------------------+ +| HWINFO | on-chip | syscon | ++----------------+------------+----------------------+ +| MAILBOX | on-chip | mbox | ++----------------+------------+----------------------+ +| DMA | on-chip | dma | ++----------------+------------+----------------------+ +| WATCHDOG | on-chip | wdt | ++----------------+------------+----------------------+ Other hardware features are not supported yet. @@ -211,6 +229,7 @@ You can build applications in the usual way. Here is an example for the :ref:`hello_world` application. .. zephyr-app-commands:: + :zephyr-app: samples/hello_world :board: adp_xc7k_ae350 :goals: build @@ -246,7 +265,7 @@ and execute it. # Check the ICEman server is running # Load the program into RAM and execute it - riscv64-zephyr-elf-gdb zephyr/zephyr.elf + riscv64-zephyr-elf-gdb build/zephyr/zephyr.elf (gdb) target remote :1111 (gdb) monitor reset halt (gdb) load @@ -260,7 +279,7 @@ and execute it. # Check the ICEman server is running # Burn the program into flash and execute it /bin/target_burn_frontend \ - -P 4444 --unlock --verify --image=zephyr/zephyr.bin \ + -P 4444 --unlock --verify --image=build/zephyr/zephyr.bin \ --algorithm-bin=/target_bin/target_SPI_v5_[32|64].bin # Note: @@ -289,7 +308,7 @@ Debugging # Check the ICEman server is running # Load and debug program - ./riscv64-zephyr-elf-gdb zephyr/zephyr.elf + ./riscv64-zephyr-elf-gdb build/zephyr/zephyr.elf (gdb) target remote :1111 (gdb) monitor reset halt (gdb) load diff --git a/boards/riscv/beaglev_fire/Kconfig.board b/boards/riscv/beaglev_fire/Kconfig.board new file mode 100644 index 000000000000000..55b59d4ac922a63 --- /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 000000000000000..df89660bcb65dc8 --- /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 000000000000000..df956f5c8f2f25a --- /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 000000000000000..64d34b454f80812 --- /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 000000000000000..eaf7d9c6f158021 --- /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 000000000000000..a4ba6b0d98e9e98 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 000000000000000..5be27ddfbb174c7 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 000000000000000..88808145c9bfc7b --- /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 3686c1e8ad3445d..922368f923be245 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/doc/index.rst b/boards/riscv/esp32c3_devkitm/doc/index.rst index 6d21b2918c39ce6..26f1521e0874fae 100644 --- a/boards/riscv/esp32c3_devkitm/doc/index.rst +++ b/boards/riscv/esp32c3_devkitm/doc/index.rst @@ -18,7 +18,7 @@ The features include the following: - 32-bit core RISC-V microcontroller with a maximum clock speed of 160 MHz - 400 KB of internal RAM - 802.11b/g/n/e/i -- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth mesh +- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth Mesh - Various peripherals: - 12-bit ADC with up to 6 channels diff --git a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts index 60cfdea523a2ed8..6c390956e4894aa 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 1a1ee456a3ddbdb..82e3a5a0c94893a 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/doc/index.rst b/boards/riscv/esp32c3_luatos_core/doc/index.rst index c943931a9e63b42..fae8e2eb178b4c2 100644 --- a/boards/riscv/esp32c3_luatos_core/doc/index.rst +++ b/boards/riscv/esp32c3_luatos_core/doc/index.rst @@ -18,7 +18,7 @@ The features include the following: - 32-bit core RISC-V microcontroller with a maximum clock speed of 160 MHz - 400 KB of internal RAM - 802.11b/g/n/e/i -- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth mesh +- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth Mesh - Various peripherals: - 12-bit ADC with up to 6 channels diff --git a/boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts b/boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts index 5a74be9984ec804..00a6983355781fd 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 160d6b14d4d9e96..8939bb4cddb0fbc 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 3cb3b024ceadad1..cea9c00b7e99e3a 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 306d3e11498fb34..857fe8adf6d38cf 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 b5b326494411715..d2f40472f244d9a 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 d37ded2bb25a1c8..8e4e8e21c1a2439 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 d4c5b99ce72690c..b0bf1edd156bb1e 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 4f691bd94354a91..b2119eecae9b594 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 4766e0ea7929eb8..f6c623e992817ec 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 15c9e60d5527c66..51d324d457d337d 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 cf6ac1c839203d9..bb303cc3aac4beb 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 c985f2d7bcafce8..56fe497dd2a3e3c 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 8b62698b61bf593..39450132d44f1eb 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 654fdc1bf2a615f..be13ed10358664a 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 000000000000000..535bb06c69cea31 --- /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 84ce94865596ffe..44157fd5b6a368e 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 998ce4c0bc3d3c7..1e5719fe2aaa109 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/Kconfig.defconfig b/boards/riscv/it82xx2_evb/Kconfig.defconfig index eb57ed1843129a2..37d6dc601c9e3af 100644 --- a/boards/riscv/it82xx2_evb/Kconfig.defconfig +++ b/boards/riscv/it82xx2_evb/Kconfig.defconfig @@ -5,4 +5,8 @@ if BOARD_IT82XX2_EVB config BOARD default "it82xx2_evb" + +config INPUT + default y if KSCAN + endif diff --git a/boards/riscv/it82xx2_evb/it82xx2_evb.dts b/boards/riscv/it82xx2_evb/it82xx2_evb.dts index fa8f3090973f5cc..1d1bb23eeb68024 100644 --- a/boards/riscv/it82xx2_evb/it82xx2_evb.dts +++ b/boards/riscv/it82xx2_evb/it82xx2_evb.dts @@ -17,7 +17,7 @@ i2c-0 = &i2c0; peci-0 = &peci0; led0 = &led0; - kscan0 = &kscan0; + kscan0 = &kscan_input; watchdog0 = &twd0; pwm-0 = &pwm0; }; @@ -30,7 +30,7 @@ zephyr,flash = &flash0; zephyr,flash-controller = &flashctrl; zephyr,code-partition = &slot0_partition; - zephyr,keyboard-scan = &kscan0; + zephyr,keyboard-scan = &kscan_input; }; leds { @@ -162,7 +162,7 @@ pinctrl-names = "default"; }; -&kscan0 { +&kbd { status = "okay"; pinctrl-0 = <&ksi0_default &ksi1_default @@ -189,6 +189,12 @@ &kso14_default &kso15_default>; pinctrl-names = "default"; + row-size = <8>; + col-size = <16>; + + kscan_input: kscan-input { + compatible = "zephyr,kscan-input"; + }; }; &peci0 { diff --git a/boards/riscv/it82xx2_evb/it82xx2_evb_defconfig b/boards/riscv/it82xx2_evb/it82xx2_evb_defconfig index f082e4a7badab60..6866e3f633b9487 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/Kconfig.defconfig b/boards/riscv/it8xxx2_evb/Kconfig.defconfig index a207bafd0cc2bb3..8c198316bed90d3 100644 --- a/boards/riscv/it8xxx2_evb/Kconfig.defconfig +++ b/boards/riscv/it8xxx2_evb/Kconfig.defconfig @@ -5,4 +5,17 @@ if BOARD_IT8XXX2_EVB config BOARD default "it8xxx2_evb" -endif + +if PM +config PM_DEVICE + default y + +choice PM_POLICY + default PM_POLICY_CUSTOM +endchoice +endif # PM + +config INPUT + default y if KSCAN + +endif # BOARD_IT8XXX2_EVB diff --git a/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts b/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts index ffac4a2ed9991cb..c111e9092aa15d9 100644 --- a/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts +++ b/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts @@ -17,7 +17,7 @@ i2c-0 = &i2c0; peci-0 = &peci0; led0 = &led0; - kscan0 = &kscan0; + kscan0 = &kscan_input; watchdog0 = &twd0; pwm-0 = &pwm0; }; @@ -30,7 +30,7 @@ zephyr,flash = &flash0; zephyr,flash-controller = &flashctrl; zephyr,code-partition = &slot0_partition; - zephyr,keyboard-scan = &kscan0; + zephyr,keyboard-scan = &kscan_input; }; leds { @@ -146,7 +146,7 @@ pinctrl-0 = <&tach0a_gpd6_default>; pinctrl-names = "default"; }; -&kscan0 { +&kbd { status = "okay"; pinctrl-0 = <&ksi0_default &ksi1_default @@ -173,6 +173,12 @@ &kso14_default &kso15_default>; pinctrl-names = "default"; + row-size = <8>; + col-size = <16>; + + kscan_input: kscan-input { + compatible = "zephyr,kscan-input"; + }; }; &peci0 { status = "okay"; diff --git a/boards/riscv/it8xxx2_evb/it8xxx2_evb.yaml b/boards/riscv/it8xxx2_evb/it8xxx2_evb.yaml index 3374ea96c32bec7..308e2c73c14ea99 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 9aa7deef842bc86..38a44d6f8f3d35c 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 @@ -19,7 +19,3 @@ CONFIG_INIT_STACKS=y CONFIG_LINKER_ORPHAN_SECTION_PLACE=y CONFIG_COMPILER_OPT="-mcmodel=medlow" CONFIG_GPIO=y -# Power Management -CONFIG_PM=y -CONFIG_PM_DEVICE=y -CONFIG_PM_POLICY_CUSTOM=y diff --git a/boards/riscv/longan_nano/doc/index.rst b/boards/riscv/longan_nano/doc/index.rst index c31abb6ec8f00c8..b62d91c3130070c 100644 --- a/boards/riscv/longan_nano/doc/index.rst +++ b/boards/riscv/longan_nano/doc/index.rst @@ -71,6 +71,9 @@ The board configuration supports the following hardware features: * - DAC - :kconfig:option:`CONFIG_DAC` - :dtcompatible:`gd,gd32-dac` + * - ADC + - :kconfig:option:`CONFIG_ADC` + - :dtcompatible:`gd,gd32-adc` Serial Port =========== diff --git a/boards/riscv/longan_nano/longan_nano-common.dtsi b/boards/riscv/longan_nano/longan_nano-common.dtsi index 71f787b2df6a4f3..6d272ddd53d4fd5 100644 --- a/boards/riscv/longan_nano/longan_nano-common.dtsi +++ b/boards/riscv/longan_nano/longan_nano-common.dtsi @@ -165,6 +165,12 @@ }; }; +&adc0 { + status = "okay"; + pinctrl-0 = <&adc0_default>; + pinctrl-names = "default"; +}; + &fwdgt { status = "okay"; }; diff --git a/boards/riscv/longan_nano/longan_nano-pinctrl.dtsi b/boards/riscv/longan_nano/longan_nano-pinctrl.dtsi index 41dd3538534be29..93d8abc02bd762e 100644 --- a/boards/riscv/longan_nano/longan_nano-pinctrl.dtsi +++ b/boards/riscv/longan_nano/longan_nano-pinctrl.dtsi @@ -37,4 +37,11 @@ , ; }; }; + + adc0_default: adc0_default { + group1 { + pinmux = ; + }; + }; + }; diff --git a/boards/riscv/longan_nano/longan_nano.dts b/boards/riscv/longan_nano/longan_nano.dts index e86c1992be1ede1..dd59e6cfe5f9708 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 976992c31736246..a36827b1bcd7496 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 51c2f9d8de311ad..9f81fad406f355d 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 8c944a10a749018..e33765680d54415 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 ef5e0226694951a..000000000000000 --- 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 297f4ce4bc75f54..e772b82d7f58cf1 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 774a553323390ac..6faaca8d590fa2f 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 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 15c38d914c777a8..000000000000000 --- 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 5c41649cb3ea37b..60df70677e1232d 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 eee37f4a8c3998b..6d85ebb2e402a5a 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 17e9b8038cec428..7dc8a74ffff1641 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/opentitan_earlgrey/Kconfig.board b/boards/riscv/opentitan_earlgrey/Kconfig.board index ec7f735b442b9db..544c02b1b2aeb5a 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 79299c3892f95bb..886e439b88ac420 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 989fa13b4531476..7c94b59455cce24 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 f50d82dcb76c247..946e679a6e81ab0 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 eef7d03e356d5a6..90f87ef6b988b80 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 2cd0b2cbecbba4d..948fa909a08548d 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 ef4d6273cfbda01..1f1c46acb10c64e 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 6f51da3c59249ae..6bfc46ac907af87 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 df0a497cbfe23e4..265d84a1ded8310 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 @@ -15,3 +14,4 @@ CONFIG_QEMU_ICOUNT=n CONFIG_IDLE_STACK_SIZE=1024 CONFIG_RISCV_PMP=y +CONFIG_TICKET_SPINLOCKS=y diff --git a/boards/riscv/riscv32_virtual/Kconfig.board b/boards/riscv/riscv32_virtual/Kconfig.board new file mode 100644 index 000000000000000..c8722acb384bb0c --- /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 000000000000000..840b10fd59443d1 --- /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 000000000000000..cc177a69ce9ee95 --- /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 000000000000000..a53384f533197f1 --- /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 000000000000000..326b97575180d48 --- /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 000000000000000..11cefb035df8e40 --- /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 000000000000000..4dcad0a7ea10404 --- /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 000000000000000..e0df808631b6ca2 --- /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 000000000000000..87e327287b61a96 --- /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/rv32m1_vega/doc/index.rst b/boards/riscv/rv32m1_vega/doc/index.rst index defd9177435420c..a2f3d107224c893 100644 --- a/boards/riscv/rv32m1_vega/doc/index.rst +++ b/boards/riscv/rv32m1_vega/doc/index.rst @@ -126,7 +126,7 @@ BLE Software Link Layer experimental support ================================================== This is an experimental feature supported on the Zephyr's RI5CY configuration, ``rv32m1_vega_ri5cy``. It uses the Software Link Layer -framework by Nordic Semi to enable the the on-SoC radio and transceiver for +framework by Nordic Semi to enable the on-SoC radio and transceiver for implementing a software defined BLE controller. By using both the controller and the host stack available in Zephyr, the following BLE samples can be used with this board: @@ -498,7 +498,7 @@ first make sure you're booting the right core. The output should look like this: - .. code-block:: none + .. code-block:: console $ ~/rv32m1-openocd -f boards/riscv/rv32m1_vega/support/openocd_rv32m1_vega_ri5cy.cfg Open On-Chip Debugger 0.10.0+dev-00431-ge1ec3c7d (2018-10-31-07:29) diff --git a/boards/riscv/rv32m1_vega/doc/ri5cy_boot.jpg b/boards/riscv/rv32m1_vega/doc/ri5cy_boot.jpg index 6483f98642f6f49..f119572c517a376 100644 Binary files a/boards/riscv/rv32m1_vega/doc/ri5cy_boot.jpg and b/boards/riscv/rv32m1_vega/doc/ri5cy_boot.jpg differ diff --git a/boards/riscv/sparkfun_red_v_things_plus/Kconfig.board b/boards/riscv/sparkfun_red_v_things_plus/Kconfig.board index 34f852dc0ecb82d..cc9e7b4f935d857 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 de3d18bcfdedf41..8cf24ffbe09f6de 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 cbd96af9cd05e44..911a8845d709e65 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 029ae49b1987f68..56353da3d8135cf 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 3b5efc64fa11f11..021a4e841623505 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 d6ed41ffc79d101..bac70816b205cb6 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 096980b864ecd09..0608a8e89537414 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 bd36cb0e481f303..971b34dc13b4026 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 fe5cfbe8c2eb3ca..c4cfdfea718e4e0 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 e67ddbcc42e166e..2852d11301d8994 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 45823b069c8b8a4..5cea1004af625ef 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/atmel_rf2xx/doc/index.rst b/boards/shields/atmel_rf2xx/doc/index.rst index dbcdccbd3e8494a..e9d2777fafe5709 100644 --- a/boards/shields/atmel_rf2xx/doc/index.rst +++ b/boards/shields/atmel_rf2xx/doc/index.rst @@ -179,7 +179,7 @@ Pins Assignment of the Arduino Shield Modules MikroBus Shields ================ -MikroBus header is available available without advanced features. It is +MikroBus header is available without advanced features. It is enabled selecting `atmel_rf2xx_mikrobus`_ variant option. Pins Assignment of the MikroBus Shield Modules 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 000000000000000..f28bf527c9a88e7 --- /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/g1120b0mipi/boards/mimxrt595_evk_cm33.overlay b/boards/shields/g1120b0mipi/boards/mimxrt595_evk_cm33.overlay new file mode 100644 index 000000000000000..7503627d99d3b95 --- /dev/null +++ b/boards/shields/g1120b0mipi/boards/mimxrt595_evk_cm33.overlay @@ -0,0 +1,15 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Change deep sleep config for suspend mode to keep SMARTDMA ram powered, + * so the SMARTDMA will continue functioning after deep sleep + */ +&suspend { + deep-sleep-config = <0xC800>, + <0x80030004>, + <0xFFFFFFFF>, + <0>; +}; diff --git a/boards/shields/g1120b0mipi/g1120b0mipi.overlay b/boards/shields/g1120b0mipi/g1120b0mipi.overlay index e456a7f31c7d4a2..7fec77ee3d71d13 100644 --- a/boards/shields/g1120b0mipi/g1120b0mipi.overlay +++ b/boards/shields/g1120b0mipi/g1120b0mipi.overlay @@ -33,7 +33,7 @@ compatible = "focaltech,ft5336"; reg = <0x38>; int-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_LOW>; - reset-gpios = <&nxp_mipi_connector 28 GPIO_ACTIVE_HIGH>; + reset-gpios = <&nxp_mipi_connector 28 GPIO_ACTIVE_LOW>; }; }; diff --git a/boards/shields/lmp90100_evb/lmp90100_evb.overlay b/boards/shields/lmp90100_evb/lmp90100_evb.overlay index 600eefdb1270303..7271c9c7c3debb9 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/m5stack_core2_ext/Kconfig.shield b/boards/shields/m5stack_core2_ext/Kconfig.shield new file mode 100644 index 000000000000000..2710087cd1e5cff --- /dev/null +++ b/boards/shields/m5stack_core2_ext/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_M5STACK_CORE2_EXT + def_bool $(shields_list_contains,m5stack_core2_ext) diff --git a/boards/shields/m5stack_core2_ext/doc/img/m5stack_core2_ext.webp b/boards/shields/m5stack_core2_ext/doc/img/m5stack_core2_ext.webp new file mode 100644 index 000000000000000..f0de7a3d5bf1055 Binary files /dev/null and b/boards/shields/m5stack_core2_ext/doc/img/m5stack_core2_ext.webp differ diff --git a/boards/shields/m5stack_core2_ext/doc/index.rst b/boards/shields/m5stack_core2_ext/doc/index.rst new file mode 100644 index 000000000000000..691ad98f4a22b7b --- /dev/null +++ b/boards/shields/m5stack_core2_ext/doc/index.rst @@ -0,0 +1,56 @@ +.. _m5stack_core2_ext: + +M5Stack-Core2 base shield +#################################### + +Overview +******** + +`M5Stack-Core2`_ comes with a base shield that is connected to the M5Stack +extension connector. It features an MPU6886 6-axis motion tracker (6DOF IMU) +and a SPM1423 microphone. + +.. figure:: img/m5stack_core2_ext.webp + :align: center + :alt: M5Stack-Core2-EXT + :width: 400 px + + M5Stack-Core2-Extension module + +.. note:: + The SPM1423 microphone functionality is not implemented yet. + +Pins Assignments +================ + ++----------------------+--------------+ +| Shield Connector Pin | Function | ++======================+==============+ +| 0 | GND | ++----------------------+--------------+ +| 11 | 3.3V | ++----------------------+--------------+ +| 16 | I2C - intSDA | ++----------------------+--------------+ +| 17 | I2C - intSCL | ++----------------------+--------------+ + +Programming +*********** + +Set ``-DSHIELD=m5stack_core2_ext`` when you invoke ``west build``. +For example: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/mpu6050 + :board: m5stack_core2 + :shield: m5stack_core2_ext + :goals: build + +References +********** + +.. target-notes:: + +.. _M5Stack-Core2: + https://docs.m5stack.com/en/core/core2 diff --git a/boards/shields/m5stack_core2_ext/m5stack_core2_ext.overlay b/boards/shields/m5stack_core2_ext/m5stack_core2_ext.overlay new file mode 100644 index 000000000000000..8403fd4da9e1290 --- /dev/null +++ b/boards/shields/m5stack_core2_ext/m5stack_core2_ext.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + accel0 = &mpu6886_m5stack_core2_ext; + }; +}; + +&m5stack_mbus_i2c0 { + status = "okay"; + + mpu6886_m5stack_core2_ext: mbus_mpu6886@68 { + status = "okay"; + compatible = "invensense,mpu6050"; + reg = <0x68>; + }; +}; diff --git a/boards/shields/mikroe_accel13_click/Kconfig.shield b/boards/shields/mikroe_accel13_click/Kconfig.shield new file mode 100644 index 000000000000000..335781b3b9bf509 --- /dev/null +++ b/boards/shields/mikroe_accel13_click/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Mark Olsson +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_MIKROE_ACCEL13_CLICK + def_bool $(shields_list_contains,mikroe_accel13_click) diff --git a/boards/shields/mikroe_accel13_click/doc/accel-13-click.jpg b/boards/shields/mikroe_accel13_click/doc/accel-13-click.jpg new file mode 100644 index 000000000000000..20c2bccb90d4936 Binary files /dev/null and b/boards/shields/mikroe_accel13_click/doc/accel-13-click.jpg differ diff --git a/boards/shields/mikroe_accel13_click/doc/index.rst b/boards/shields/mikroe_accel13_click/doc/index.rst new file mode 100644 index 000000000000000..24d6a69443a6037 --- /dev/null +++ b/boards/shields/mikroe_accel13_click/doc/index.rst @@ -0,0 +1,56 @@ +.. _mikroe_accel13_click_shield: + +MikroElektronika ACCEL 13 Click +############################### + +Overview +******** + +The MikroElektronika ACCEL 13 Click carries the `IIS2DLPC`_ ultra-low +power triaxial accelerometer sensor in a `mikroBUS`_ |trade| form factor. + +The `IIS2DLPC`_ sensor supports both SPI and I2C bus protocols. Currently +only I2C is supported for this shield. + +.. figure:: accel-13-click.jpg + :align: center + :alt: MikroElektronika ACCEL 13 Click + + MikroElektronika ACCEL 13 Click (Credit: MikroElektronika) + +Requirements +************ + +This shield can only be used with a development board that provides a +configuration for mikroBUS connectors and defines a node alias for the mikroBUS +I2C interface (see :ref:`shields` for more details). + +For more information about interfacing the IIS2DLPC and the ACCEL 13 Click, +see the following documentation: + +- `IIS2DLPC Datasheet`_ +- `ACCEL 13 Click`_ + +Programming +*********** + +Set ``-DSHIELD=mikro_accel13_click`` when you invoke ``west build``. For +example: + +.. zephyr-app-commands:: + :zephyr-app: test/boards/board_shell + :board: lpcxpresso55s69 + :shield: mikroe_accel13_click + :goals: build + +.. _IIS2DLPC: + https://www.st.com/en/mems-and-sensors/iis2dlpc.html + +.. _mikroBUS: + https://www.mikroe.com/mikrobus + +.. _IIS2DLPC Datasheet: + https://www.st.com/resource/en/datasheet/iis2dlpc.pdf + +.. _ACCEL 13 Click: + https://www.mikroe.com/accel-13-click diff --git a/boards/shields/mikroe_accel13_click/mikroe_accel13_click.overlay b/boards/shields/mikroe_accel13_click/mikroe_accel13_click.overlay new file mode 100644 index 000000000000000..e2979b384d3394a --- /dev/null +++ b/boards/shields/mikroe_accel13_click/mikroe_accel13_click.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Mark Olsson + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + accel0 = &iis2dlpc_mikroe_accel13_click; + }; +}; + +&mikrobus_i2c { + status = "okay"; + + iis2dlpc_mikroe_accel13_click: iis2dlpc@18 { + compatible = "st,iis2dlpc"; + reg = <0x18>; + drdy-gpios = <&mikrobus_header 7 GPIO_ACTIVE_HIGH>; + drdy-int = <2>; + status = "okay"; + }; +}; diff --git a/boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay b/boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay index 7238a5cfb8e601e..62f633b1a3349ac 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 41656ab2e367f50..8157863d7d48d5b 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 e5604daee7eff72..6686e9e781235e8 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/mikroe_mcp2518fd_click/doc/index.rst b/boards/shields/mikroe_mcp2518fd_click/doc/index.rst index 00bc60190f85d10..79ac2b441c34b35 100644 --- a/boards/shields/mikroe_mcp2518fd_click/doc/index.rst +++ b/boards/shields/mikroe_mcp2518fd_click/doc/index.rst @@ -1,12 +1,12 @@ .. _mikroe_mcp2518fd_click_shield: -MikroElektronika MCP2518FD Click shield (CAN-FD) -################################################ +MikroElektronika MCP2518FD Click shield +####################################### Overview -------- -MCP2518FD Click shield has a MCP2518FD CAN-FD controller via a SPI +MCP2518FD Click shield has a MCP2518FD CAN FD controller via a SPI interface and a high-speed ATA6563 CAN transceiver. More information about the shield can be found at diff --git a/boards/shields/npm1300_ek/npm1300_ek.overlay b/boards/shields/npm1300_ek/npm1300_ek.overlay index c5991f785981ab1..592aa55f1243385 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/rk055hdmipi4m/rk055hdmipi4m.overlay b/boards/shields/rk055hdmipi4m/rk055hdmipi4m.overlay index 079596b60d2a3dd..4740ee664f141bb 100644 --- a/boards/shields/rk055hdmipi4m/rk055hdmipi4m.overlay +++ b/boards/shields/rk055hdmipi4m/rk055hdmipi4m.overlay @@ -30,7 +30,7 @@ compatible = "goodix,gt911"; reg = <0x5d>; irq-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_HIGH>; - reset-gpios = <&nxp_mipi_connector 28 GPIO_ACTIVE_HIGH>; + reset-gpios = <&nxp_mipi_connector 28 GPIO_ACTIVE_LOW>; }; }; diff --git a/boards/shields/rk055hdmipi4ma0/rk055hdmipi4ma0.overlay b/boards/shields/rk055hdmipi4ma0/rk055hdmipi4ma0.overlay index 29a90ee0b737145..0f4e0c9ce45e717 100644 --- a/boards/shields/rk055hdmipi4ma0/rk055hdmipi4ma0.overlay +++ b/boards/shields/rk055hdmipi4ma0/rk055hdmipi4ma0.overlay @@ -30,7 +30,7 @@ compatible = "goodix,gt911"; reg = <0x5d>; irq-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_HIGH>; - reset-gpios = <&nxp_mipi_connector 28 GPIO_ACTIVE_HIGH>; + reset-gpios = <&nxp_mipi_connector 28 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 000000000000000..b192ce223f0e077 --- /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 a50b0ef6c53b6e5..bbaba0718b9b65e 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 407f8c6efdaa035..815b65f57501d2c 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 000000000000000..38da89750c4b919 --- /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 000000000000000..e8fe6525af1c9b6 --- /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 000000000000000..4fc35403b4675ea --- /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 000000000000000..53f1191db5a035b 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 000000000000000..381bce67c742d7a --- /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 000000000000000..88f16f95dc56e6e --- /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 000000000000000..67efc1dffa5333b --- /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 000000000000000..82304ace3452ea3 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 000000000000000..ddc9cf838193c21 --- /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 000000000000000..177ac9eb9484d3b --- /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 eb2ec1c1372ef31..430b8a860f7df83 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/doc/index.rst b/boards/shields/x_nucleo_idb05a1/doc/index.rst index c210e6ac6f1ac16..d2c6f006f774e46 100644 --- a/boards/shields/x_nucleo_idb05a1/doc/index.rst +++ b/boards/shields/x_nucleo_idb05a1/doc/index.rst @@ -85,7 +85,7 @@ build command: Alternatively, set use of this shield in the project's ``CMakeLists.txt`` file: -.. code-block:: none +.. code-block:: cmake set(SHIELD x_nucleo_idb05a1) diff --git a/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay b/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay index a6a789c53c11142..e6dff3c9c9f331e 100644 --- a/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay +++ b/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay @@ -5,14 +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 000000000000000..a7532594de08e9d --- /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 000000000000000..2b631c634c4c865 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 000000000000000..a43492bf9487f2c --- /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 000000000000000..3cda8324777d029 --- /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 000000000000000..6560816c25cec34 --- /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 000000000000000..6c259fb221b6331 --- /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/x86/acrn/Kconfig.defconfig b/boards/x86/acrn/Kconfig.defconfig index 0216875583c9206..a1a8936e38b0030 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/common/efi_boot.rst b/boards/x86/common/efi_boot.rst index bfd88d276f5e4f7..54a08386d5d3075 100644 --- a/boards/x86/common/efi_boot.rst +++ b/boards/x86/common/efi_boot.rst @@ -1,5 +1,7 @@ :orphan: +.. start_include_here + Preparing the Boot Device ------------------------- diff --git a/boards/x86/common/net_boot.rst b/boards/x86/common/net_boot.rst index 20e2de0f45b26fc..e00dea8312c02f4 100644 --- a/boards/x86/common/net_boot.rst +++ b/boards/x86/common/net_boot.rst @@ -1,5 +1,7 @@ :orphan: +.. start_include_here + Prepare Linux host ------------------ @@ -67,7 +69,7 @@ Booting the board .. note:: Use a baud rate of 115200. -#. Power on the the board. +#. Power on the board. #. Verify that the board got an IP address. Run from the Linux host: diff --git a/boards/x86/index.rst b/boards/x86/index.rst index d51c2551c4fb2d4..f7321566591af12 100644 --- a/boards/x86/index.rst +++ b/boards/x86/index.rst @@ -7,4 +7,4 @@ x86 Boards :maxdepth: 1 :glob: - **/index + [!common]*/**/* diff --git a/boards/x86/intel_adl/Kconfig.board b/boards/x86/intel_adl/Kconfig.board index 997b5a30504e590..591da3261f27f4d 100644 --- a/boards/x86/intel_adl/Kconfig.board +++ b/boards/x86/intel_adl/Kconfig.board @@ -12,3 +12,9 @@ config BOARD_INTEL_ADL_RVP depends on SOC_ALDER_LAKE select X86_64 select HAS_COVERAGE_SUPPORT + +config BOARD_UP_SQUARED_PRO_7000 + bool "UP SQUARED PRO 7000 board" + depends on SOC_ALDER_LAKE + select X86_64 + select HAS_COVERAGE_SUPPORT diff --git a/boards/x86/intel_adl/Kconfig.defconfig b/boards/x86/intel_adl/Kconfig.defconfig index 9e2255a7471a11c..6211c52503055af 100644 --- a/boards/x86/intel_adl/Kconfig.defconfig +++ b/boards/x86/intel_adl/Kconfig.defconfig @@ -1,11 +1,12 @@ # Copyright (c) 2023 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -if BOARD_INTEL_ADL_CRB || BOARD_INTEL_ADL_RVP +if BOARD_INTEL_ADL_CRB || BOARD_INTEL_ADL_RVP || BOARD_UP_SQUARED_PRO_7000 config BOARD default "intel_adl_crb" if BOARD_INTEL_ADL_CRB default "intel_adl_rvp" if BOARD_INTEL_ADL_RVP + default "up_squared_pro_7000" if BOARD_UP_SQUARED_PRO_7000 config BUILD_OUTPUT_STRIPPED default y @@ -32,10 +33,12 @@ 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 @@ -43,4 +46,16 @@ config SHELL_STACK_SIZE endif # SHELL endif # ACPI -endif # BOARD_INTEL_ADL_CRB || BOARD_INTEL_ADL_RVP +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/doc/index.rst b/boards/x86/intel_adl/doc/index.rst index f009c1c2268e2d0..63a518248b88ec7 100644 --- a/boards/x86/intel_adl/doc/index.rst +++ b/boards/x86/intel_adl/doc/index.rst @@ -60,5 +60,6 @@ Booting the Alder Lake N CRB Board using UEFI ============================================= .. include:: ../../common/efi_boot.rst + :start-after: start_include_here .. _INTEL_ADL: https://edc.intel.com/content/www/us/en/design/products/platforms/processor-and-core-i3-n-series-datasheet-volume-1-of-2/ diff --git a/boards/x86/intel_adl/doc/up_squared_pro_7000.rst b/boards/x86/intel_adl/doc/up_squared_pro_7000.rst new file mode 100644 index 000000000000000..762340e10495a83 --- /dev/null +++ b/boards/x86/intel_adl/doc/up_squared_pro_7000.rst @@ -0,0 +1,85 @@ +:orphan: + +.. _up_squared_pro_7000_board: + +UP Squared Pro 7000 +################### + +Overview +******** + +UP Squared Pro 7000 is the 3rd generation of palm-sized developer board of +UP Boards series. UP Squared Pro 7000 is powered by Intel Alder Lake N +(Intel N-series Platform). + +For more information about Intel N-series Platform please refer to +:ref:`intel_adl_n`. + +This board configuration enables kernel support for the UP Squared Pro 7000 boards. + +Hardware +******** + +General information about the board can be found at the `UP Squared Pro 7000`_ website. + +Connections and IOs +=================== + +Refer to the `UP Squared Pro 7000`_ website for more information. + +Programming and Debugging +************************* + +Use the following procedures for booting an image for an UP Squared Pro 7000 board. + +.. contents:: + :depth: 1 + :local: + :backlinks: top + +Build Zephyr application +======================== + +#. Build a Zephyr application; for instance, to build the ``hello_world`` + application for UP Squared Pro 7000 board: + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: up_squared_pro_7000 + :goals: build + + .. note:: + + A Zephyr EFI image file named :file:`zephyr.efi` is automatically + created in the build directory after the application is built. + +Connect Serial Console +====================== + +Current board configuration assumes that serial console is connected to +connector ``CN14 USB 2.0/UART 1x10P Wafer``. Refer to `User Manual`_ for +description of the connector and location on the board. + +Refer to `UP Serial Console`_ for additional information about serial +connection setup. + +Booting the UP Squared Pro 7000 Board using UEFI +================================================ + +.. include:: ../../common/efi_boot.rst + :start-after: start_include_here + +Booting the UP Squared Pro 7000 Board over network +================================================== + +.. include:: ../../common/net_boot.rst + :start-after: start_include_here + +References +********** + +.. target-notes:: + +.. _UP Squared Pro 7000: https://up-board.org/up-squared-pro-7000/ +.. _User Manual: https://downloads.up-community.org/download/up-squared-pro-7000-user-manual/ +.. _UP Serial Console: https://github.com/up-board/up-community/wiki/Serial-Console diff --git a/boards/x86/intel_adl/intel_adl_crb.dts b/boards/x86/intel_adl/intel_adl_crb.dts index 7a5f8b9d6e02017..e78b92aff4d95b0 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.yaml b/boards/x86/intel_adl/intel_adl_crb.yaml index a49e0864f920423..b393059d427de52 100644 --- a/boards/x86/intel_adl/intel_adl_crb.yaml +++ b/boards/x86/intel_adl/intel_adl_crb.yaml @@ -6,6 +6,7 @@ toolchain: - zephyr ram: 2048 supported: + - acpi - watchdog - pwm - gpio diff --git a/boards/x86/intel_adl/intel_adl_crb_defconfig b/boards/x86/intel_adl/intel_adl_crb_defconfig index c2c1a37850d44e0..5287bfcacc08a33 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.yaml b/boards/x86/intel_adl/intel_adl_rvp.yaml index ce009bfe33bad60..8a09b3fe16e5967 100644 --- a/boards/x86/intel_adl/intel_adl_rvp.yaml +++ b/boards/x86/intel_adl/intel_adl_rvp.yaml @@ -6,6 +6,7 @@ toolchain: - zephyr ram: 2048 supported: + - acpi - smp - watchdog testing: diff --git a/boards/x86/intel_adl/intel_adl_rvp_defconfig b/boards/x86/intel_adl/intel_adl_rvp_defconfig index 41260a3b233625d..0f6ed718268ef37 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.dts b/boards/x86/intel_adl/up_squared_pro_7000.dts new file mode 100644 index 000000000000000..06d6f8e23307579 --- /dev/null +++ b/boards/x86/intel_adl/up_squared_pro_7000.dts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "intel_adl.dts" + +/ { + model = "UP Squared Pro 7000 board"; + compatible = "aaeon,up_squared_pro_7000"; + + chosen { + zephyr,console = &uart1; + zephyr,shell-uart = &uart1; + }; +}; + +&uart1 { + status = "okay"; +}; diff --git a/boards/x86/intel_adl/up_squared_pro_7000.yaml b/boards/x86/intel_adl/up_squared_pro_7000.yaml new file mode 100644 index 000000000000000..e16731123090978 --- /dev/null +++ b/boards/x86/intel_adl/up_squared_pro_7000.yaml @@ -0,0 +1,17 @@ +identifier: up_squared_pro_7000 +name: UP SQUARED PRO 7000 board +type: mcu +arch: x86 +toolchain: + - zephyr +ram: 2048 +supported: + - acpi + - smp + - watchdog +testing: + timeout_multiplier: 4 + ignore_tags: + - net + - bluetooth +vendor: UP diff --git a/boards/x86/intel_adl/up_squared_pro_7000_defconfig b/boards/x86/intel_adl/up_squared_pro_7000_defconfig new file mode 100644 index 000000000000000..4c228677a70c535 --- /dev/null +++ b/boards/x86/intel_adl/up_squared_pro_7000_defconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_ALDER_LAKE=y +CONFIG_BOARD_UP_SQUARED_PRO_7000=y +CONFIG_PIC_DISABLE=y +CONFIG_LOAPIC=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_NS16550=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_ehl/Kconfig.defconfig b/boards/x86/intel_ehl/Kconfig.defconfig index d0a9aa7093bbafd..f3a5519ee9b25e0 100644 --- a/boards/x86/intel_ehl/Kconfig.defconfig +++ b/boards/x86/intel_ehl/Kconfig.defconfig @@ -19,9 +19,13 @@ config SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN default n endif -config HEAP_MEM_POOL_SIZE - default 32768 if ACPI - depends on KERNEL_MEM_POOL +config ACPI_PRT_BUS_NAME + depends on ACPI + default "_SB.PC00" + +config HEAP_MEM_POOL_ADD_SIZE_ACPI + default 2097152 + depends on ACPI # 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_ehl/doc/index.rst b/boards/x86/intel_ehl/doc/index.rst index 76661961c975418..1aa8f530155046c 100644 --- a/boards/x86/intel_ehl/doc/index.rst +++ b/boards/x86/intel_ehl/doc/index.rst @@ -56,11 +56,13 @@ Booting the Elkhart Lake CRB Board using UEFI ============================================= .. include:: ../../common/efi_boot.rst + :start-after: start_include_here Booting the Elkhart Lake CRB Board over network =============================================== .. include:: ../../common/net_boot.rst + :start-after: start_include_here .. note:: To enable PXE boot for Elkhart Lake CRB board do the following: diff --git a/boards/x86/intel_ehl/intel_ehl_crb.yaml b/boards/x86/intel_ehl/intel_ehl_crb.yaml index 4e9d07e9cafb96e..04cf5e2702eb02d 100644 --- a/boards/x86/intel_ehl/intel_ehl_crb.yaml +++ b/boards/x86/intel_ehl/intel_ehl_crb.yaml @@ -7,6 +7,7 @@ toolchain: - llvm ram: 2048 supported: + - acpi - gpio - smbus - smp diff --git a/boards/x86/intel_ish/Kconfig.defconfig b/boards/x86/intel_ish/Kconfig.defconfig index f989dfcd6ed365a..1f3d68096437a22 100644 --- a/boards/x86/intel_ish/Kconfig.defconfig +++ b/boards/x86/intel_ish/Kconfig.defconfig @@ -16,9 +16,6 @@ config TEST_EXTRA_STACK_SIZE default 1024 endif # TEST -config HPET_TIMER - default y - config SYS_CLOCK_TICKS_PER_SEC default 2048 if HPET_TIMER # HPET is 32768 HZ diff --git a/boards/x86/intel_rpl/Kconfig.board b/boards/x86/intel_rpl/Kconfig.board index f806be34a882b45..0424004d10b0fa8 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 99d9f8d08f2604f..1a71b32f84cbdb8 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 @@ -12,6 +13,7 @@ config BUILD_OUTPUT_STRIPPED config MP_MAX_NUM_CPUS default 2 +# TSC on this board is 1.9 GHz, HPET and APIC are 19.2 MHz config SYS_CLOCK_HW_CYCLES_PER_SEC default 1900000000 if APIC_TSC_DEADLINE_TIMER default 1900000000 if APIC_TIMER_TSC @@ -29,6 +31,20 @@ endif config ACPI default y +if ACPI +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 + default 320000 +endif # SHELL +endif # ACPI + if DMA config DMA_64BIT default y @@ -38,9 +54,12 @@ config DMA_DW_CHANNEL_COUNT default 2 endif +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 +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 c9db4c0fe3f6a91..7c3d7758484eca2 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 @@ -56,5 +70,6 @@ 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 000000000000000..ea07719a9b5e45e --- /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 000000000000000..2e6504dd32f776f --- /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 000000000000000..09fd65cf261599e --- /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 5301b373022d477..9a18aa57266d360 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/intel_rpl/intel_rpl_s_crb.yaml b/boards/x86/intel_rpl/intel_rpl_s_crb.yaml index ca0be3de6975238..ef51e444e580dff 100644 --- a/boards/x86/intel_rpl/intel_rpl_s_crb.yaml +++ b/boards/x86/intel_rpl/intel_rpl_s_crb.yaml @@ -6,6 +6,7 @@ toolchain: - zephyr ram: 2048 supported: + - acpi - smp - smbus - watchdog diff --git a/boards/x86/intel_rpl/intel_rpl_s_crb_defconfig b/boards/x86/intel_rpl/intel_rpl_s_crb_defconfig index 1fe227ba4a67617..1d8570bdeb74984 100644 --- a/boards/x86/intel_rpl/intel_rpl_s_crb_defconfig +++ b/boards/x86/intel_rpl/intel_rpl_s_crb_defconfig @@ -13,5 +13,3 @@ CONFIG_X2APIC=y CONFIG_SMP=y CONFIG_BUILD_OUTPUT_EFI=y CONFIG_BUILD_NO_GAP_FILL=y -CONFIG_HEAP_MEM_POOL_SIZE=64000000 -CONFIG_MAIN_STACK_SIZE=320000 diff --git a/boards/x86/qemu_x86/Kconfig.defconfig b/boards/x86/qemu_x86/Kconfig.defconfig index 4ed71964aa34b26..1e2b7af0a4d9415 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 32768 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 32768 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 934b078154e5d65..97a56a92770db80 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_64.dts b/boards/x86/qemu_x86/qemu_x86_64.dts index 83bf2c7fd0f2a7f..fc2521047735f30 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.yaml b/boards/x86/qemu_x86/qemu_x86_64.yaml index afa50057b6a82ef..b5c77de4c0e586d 100644 --- a/boards/x86/qemu_x86/qemu_x86_64.yaml +++ b/boards/x86/qemu_x86/qemu_x86_64.yaml @@ -7,6 +7,7 @@ toolchain: - xtools simulation: qemu supported: + - acpi - can - smp - smbus diff --git a/boards/x86/qemu_x86/qemu_x86_64_nokpti.dts b/boards/x86/qemu_x86/qemu_x86_64_nokpti.dts index 92522ab8a4ea1cf..8a5f2d511545855 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.ld b/boards/x86/qemu_x86/qemu_x86_tiny.ld index c53e2a7b409804f..44e8ff853583cf5 100644 --- a/boards/x86/qemu_x86/qemu_x86_tiny.ld +++ b/boards/x86/qemu_x86/qemu_x86_tiny.ld @@ -10,7 +10,7 @@ #include #include #include -#include +#include /* Bounds of physical RAM from DTS */ diff --git a/boards/x86/up_squared/Kconfig.defconfig b/boards/x86/up_squared/Kconfig.defconfig index 659ecc336ef05a0..e8eecbcc5087fd5 100644 --- a/boards/x86/up_squared/Kconfig.defconfig +++ b/boards/x86/up_squared/Kconfig.defconfig @@ -8,16 +8,9 @@ config BOARD config MP_MAX_NUM_CPUS default 2 if BOARD_UP_SQUARED -config HEAP_MEM_POOL_SIZE - default 32768 if ACPI - depends on KERNEL_MEM_POOL - config BUILD_OUTPUT_STRIPPED default y -config APIC_TSC_DEADLINE_TIMER - default y - # TSC on this board is 1.5936 GHz, HPET and APIC are 19.2 MHz config SYS_CLOCK_HW_CYCLES_PER_SEC default 1593600000 if APIC_TSC_DEADLINE_TIMER diff --git a/boards/x86/up_squared/doc/index.rst b/boards/x86/up_squared/doc/index.rst index 35dc68ac5333831..bf40fa16ba2ce69 100644 --- a/boards/x86/up_squared/doc/index.rst +++ b/boards/x86/up_squared/doc/index.rst @@ -80,7 +80,7 @@ Booting the UP Squared Board using UEFI ======================================= .. include:: ../../common/efi_boot.rst - + :start-after: start_include_here .. note:: Refer to the `UP Squared Serial Console Wiki page @@ -98,6 +98,7 @@ Booting the UP Squared Board over network ========================================= .. include:: ../../common/net_boot.rst + :start-after: start_include_here .. note:: Refer to the `UP Squared Serial Console Wiki page diff --git a/boards/x86/up_squared/up_squared.dts b/boards/x86/up_squared/up_squared.dts index 22303e0ef1684a4..e4977160db62bed 100644 --- a/boards/x86/up_squared/up_squared.dts +++ b/boards/x86/up_squared/up_squared.dts @@ -14,7 +14,7 @@ / { model = "up_squared"; - compatible = "up_board,up_squared"; + compatible = "aaeon,up_squared"; aliases { i2c-0 = &i2c0; diff --git a/boards/x86/up_squared/up_squared.yaml b/boards/x86/up_squared/up_squared.yaml index 2b27e7a7b2b2246..79e4d5e7e92a6c1 100644 --- a/boards/x86/up_squared/up_squared.yaml +++ b/boards/x86/up_squared/up_squared.yaml @@ -6,6 +6,7 @@ toolchain: - zephyr ram: 256 supported: + - acpi - smp testing: ignore_tags: diff --git a/boards/xtensa/esp32_devkitc_wroom/Kconfig.board b/boards/xtensa/esp32_devkitc_wroom/Kconfig.board index 5c3fa887b575534..a295f3bfc50edc8 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 cf2cb4403a164d1..aadb2d833f8dcff 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 b8856c7b3cb9a9e..ceeb7d38ba9c3f2 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 6fa0bf47f61d5d2..a33384c2a5ce590 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 0481a96df003124..19155f8a0d1299a 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 000000000000000..c58f39cd444bf45 --- /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 000000000000000..02f9916ef9013f3 --- /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 000000000000000..81406ae4c492182 --- /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 b345a9dff448b26..20e59ac10fea693 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 8b977af6943657e..84b365c2b77a7c3 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 e7615f1333527bf..ec59ab5c640745b 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 43218f3e81ffda5..d62fe5ccfb86098 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 7ae68f8e9de2160..df56a1dbc553c53 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 000000000000000..2b6f06263563b0a --- /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 000000000000000..03fe6a111a65f9a --- /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 000000000000000..5363f49388288cd --- /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 aed4adc50a840eb..8797780b74ea01c 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/doc/index.rst b/boards/xtensa/esp32_ethernet_kit/doc/index.rst index 5227cd3646e5b52..7159681dccdfcdf 100644 --- a/boards/xtensa/esp32_ethernet_kit/doc/index.rst +++ b/boards/xtensa/esp32_ethernet_kit/doc/index.rst @@ -581,7 +581,9 @@ You can debug an application in the usual way. Here is an example for the :ref:` Enabling Ethernet ***************** -Enable Ethernet MAC, PHY and MDIO; add these to your device tree overlay:: +Enable Ethernet MAC, PHY and MDIO; add these to your device tree overlay: + +.. code-block:: devicetree ð { status = "okay"; @@ -595,7 +597,9 @@ Enable Ethernet MAC, PHY and MDIO; add these to your device tree overlay:: status = "okay"; }; -Enable Ethernet in KConfig:: +Enable Ethernet in KConfig: + +.. code-block:: cfg CONFIG_ETH_ESP32=y CONFIG_NETWORKING=y diff --git a/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts b/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts index 3139e8beaa30aa7..50b01b88b2f58ff 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 946a59dce7fbd85..000000000000000 --- 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 928a4c06de9cf16..000000000000000 --- 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 5321727aa7db0ba..000000000000000 --- 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 7479d342fb696c8..000000000000000 --- 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 14739928f627e26..000000000000000 --- 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 94fed73bc45988f..000000000000000 --- 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 94937f824dc5eb5..2319c0061e4f3e1 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 66c8560609747bb..2ce35ee55342831 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.board b/boards/xtensa/esp32s2_lolin_mini/Kconfig.board new file mode 100644 index 000000000000000..1f567f3f42b5590 --- /dev/null +++ b/boards/xtensa/esp32s2_lolin_mini/Kconfig.board @@ -0,0 +1,12 @@ +# ESP32S2 LOLIN S2 MINI board configuration + +# Copyright (c) 2023 Google, LLC +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ESP32S2_LOLIN_MINI + bool "ESP32S2 Lolin Mini Board" + depends on SOC_SERIES_ESP32S2 + +choice SOC_PART_NUMBER + default SOC_ESP32S2_FN4R2 +endchoice diff --git a/boards/xtensa/esp32s2_lolin_mini/Kconfig.defconfig b/boards/xtensa/esp32s2_lolin_mini/Kconfig.defconfig new file mode 100644 index 000000000000000..709b0d5b53b94f7 --- /dev/null +++ b/boards/xtensa/esp32s2_lolin_mini/Kconfig.defconfig @@ -0,0 +1,16 @@ +# ESP32S2 LOLIN S2 MINI board configuration + +# Copyright (c) 2023 Google, LLC +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "esp32s2_lolin_mini" + depends on BOARD_ESP32S2_LOLIN_MINI + +config ENTROPY_GENERATOR + default y + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 32768 if WIFI + default 4096 diff --git a/boards/xtensa/esp32_net/board.cmake b/boards/xtensa/esp32s2_lolin_mini/board.cmake similarity index 100% rename from boards/xtensa/esp32_net/board.cmake rename to boards/xtensa/esp32s2_lolin_mini/board.cmake diff --git a/boards/xtensa/esp32s2_lolin_mini/doc/img/esp32_s2_lolin_mini.jpg b/boards/xtensa/esp32s2_lolin_mini/doc/img/esp32_s2_lolin_mini.jpg new file mode 100644 index 000000000000000..65ef9d11cae329b Binary files /dev/null and b/boards/xtensa/esp32s2_lolin_mini/doc/img/esp32_s2_lolin_mini.jpg differ diff --git a/boards/xtensa/esp32s2_lolin_mini/doc/index.rst b/boards/xtensa/esp32s2_lolin_mini/doc/index.rst new file mode 100644 index 000000000000000..70682657f8ab12f --- /dev/null +++ b/boards/xtensa/esp32s2_lolin_mini/doc/index.rst @@ -0,0 +1,96 @@ +.. _esp32s2_lolin_mini: + +ESP32-S2 Lolin Mini +################### + +Overview +******** + +ESP32-S2 is a highly integrated, low-power, single-core Wi-Fi Microcontroller SoC, designed to be secure and +cost-effective, with a high performance and a rich set of IO capabilities. [1]_ + +The features include the following: + +- RSA-3072-based secure boot +- AES-XTS-256-based flash encryption +- Protected private key and device secrets from software access +- Cryptographic accelerators for enhanced performance +- Protection against physical fault injection attacks +- Various peripherals: + + - 43x programmable GPIOs + - 14x configurable capacitive touch GPIOs + - USB OTG + - LCD interface + - camera interface + - SPI + - I2S + - UART + - ADC + - DAC + - LED PWM with up to 8 channels + +.. figure:: img/esp32_s2_lolin_mini.jpg + :align: center + :alt: ESP32-S2 LOLIN MINI + +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: esp32s2_lolin_mini + :goals: build + +The usual ``flash`` target will work with the ``esp32s2_lolin_mini`` board +configuration after putting the board into bootloader mode by holding the '0' +button then pressing 'RST' and releasing the 'RST' button. + +Here is an example for the :ref:`hello_world` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: esp32s2_lolin_mini + :goals: flash + +Open a serial port using e.g. screen + +.. code-block:: shell + + screen /dev/ttyUSB0 115200 + +After the board has been manually 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! esp32s2_lolin_mini + +References +********** + +.. [1] https://www.espressif.com/en/products/socs/esp32-s2 +.. _`ESP32S2 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf +.. _`ESP32S2 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf diff --git a/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini-pinctrl.dtsi b/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini-pinctrl.dtsi new file mode 100644 index 000000000000000..c6dbf79e6767177 --- /dev/null +++ b/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini-pinctrl.dtsi @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Google, LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +&pinctrl { + + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; +}; diff --git a/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts b/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts new file mode 100644 index 000000000000000..3ce00f8bdb8c223 --- /dev/null +++ b/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2023 Google, LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include "esp32s2_lolin_mini-pinctrl.dtsi" + +/ { + model = "esp32s2_lolin_mini"; + compatible = "espressif,esp32s2"; + + aliases { + sw0 = &user_button; + led0 = &user_led; + watchdog0 = &wdt0; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + leds { + compatible = "gpio-leds"; + user_led: led { + gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; + label = "LED1"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: user_button { + label = "0"; + gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = ; + }; + }; +}; + +&cpu0 { + clock-frequency = ; + cpu-power-states = <&deep_sleep &light_sleep>; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&timer0 { + status = "disabled"; +}; + +&timer1 { + status = "disabled"; +}; + +&timer2 { + status = "disabled"; +}; + +&timer3 { + status = "disabled"; +}; + +&trng0 { + status = "okay"; +}; + +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; + + 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>; + }; + }; +}; + +&wdt0 { + status = "okay"; +}; diff --git a/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.yaml b/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.yaml new file mode 100644 index 000000000000000..3764f5eddd74f79 --- /dev/null +++ b/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.yaml @@ -0,0 +1,14 @@ +identifier: esp32s2_lolin_mini +name: Lolin ESP32-S2 Mini +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - watchdog + - uart +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini_defconfig b/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini_defconfig new file mode 100644 index 000000000000000..c8c04460dbe4617 --- /dev/null +++ b/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini_defconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_ESP32S2_LOLIN_MINI=y +CONFIG_SOC_SERIES_ESP32S2=y + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y + +CONFIG_GPIO=y diff --git a/boards/xtensa/esp32s2_lolin_mini/support/openocd.cfg b/boards/xtensa/esp32s2_lolin_mini/support/openocd.cfg new file mode 100644 index 000000000000000..f75d53b0b34cd47 --- /dev/null +++ b/boards/xtensa/esp32s2_lolin_mini/support/openocd.cfg @@ -0,0 +1,4 @@ +set ESP_RTOS none + +source [find interface/ftdi/esp32s2_kaluga_v1.cfg] +source [find target/esp32s2.cfg] diff --git a/boards/xtensa/esp32s2_saola/Kconfig.defconfig b/boards/xtensa/esp32s2_saola/Kconfig.defconfig index 077b2bde4ac7676..8b160c0293591b1 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 7a5c4fb087a551d..781f4b758d67f01 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 261d7d0eb8f4af4..1e1e391bb0e22cb 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 cb102b4ee645965..54a015957211033 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 f7c75b120176e51..640304ee00fa5a4 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 160e01f4d6e9b1c..cce4cb8b82e9ad3 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 88744adac069341..35d4a9bc3fc417d 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 89bebe9018cb54d..fea76fca3b7a010 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 65efe16093d76aa..378b557eb7f4fdd 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 54ded2ac1b345cd..f5d366e0313c591 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; }; diff --git a/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig b/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig index d8e0ba31dba55af..eaf538cd28127ca 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 5fd323082a30f6f..636f1afd3543179 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 000000000000000..11856690835ccb0 --- /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 000000000000000..a590916109dc308 --- /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 000000000000000..ea79f62e2fae944 --- /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 000000000000000..3a2d17ac5cfd067 --- /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/heltec_wireless_stick_lite_v3/board.cmake b/boards/xtensa/heltec_wireless_stick_lite_v3/board.cmake new file mode 100644 index 000000000000000..2f04d1fe8861ea6 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/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/heltec_wireless_stick_lite_v3/board_init.c b/boards/xtensa/heltec_wireless_stick_lite_v3/board_init.c new file mode 100644 index 000000000000000..f36032fcfa495d1 --- /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 000000000000000..4cdb9bfdded8ab6 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 000000000000000..b24d2de9911c45b 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 000000000000000..24170d4cb1b7ff0 --- /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 000000000000000..6afc36ddec6ce24 --- /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 000000000000000..9a23a008c2f2453 --- /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 000000000000000..05c89b6d9842573 --- /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 000000000000000..a32ddde0422cdf2 --- /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 000000000000000..2f740b4a36ab1f4 --- /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 0948dfc49efab3b..e9778da4d8449f5 100644 --- a/boards/xtensa/intel_adsp_ace15_mtpm/board.cmake +++ b/boards/xtensa/intel_adsp_ace15_mtpm/board.cmake @@ -5,3 +5,5 @@ board_set_rimage_target(mtl) set(RIMAGE_SIGN_KEY "otc_private_key_3k.pem" CACHE STRING "default in ace15_mtpm/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 8d7f36e07bd2aa8..1bdb2698c12febb 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 737cdbee05bbe5b..6b0a4526fe4009a 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 000000000000000..098f377092bcecb --- /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 000000000000000..85e02264b5a85ac --- /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 000000000000000..bcf253836da160f --- /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 000000000000000..bf24ed1715081d6 --- /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 000000000000000..9fa5685bb4d42eb 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 000000000000000..dfd4797701bdd6f --- /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 000000000000000..e1ee7cb2432c6db --- /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 000000000000000..2690ae75b24644b --- /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 000000000000000..72577b2572a2e16 --- /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 000000000000000..7bb4a23e7949b16 --- /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.board b/boards/xtensa/m5stack_atoms3/Kconfig.board new file mode 100644 index 000000000000000..726e31773e223fa --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/Kconfig.board @@ -0,0 +1,12 @@ +# M5Stack AtomS3 board configuration + +# Copyright (c) 2023 Benjamin Cabé +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_M5STACK_ATOMS3 + bool "M5Stack AtomS3 Development Board" + depends on SOC_SERIES_ESP32S3 + +choice SOC_PART_NUMBER + default SOC_ESP32S3_FN8 +endchoice diff --git a/boards/xtensa/m5stack_atoms3/Kconfig.defconfig b/boards/xtensa/m5stack_atoms3/Kconfig.defconfig new file mode 100644 index 000000000000000..94f209758eb73a7 --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/Kconfig.defconfig @@ -0,0 +1,31 @@ +# M5Stack AtomS3 board configuration +# Copyright (c) 2023 Benjamin Cabé +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_M5STACK_ATOMS3 + +config BOARD + default "m5stack_atoms3" + depends on BOARD_M5STACK_ATOMS3 + +config ENTROPY_GENERATOR + default y + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 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 + +config LV_COLOR_16_SWAP + default y if LVGL + +endif # BOARD_M5STACK_ATOMS3 diff --git a/boards/xtensa/m5stack_atoms3/board.cmake b/boards/xtensa/m5stack_atoms3/board.cmake new file mode 100644 index 000000000000000..2f04d1fe8861ea6 --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/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/doc/img/m5stack_atoms3.webp b/boards/xtensa/m5stack_atoms3/doc/img/m5stack_atoms3.webp new file mode 100644 index 000000000000000..b4b964069b4159d Binary files /dev/null and b/boards/xtensa/m5stack_atoms3/doc/img/m5stack_atoms3.webp differ diff --git a/boards/xtensa/m5stack_atoms3/doc/index.rst b/boards/xtensa/m5stack_atoms3/doc/index.rst new file mode 100644 index 000000000000000..2dd229be436455c --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/doc/index.rst @@ -0,0 +1,136 @@ +.. _m5stack_atoms3: + +M5Stack AtomS3 +############## + +Overview +******** + +M5Stack AtomS3 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 +- LCD IPS TFT 0.85", 128x128 px screen (ST7789 compatible) +- 6-axis IMU MPU6886 +- Infrared emitter + + +.. figure:: img/m5stack_atoms3.webp + :align: center + :alt: M5Stack AtomS3 + + M5Stack AtomS3 + + +Supported Features +================== + +The Zephyr m5stack_atoms3 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, 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 + :goals: build + +The usual ``flash`` target will work with the ``m5stack_atoms3`` board +configuration. Here is an example for the :ref:`hello_world` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: m5stack_atoms3 + :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 + +Debugging +--------- + +M5Stack AtomS3 debugging is not supported due to pinout limitations. + +Related Documents +***************** + +- `M5Stack AtomS3 schematic `_ +- `ESP32S3 Datasheet `_ diff --git a/boards/xtensa/m5stack_atoms3/grove_connectors.dtsi b/boards/xtensa/m5stack_atoms3/grove_connectors.dtsi new file mode 100644 index 000000000000000..798c40cf2961daa --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/grove_connectors.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 Benjamin Cabé + * 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/m5stack_atoms3-pinctrl.dtsi b/boards/xtensa/m5stack_atoms3/m5stack_atoms3-pinctrl.dtsi new file mode 100644 index 000000000000000..0f59b0bc6a82520 --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/m5stack_atoms3-pinctrl.dtsi @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Benjamin Cabé + * + * 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; + }; + + }; +}; diff --git a/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts b/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts new file mode 100644 index 000000000000000..72ebd81b42fe94a --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2023 Benjamin Cabé + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "m5stack_atoms3-pinctrl.dtsi" +#include "grove_connectors.dtsi" +#include + +/ { + model = "M5Stack AtomS3"; + compatible = "m5stack,atoms3"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &usb_serial; + zephyr,shell-uart = &usb_serial; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,display = &st7789v; + }; + + aliases { + sw0 = &user_button_0; + watchdog0 = &wdt0; + accel0 = &mpu6886; + }; + + 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 = <&gpio1 9 GPIO_ACTIVE_LOW>; // G42 + zephyr,code = ; + }; + }; + + /* Regulators */ + lcd_backlight_en { + compatible = "regulator-fixed"; + regulator-name = "lcd_backlight_enable"; + enable-gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; + regulator-boot-on; + }; + +}; + +&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"; + + mpu6886: mpu6886@68 { + compatible = "invensense,mpu6050"; + reg = <0x68>; + status = "okay"; + }; +}; + +&i2c1 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; +}; + +&trng0 { + status = "okay"; +}; + +&spi2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim2_default>; + pinctrl-names = "default"; + + st7789v: st7789v@0 { + compatible = "sitronix,st7789v"; + reg = <0>; + spi-max-frequency = <27000000>; + cmd-data-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; /* G33 */ + reset-gpios = <&gpio1 2 GPIO_ACTIVE_LOW>; /* G34 */ + + width = <128>; + height = <128>; + x-offset = <2>; + y-offset = <1>; + + vcom = <0x28>; + gctrl = <0x35>; + vrhs = <0x10>; + vdvs = <0x20>; + mdac = <0x00>; + gamma = <0x01>; + colmod = <0x55>; + lcm = <0x0c>; + porch-param = [0c 0c 00 33 33]; + cmd2en-param = [5a 69 02 00]; + pwctrl1-param = [a4 a1]; + pvgam-param = [d0 00 02 07 0a 28 32 44 42 06 0e 12 14 17]; + nvgam-param = [d0 00 02 07 0a 28 31 54 47 0e 1c 17 1b 1e]; + ram-param = [00 E0]; + rgb-param = [40 02 14]; + }; + +}; + +&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/m5stack_atoms3.yaml b/boards/xtensa/m5stack_atoms3/m5stack_atoms3.yaml new file mode 100644 index 000000000000000..ed34b2f551d7d6f --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/m5stack_atoms3.yaml @@ -0,0 +1,21 @@ +identifier: m5stack_atoms3 +name: M5Stack AtomS3 +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - i2c + - spi + - watchdog + - regulator + - uart + - pinmux + - nvs + - display +testing: + ignore_tags: + - net + - bluetooth +vendor: m5stack diff --git a/boards/xtensa/m5stack_atoms3/m5stack_atoms3_defconfig b/boards/xtensa/m5stack_atoms3/m5stack_atoms3_defconfig new file mode 100644 index 000000000000000..1000271dbe584bd --- /dev/null +++ b/boards/xtensa/m5stack_atoms3/m5stack_atoms3_defconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_M5STACK_ATOMS3=y +CONFIG_SOC_SERIES_ESP32S3=y + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_GPIO=y +CONFIG_REGULATOR=y # for LCD backlight + +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y diff --git a/boards/xtensa/m5stack_atoms3_lite/Kconfig.board b/boards/xtensa/m5stack_atoms3_lite/Kconfig.board new file mode 100644 index 000000000000000..2c77718895e0e56 --- /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 000000000000000..8f982cec80b7e49 --- /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 000000000000000..3a2d17ac5cfd067 --- /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 000000000000000..2f04d1fe8861ea6 --- /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 000000000000000..c538a14dc0e6523 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 000000000000000..c51f580aa623bb2 --- /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 000000000000000..db98d8885dd6204 --- /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 000000000000000..051456e687ce209 --- /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 000000000000000..51b65cfba0cfa1a --- /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 000000000000000..82426e35fe68adc --- /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 000000000000000..18468290e06d998 --- /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 2e68d5614d0c36d..0edbda5d302897b 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 @@ -24,17 +26,11 @@ choice BT_HCI_BUS_TYPE default BT_ESP32 if BT endchoice -config MFD_INIT_PRIORITY - default 60 - config REGULATOR_AXP192_INIT_PRIORITY - default 76 - -config GPIO_AXP192_INIT_PRIORITY - default 80 + default 81 config GPIO_HOGS_INIT_PRIORITY - default 81 + default 82 config INPUT_FT5336_INTERRUPT default y if INPUT diff --git a/boards/xtensa/m5stack_core2/doc/index.rst b/boards/xtensa/m5stack_core2/doc/index.rst index 2a5c25f7deb6b6a..11fd9b9826e224c 100644 --- a/boards/xtensa/m5stack_core2/doc/index.rst +++ b/boards/xtensa/m5stack_core2/doc/index.rst @@ -50,36 +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 | -+------------------+--------------------------------------------------------------------------+ -|| 3-axis || The `MPU-6886`_ is a 6-axis MotionTracking device that combines a | -|| gyrosopce || 3-axis gyroscope and a 3-axis accelerometer. | -+------------------+--------------------------------------------------------------------------+ -|| 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 dce82fde545a710..05db025471f3b82 100644 --- a/boards/xtensa/m5stack_core2/m5stack_core2-pinctrl.dtsi +++ b/boards/xtensa/m5stack_core2/m5stack_core2-pinctrl.dtsi @@ -24,6 +24,14 @@ pinmux = ; }; + uart2_rx_gpio13: uart2_rx_gpio13 { + pinmux = ; + }; + + uart2_tx_gpio14: uart2_rx_gpio14 { + pinmux = ; + }; + uart1_tx_gpio32: uart1_tx_gpio32 { pinmux = ; }; @@ -31,8 +39,7 @@ spim3_default: spim3_default { group1 { pinmux = , - , - ; + ; }; group2 { pinmux = ; @@ -40,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 35ed29ae32f400e..c17b540ca5de419 100644 --- a/boards/xtensa/m5stack_core2/m5stack_core2.dts +++ b/boards/xtensa/m5stack_core2/m5stack_core2.dts @@ -8,12 +8,13 @@ #include #include "m5stack_core2-pinctrl.dtsi" #include "grove_connectors.dtsi" +#include "m5stack_mbus_connectors.dtsi" #include #include / { - model = "esp32"; - compatible = "espressif,esp32"; + model = "M5Stack Core2"; + compatible = "m5stack,core2"; aliases { pwr-led = &pwr_led; @@ -45,6 +46,7 @@ lvgl_pointer { compatible = "zephyr,lvgl-pointer-input"; input = <&ft5336_touch>; + swap-xy; }; }; @@ -167,8 +169,8 @@ &i2c1 { status = "disabled"; clock-frequency = ; - sda-gpios = <&gpio0 32 GPIO_OPEN_DRAIN>; - scl-gpios = <&gpio0 33 GPIO_OPEN_DRAIN>; + sda-gpios = <&gpio1 0 GPIO_OPEN_DRAIN>; + scl-gpios = <&gpio1 1 GPIO_OPEN_DRAIN>; pinctrl-0 = <&i2c1_default>; pinctrl-names = "default"; }; @@ -181,10 +183,12 @@ pinctrl-names = "default"; dma-enabled; clock-frequency = <20000000>; - cs-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; + cs-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>, + <&gpio0 4 GPIO_ACTIVE_LOW>; ili9342c: ili9342c@0 { compatible = "ilitek,ili9342c"; + status = "okay"; spi-max-frequency = <30000000>; reg = <0>; cmd-data-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; @@ -196,6 +200,18 @@ height = <240>; rotation = <0>; }; + + 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_core2/m5stack_core2.yaml b/boards/xtensa/m5stack_core2/m5stack_core2.yaml index bb929e2abc02b48..78b361e8834205f 100644 --- a/boards/xtensa/m5stack_core2/m5stack_core2.yaml +++ b/boards/xtensa/m5stack_core2/m5stack_core2.yaml @@ -14,8 +14,7 @@ supported: - pinmux - nvs testing: - default: true ignore_tags: - net - bluetooth -vendor: espressif +vendor: m5stack diff --git a/boards/xtensa/m5stack_core2/m5stack_mbus_connectors.dtsi b/boards/xtensa/m5stack_core2/m5stack_mbus_connectors.dtsi new file mode 100644 index 000000000000000..9929b8dc879ab5d --- /dev/null +++ b/boards/xtensa/m5stack_core2/m5stack_mbus_connectors.dtsi @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Martin Kiepfer + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + m5stack_mbus_header: m5stack_mbus_connector { + compatible = "m5stack,mbus-header"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = /* 0 GND */ + <1 0 &gpio1 4 0>, /* ADC0 */ + /* 2 GND */ + <3 0 &gpio1 5 0>, /* ADC1 */ + /* 4 GND */ + /* 5 RESET */ + <6 0 &gpio0 23 0>, /* MOSI */ + <7 0 &gpio0 25 0>, /* DAC0 */ + <8 0 &gpio1 7 0>, /* MISO */ + <9 0 &gpio0 26 0>, /* DAC1 */ + <10 0 &gpio0 18 0>, /* SCK */ + /* 11 3.3V */ + <12 0 &gpio0 3 0>, /* RXD0 */ + <13 0 &gpio0 1 0>, /* TXD0 */ + <14 0 &gpio0 13 0>, /* RXD1 */ + <15 0 &gpio0 14 0>, /* TXD1 */ + <16 0 &gpio0 21 0>, /* intSDA */ + <17 0 &gpio0 22 0>, /* intSCL */ + <18 0 &gpio1 0 0>, /* SDA */ + <19 0 &gpio1 1 0>, /* SCL */ + <20 0 &gpio0 27 0>, /* GPIO */ + <21 0 &gpio0 19 0>, /* GPIO */ + <22 0 &gpio0 2 0>, /* GPIO */ + <23 0 &gpio0 0 0>, /* GPIO */ + /* 24 NC */ + <25 0 &gpio1 3 0>; /* GPIO */ + /* 26 NC */ + /* 27 5V */ + /* 28 NC */ + /* 29 BAT */ + }; +}; + +m5stack_mbus_i2c0: &i2c0 {}; +m5stack_mbus_i2c1: &i2c1 {}; +m5stack_mbus_uart0: &uart1 {}; +m5stack_mbus_uart1: &uart2 {}; +m5stack_mbus_spi: &spi3 {}; diff --git a/boards/xtensa/m5stack_stamps3/Kconfig.board b/boards/xtensa/m5stack_stamps3/Kconfig.board new file mode 100644 index 000000000000000..1f22500830e8644 --- /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 000000000000000..f451db3e231c35e --- /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 000000000000000..2f04d1fe8861ea6 --- /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 000000000000000..3d24c0322e3b442 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 000000000000000..ae0d629f738abe9 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 000000000000000..75c660de8033e8e --- /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 000000000000000..c10190db129509b --- /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 000000000000000..b4087e31bd9edd6 --- /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 000000000000000..f5275cabe05ad80 --- /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 000000000000000..393b741440ac0e0 --- /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 000000000000000..34f489623bc8740 --- /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 2fdc31f400822bd..a9e732027811112 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 0254d82003d0f72..6737973adae5102 100644 --- a/boards/xtensa/m5stickc_plus/m5stickc_plus.dts +++ b/boards/xtensa/m5stickc_plus/m5stickc_plus.dts @@ -10,8 +10,8 @@ #include / { - model = "esp32"; - compatible = "espressif,esp32"; + model = "M5StickC Plus"; + compatible = "m5stack,m5stickc-plus"; aliases { led0 = &red_led; @@ -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/m5stickc_plus/m5stickc_plus.yaml b/boards/xtensa/m5stickc_plus/m5stickc_plus.yaml index dbd09151be1df54..821770c2be4410d 100644 --- a/boards/xtensa/m5stickc_plus/m5stickc_plus.yaml +++ b/boards/xtensa/m5stickc_plus/m5stickc_plus.yaml @@ -16,4 +16,4 @@ testing: ignore_tags: - net - bluetooth -vendor: espressif +vendor: m5stack diff --git a/boards/xtensa/nxp_adsp_imx8/Kconfig.board b/boards/xtensa/nxp_adsp_imx8/Kconfig.board index e24c0a453169e44..4bb4f56404043f0 100644 --- a/boards/xtensa/nxp_adsp_imx8/Kconfig.board +++ b/boards/xtensa/nxp_adsp_imx8/Kconfig.board @@ -5,3 +5,5 @@ config BOARD_NXP_ADSP_IMX8 bool "NXP ADSP i.MX8" + depends on SOC_SERIES_NXP_IMX8 + select SOC_PART_NUMBER_MIMX8QM6AVUFF diff --git a/boards/xtensa/nxp_adsp_imx8/Kconfig.defconfig b/boards/xtensa/nxp_adsp_imx8/Kconfig.defconfig index f72d1a4e11f9f17..04aa0aa6ed30e5d 100644 --- a/boards/xtensa/nxp_adsp_imx8/Kconfig.defconfig +++ b/boards/xtensa/nxp_adsp_imx8/Kconfig.defconfig @@ -7,15 +7,4 @@ if BOARD_NXP_ADSP_IMX8 config BOARD default "nxp_adsp_imx8" -config DUMMY_DMA - bool - default y - depends on DMA - -config IMX_EDMA - bool - default y - depends on DMA - - endif # BOARD_NXP_ADSP_IMX8 diff --git a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8-pinctrl.dtsi b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8-pinctrl.dtsi new file mode 100644 index 000000000000000..a6291a5d4b853fb --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8-pinctrl.dtsi @@ -0,0 +1,26 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&iomuxc { + iomuxc_uart2_rx_uart0_rts_b: IOMUXC_UART2_RX_UART0_RTS_B { + pinmux = ; + }; + + iomuxc_uart2_tx_uart0_cts_b: IOMUXC_UART2_TX_UART0_CTS_B { + pinmux = ; + }; +}; + +&pinctrl { + lpuart2_default: lpuart2_default { + group0 { + pinmux = <&iomuxc_uart2_rx_uart0_rts_b>, + <&iomuxc_uart2_tx_uart0_cts_b>; + }; + }; +}; diff --git a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.dts b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.dts index 51d3162134afbba..a17690109eca596 100644 --- a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.dts +++ b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.dts @@ -7,6 +7,7 @@ /dts-v1/; #include +#include "nxp_adsp_imx8-pinctrl.dtsi" / { model = "nxp_adsp_imx8"; @@ -14,5 +15,14 @@ chosen { zephyr,sram = &sram0; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; }; }; + +&lpuart2 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&lpuart2_default>; + pinctrl-names = "default"; +}; diff --git a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.yaml b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.yaml index 60aa04828228558..b2ab9b227a9dc94 100644 --- a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.yaml +++ b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8.yaml @@ -8,3 +8,4 @@ testing: only_tags: - kernel - sof +vendor: nxp diff --git a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig index 3d0c02d5017c7f2..a16d8be5e2e36e4 100644 --- a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig +++ b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig @@ -2,21 +2,21 @@ CONFIG_MAIN_STACK_SIZE=3072 +# board/soc-related configurations CONFIG_SOC_SERIES_NXP_IMX8=y +CONFIG_SOC_MIMX8QM_ADSP=y CONFIG_BOARD_NXP_ADSP_IMX8=y -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_XTENSA_RESET_VECTOR=y - -CONFIG_XTENSA_USE_CORE_CRT1=y - -CONFIG_XTENSA_SMALL_VECTOR_TABLE_ENTRY=y - -CONFIG_MULTI_LEVEL_INTERRUPTS=n -CONFIG_2ND_LEVEL_INTERRUPTS=n +CONFIG_LOG=y +# TODO: maybe move this to SOF? +CONFIG_DYNAMIC_INTERRUPTS=y CONFIG_BUILD_OUTPUT_BIN=n -CONFIG_DCACHE_LINE_SIZE=128 +# clock-related configurations +CONFIG_CLOCK_CONTROL=y + +# serial-related configurations +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/xtensa/nxp_adsp_imx8m/Kconfig.defconfig b/boards/xtensa/nxp_adsp_imx8m/Kconfig.defconfig index 628c8bfd0b42255..344449dd74436b6 100644 --- a/boards/xtensa/nxp_adsp_imx8m/Kconfig.defconfig +++ b/boards/xtensa/nxp_adsp_imx8m/Kconfig.defconfig @@ -1,4 +1,4 @@ -# Copyright (c) 2021 NXP +# Copyright 2021, 2023 NXP # # SPDX-License-Identifier: Apache-2.0 @@ -7,14 +7,4 @@ if BOARD_NXP_ADSP_IMX8M config BOARD default "nxp_adsp_imx8m" -config DUMMY_DMA - bool - default y - depends on DMA - -config IMX_SDMA - bool - default y - depends on DMA - endif # BOARD_NXP_ADSP_IMX8M diff --git a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.dts b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.dts index bc5b663f57d4546..6a0d7508deb2a72 100644 --- a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.dts +++ b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 NXP + * Copyright 2021, 2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,7 +22,7 @@ }; &pinctrl { - /omit-if-no-ref/ uart4_default: uart4_default { + uart4_default: uart4_default { group0 { pinmux = <&iomuxc_uart4_rxd_uart_rx_uart4_rx>, <&iomuxc_uart4_txd_uart_tx_uart4_tx>; diff --git a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.yaml b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.yaml index 675db668f136e13..ef0bbdfe0ff04ff 100644 --- a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.yaml +++ b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.yaml @@ -3,11 +3,14 @@ name: NXP i.MX8M Plus EVK Audio DSP type: mcu arch: xtensa toolchain: + - xcc + - xt-clang - zephyr -testing: - only_tags: - - kernel - - sof - - ipm supported: - uart +testing: + ignore_tags: + - net + - bluetooth + - mcumgr +vendor: nxp diff --git a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig index f3b4ca76cbe9a51..72ccd09f55a47cb 100644 --- a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig +++ b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig @@ -1,27 +1,18 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_MAIN_STACK_SIZE=3072 - CONFIG_SOC_SERIES_NXP_IMX8M=y CONFIG_SOC_MIMX8M_ADSP=y CONFIG_BOARD_NXP_ADSP_IMX8M=y -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_XTENSA_RESET_VECTOR=y - -CONFIG_XTENSA_USE_CORE_CRT1=y - -CONFIG_XTENSA_SMALL_VECTOR_TABLE_ENTRY=y +# size of stack for initialization and main thread +CONFIG_MAIN_STACK_SIZE=3072 -CONFIG_MULTI_LEVEL_INTERRUPTS=n -CONFIG_2ND_LEVEL_INTERRUPTS=n +# enable logger +CONFIG_LOG=y +# no need for a "raw" binary zephyr/zephyr.bin in the build directory CONFIG_BUILD_OUTPUT_BIN=n -CONFIG_DCACHE_LINE_SIZE=128 - # enable uart driver CONFIG_SERIAL=y diff --git a/boards/xtensa/nxp_adsp_imx8ulp/Kconfig.board b/boards/xtensa/nxp_adsp_imx8ulp/Kconfig.board new file mode 100644 index 000000000000000..d9a1ff659532860 --- /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 000000000000000..431515d5961428d --- /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 000000000000000..e05fbc891e52026 --- /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 000000000000000..d584097cb0306e6 --- /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 000000000000000..e71105631da6f9a --- /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 000000000000000..cc1911c615cfcee --- /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/nxp_adsp_imx8x/Kconfig.board b/boards/xtensa/nxp_adsp_imx8x/Kconfig.board index 7f4f7e0e3f90eb1..7d5336ce7a790ca 100644 --- a/boards/xtensa/nxp_adsp_imx8x/Kconfig.board +++ b/boards/xtensa/nxp_adsp_imx8x/Kconfig.board @@ -5,3 +5,5 @@ config BOARD_NXP_ADSP_IMX8X bool "NXP ADSP i.MX8X" + depends on SOC_SERIES_NXP_IMX8 + select SOC_PART_NUMBER_MIMX8QX6AVLFZ diff --git a/boards/xtensa/nxp_adsp_imx8x/Kconfig.defconfig b/boards/xtensa/nxp_adsp_imx8x/Kconfig.defconfig index 31d4239550396a2..a985696286afb9f 100644 --- a/boards/xtensa/nxp_adsp_imx8x/Kconfig.defconfig +++ b/boards/xtensa/nxp_adsp_imx8x/Kconfig.defconfig @@ -7,14 +7,4 @@ if BOARD_NXP_ADSP_IMX8X config BOARD default "nxp_adsp_imx8x" -config DUMMY_DMA - bool - default y - depends on DMA - -config IMX_EDMA - bool - default y - depends on DMA - endif # BOARD_NXP_ADSP_IMX8X diff --git a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x-pinctrl.dtsi b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x-pinctrl.dtsi new file mode 100644 index 000000000000000..18cfb4732573461 --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x-pinctrl.dtsi @@ -0,0 +1,26 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&iomuxc { + iomuxc_uart2_rx_uart2_rx: IOMUXC_UART2_RX_UART2_RX { + pinmux = ; + }; + + iomuxc_uart2_tx_uart2_tx: IOMUXC_UART2_TX_UART2_TX { + pinmux = ; + }; +}; + +&pinctrl { + lpuart2_default: lpuart2_default { + group0 { + pinmux = <&iomuxc_uart2_rx_uart2_rx>, + <&iomuxc_uart2_tx_uart2_tx>; + }; + }; +}; diff --git a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.dts b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.dts index bee8ccdb1a15e8a..5aa0e59ebdd0782 100644 --- a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.dts +++ b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.dts @@ -7,6 +7,7 @@ /dts-v1/; #include +#include "nxp_adsp_imx8x-pinctrl.dtsi" / { model = "nxp_adsp_imx8x"; @@ -14,5 +15,14 @@ chosen { zephyr,sram = &sram0; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; }; }; + +&lpuart2 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&lpuart2_default>; + pinctrl-names = "default"; +}; diff --git a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.yaml b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.yaml index 3277fffc7d662fd..a343b8843c8dccd 100644 --- a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.yaml +++ b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x.yaml @@ -8,3 +8,4 @@ testing: only_tags: - kernel - sof +vendor: nxp diff --git a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig index 92a66362cd03bdf..0635e78adf88f69 100644 --- a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig +++ b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig @@ -2,21 +2,21 @@ CONFIG_MAIN_STACK_SIZE=3072 +# board/soc-related configurations CONFIG_SOC_SERIES_NXP_IMX8=y +CONFIG_SOC_MIMX8QXP_ADSP=y CONFIG_BOARD_NXP_ADSP_IMX8X=y -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_XTENSA_RESET_VECTOR=y - -CONFIG_XTENSA_USE_CORE_CRT1=y - -CONFIG_XTENSA_SMALL_VECTOR_TABLE_ENTRY=y - -CONFIG_MULTI_LEVEL_INTERRUPTS=n -CONFIG_2ND_LEVEL_INTERRUPTS=n +CONFIG_LOG=y +# TODO: maybe move this to SOF? +CONFIG_DYNAMIC_INTERRUPTS=y CONFIG_BUILD_OUTPUT_BIN=n -CONFIG_DCACHE_LINE_SIZE=128 +# clock-related configurations +CONFIG_CLOCK_CONTROL=y + +# serial-related configurations +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/xtensa/nxp_adsp_rt595/Kconfig b/boards/xtensa/nxp_adsp_rt595/Kconfig new file mode 100644 index 000000000000000..3c787188a9b0172 --- /dev/null +++ b/boards/xtensa/nxp_adsp_rt595/Kconfig @@ -0,0 +1,41 @@ +# Copyright (c) 2023 Google LLC. +# SPDX-License-Identifier: Apache-2.0 + +DT_ADSP_RESET_MEM := $(dt_nodelabel_path,adsp_reset) +DT_ADSP_DATA_MEM := $(dt_nodelabel_path,adsp_data) +DT_ADSP_TEXT_MEM := $(dt_nodelabel_path,adsp_text) + +if BOARD_NXP_ADSP_RT595 + +config RT595_ADSP_STACK_SIZE + hex "Boot time stack size" + default 0x1000 + help + Stack space is reserved at the end of the RT595_ADSP_DATA_MEM + region, starting at RT595_ADSP_DATA_MEM_ADDR - RT595_ADSP_STACK_SIZE + +config RT595_ADSP_RESET_MEM_ADDR + hex + default $(dt_node_reg_addr_hex,$(DT_ADSP_RESET_MEM)) + +config RT595_ADSP_RESET_MEM_SIZE + hex + default $(dt_node_reg_size_hex,$(DT_ADSP_RESET_MEM)) + +config RT595_ADSP_DATA_MEM_ADDR + hex + default $(dt_node_reg_addr_hex,$(DT_ADSP_DATA_MEM)) + +config RT595_ADSP_DATA_MEM_SIZE + hex + default $(dt_node_reg_size_hex,$(DT_ADSP_DATA_MEM)) + +config RT595_ADSP_TEXT_MEM_ADDR + hex + default $(dt_node_reg_addr_hex,$(DT_ADSP_TEXT_MEM)) + +config RT595_ADSP_TEXT_MEM_SIZE + hex + default $(dt_node_reg_size_hex,$(DT_ADSP_TEXT_MEM)) + +endif # BOARD_NXP_ADSP_RT595 diff --git a/boards/xtensa/nxp_adsp_rt595/Kconfig.board b/boards/xtensa/nxp_adsp_rt595/Kconfig.board new file mode 100644 index 000000000000000..a88eb58638fe618 --- /dev/null +++ b/boards/xtensa/nxp_adsp_rt595/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Google LLC. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NXP_ADSP_RT595 + bool "NXP ADSP RT595" + depends on SOC_SERIES_NXP_RT5XX diff --git a/boards/xtensa/nxp_adsp_rt595/Kconfig.defconfig b/boards/xtensa/nxp_adsp_rt595/Kconfig.defconfig new file mode 100644 index 000000000000000..7ffe782d28b2885 --- /dev/null +++ b/boards/xtensa/nxp_adsp_rt595/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Google LLC. +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NXP_ADSP_RT595 + +config BOARD + default "nxp_adsp_rt595" + +endif # BOARD_NXP_ADSP_RT595 diff --git a/boards/xtensa/nxp_adsp_rt595/nxp_adsp_rt595.dts b/boards/xtensa/nxp_adsp_rt595/nxp_adsp_rt595.dts new file mode 100644 index 000000000000000..dc546c8db2451f4 --- /dev/null +++ b/boards/xtensa/nxp_adsp_rt595/nxp_adsp_rt595.dts @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 Google LLC. + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include + +/ { + model = "nxp_adsp_rt595"; + compatible = "nxp"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "cdns,tensilica-xtensa-lx6"; + reg = <0>; + }; + }; + + sram0: memory@0 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "memory"; + compatible = "mmio-sram"; + /* Reserve first 512kB of shared memory for ADSP. */ + reg = <0x0 DT_SIZE_K(512)>; + /* Reset section must always be at 0 and at least 1kB. */ + adsp_reset: memory@0 { + reg = <0x0 DT_SIZE_K(1)>; + }; + /* Code and data sections can be moved around and resized if needed. */ + adsp_text: memory@400 { + reg = <0x400 DT_SIZE_K(255)>; + }; + /* On RT595 ADSP shared RAM is mapped at offset 0 on the code bus and at + * offset 0x800000 on the data bus. + */ + adsp_data: memory@840000 { + reg = <0x840000 DT_SIZE_K(256)>; + }; + }; + + chosen { + zephyr,sram = &adsp_data; + }; +}; diff --git a/boards/xtensa/nxp_adsp_rt595/nxp_adsp_rt595.yaml b/boards/xtensa/nxp_adsp_rt595/nxp_adsp_rt595.yaml new file mode 100644 index 000000000000000..09f61405d94bab1 --- /dev/null +++ b/boards/xtensa/nxp_adsp_rt595/nxp_adsp_rt595.yaml @@ -0,0 +1,10 @@ +identifier: nxp_adsp_rt595 +name: i.MXRT595 DSP +type: mcu +arch: xtensa +toolchain: + - zephyr +testing: + only_tags: + - kernel +vendor: nxp diff --git a/boards/xtensa/nxp_adsp_rt595/nxp_adsp_rt595_defconfig b/boards/xtensa/nxp_adsp_rt595/nxp_adsp_rt595_defconfig new file mode 100644 index 000000000000000..0e80f8a41a66ec6 --- /dev/null +++ b/boards/xtensa/nxp_adsp_rt595/nxp_adsp_rt595_defconfig @@ -0,0 +1,7 @@ +CONFIG_SOC_SERIES_NXP_RT5XX=y +CONFIG_SOC_NXP_RT595=y +CONFIG_BOARD_NXP_ADSP_RT595=y + +CONFIG_GEN_ISR_TABLES=y +CONFIG_GEN_IRQ_VECTOR_TABLE=n +CONFIG_XTENSA_SMALL_VECTOR_TABLE_ENTRY=y diff --git a/boards/xtensa/odroid_go/Kconfig.defconfig b/boards/xtensa/odroid_go/Kconfig.defconfig index 7193624673e0b9b..1827d83a0411b79 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 0a868adc2a3a92f..458a8251b1c79c8 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; }; diff --git a/boards/xtensa/olimex_esp32_evb/Kconfig.defconfig b/boards/xtensa/olimex_esp32_evb/Kconfig.defconfig index 8e788f6a3938c1c..6aca00ecad505f8 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 0abf7d7128ef2be..11747f1a7b6e91a 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/qemu_xtensa/Kconfig.board b/boards/xtensa/qemu_xtensa/Kconfig.board index 8c517c88dc00aed..34cdf44a15c46b8 100644 --- a/boards/xtensa/qemu_xtensa/Kconfig.board +++ b/boards/xtensa/qemu_xtensa/Kconfig.board @@ -5,11 +5,13 @@ config BOARD_QEMU_XTENSA bool "Xtensa emulation using QEMU" - depends on SOC_XTENSA_SAMPLE_CONTROLLER + depends on SOC_XTENSA_DC233C select QEMU_TARGET + select ARCH_SUPPORTS_COREDUMP config BOARD_QEMU_XTENSA_MMU bool "Xtensa emulation using QEMU with MMU" depends on SOC_XTENSA_DC233C select QEMU_TARGET + select ARCH_SUPPORTS_COREDUMP select XTENSA_MMU diff --git a/boards/xtensa/qemu_xtensa/board.cmake b/boards/xtensa/qemu_xtensa/board.cmake index 7d6997c702cceb2..56a6c358be47ca1 100644 --- a/boards/xtensa/qemu_xtensa/board.cmake +++ b/boards/xtensa/qemu_xtensa/board.cmake @@ -2,13 +2,7 @@ set(SUPPORTED_EMU_PLATFORMS qemu) -if(CONFIG_BOARD_QEMU_XTENSA) - set(QEMU_CPU_TYPE_${ARCH} sample_controller) - - set(QEMU_FLAGS_${ARCH} - -machine sim -semihosting -nographic -cpu sample_controller - ) -elseif(CONFIG_BOARD_QEMU_XTENSA_MMU) +if(CONFIG_BOARD_QEMU_XTENSA OR CONFIG_BOARD_QEMU_XTENSA_MMU) set(QEMU_CPU_TYPE_${ARCH} dc233c) set(QEMU_FLAGS_${ARCH} diff --git a/boards/xtensa/qemu_xtensa/qemu_xtensa.dts b/boards/xtensa/qemu_xtensa/qemu_xtensa.dts index 4fa67abf2ecae81..da45a72dbc63474 100644 --- a/boards/xtensa/qemu_xtensa/qemu_xtensa.dts +++ b/boards/xtensa/qemu_xtensa/qemu_xtensa.dts @@ -1,16 +1,16 @@ /* - * Copyright (c) 2019 Intel Corporation. + * Copyright (c) 2019, 2023 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ /dts-v1/; -#include "sample_controller.dtsi" +#include "dc233c.dtsi" / { model = "qemu_xtensa"; - compatible = "cdns,xtensa-sample-controller"; + compatible = "cdns,xtensa-dc233c"; chosen { zephyr,sram = &sram0; diff --git a/boards/xtensa/qemu_xtensa/qemu_xtensa_defconfig b/boards/xtensa/qemu_xtensa/qemu_xtensa_defconfig index 08e8295cc803455..ec51bb17a3852d1 100644 --- a/boards/xtensa/qemu_xtensa/qemu_xtensa_defconfig +++ b/boards/xtensa/qemu_xtensa/qemu_xtensa_defconfig @@ -3,7 +3,7 @@ CONFIG_MAIN_STACK_SIZE=2048 CONFIG_BOARD_QEMU_XTENSA=y CONFIG_CONSOLE=y -CONFIG_SOC_XTENSA_SAMPLE_CONTROLLER=y +CONFIG_SOC_XTENSA_DC233C=y CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=10000000 CONFIG_STACK_SENTINEL=y CONFIG_GEN_ISR_TABLES=y diff --git a/boards/xtensa/xiao_esp32s3/Kconfig.defconfig b/boards/xtensa/xiao_esp32s3/Kconfig.defconfig index 4a1b168cf54a0c4..3bc3e999189ca20 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/seeed_xiao_connector.dtsi b/boards/xtensa/xiao_esp32s3/seeed_xiao_connector.dtsi index 2251ed92015a410..73fe66d28dcc9e9 100644 --- a/boards/xtensa/xiao_esp32s3/seeed_xiao_connector.dtsi +++ b/boards/xtensa/xiao_esp32s3/seeed_xiao_connector.dtsi @@ -16,8 +16,8 @@ <3 0 &gpio0 4 0>, /* D3 */ <4 0 &gpio0 5 0>, /* D4 */ <5 0 &gpio0 6 0>, /* D5 */ - <6 0 &gpio0 43 0>, /* D6 */ - <7 0 &gpio0 44 0>, /* D7 */ + <6 0 &gpio1 11 0>, /* D6 */ + <7 0 &gpio1 12 0>, /* D7 */ <8 0 &gpio0 7 0>, /* D8 */ <9 0 &gpio0 8 0>, /* D9 */ <10 0 &gpio0 9 0>; /* D10 */ diff --git a/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts index 3090f9ff5affd92..a4592b26bce2a91 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 { @@ -79,6 +80,10 @@ status = "okay"; }; +&gpio1 { + status = "okay"; +}; + &wdt0 { status = "okay"; }; diff --git a/boards/xtensa/xt-sim/xt-sim_defconfig b/boards/xtensa/xt-sim/xt-sim_defconfig index ae3d7a6cd9173bd..73700f07275d9cc 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 ebb60766eb9f540..4807671ca7917f1 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 3995788beb27a30..9442e5009e45cfd 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_bintools.cmake b/cmake/bintools/gnu/target_bintools.cmake index e8cb6e181d55aff..8aac55b0400cdcf 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 447d2adf5559b17..9489491968f7cc1 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 8eeaf2fa37a5e62..5383016795b905a 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 @@ -206,3 +209,6 @@ endif() # Remove after testing that -Wshadow works set_compiler_property(PROPERTY warning_shadow_variables) + +set_compiler_property(PROPERTY no_builtin -fno-builtin) +set_compiler_property(PROPERTY no_builtin_malloc -fno-builtin-malloc) diff --git a/cmake/compiler/arcmwdt/generic.cmake b/cmake/compiler/arcmwdt/generic.cmake index c7ab586b3f3b582..d28ad81ea04f5ac 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 7804cd0e64009e1..0f12abce24725f4 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 3658161123bed4b..e0448d0720e6a2c 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/clang/target.cmake b/cmake/compiler/clang/target.cmake index 2289856941feec9..8dd1460280b6aef 100644 --- a/cmake/compiler/clang/target.cmake +++ b/cmake/compiler/clang/target.cmake @@ -20,6 +20,7 @@ find_program(CMAKE_CXX_COMPILER clang++ ${find_program_clang_args}) if(NOT "${ARCH}" STREQUAL "posix") include(${ZEPHYR_BASE}/cmake/gcc-m-cpu.cmake) + include(${ZEPHYR_BASE}/cmake/gcc-m-fpu.cmake) if("${ARCH}" STREQUAL "arm") list(APPEND TOOLCHAIN_C_FLAGS diff --git a/cmake/compiler/compiler_flags_template.cmake b/cmake/compiler/compiler_flags_template.cmake index 1476c45e85197dd..53e37287b9fd2d9 100644 --- a/cmake/compiler/compiler_flags_template.cmake +++ b/cmake/compiler/compiler_flags_template.cmake @@ -133,3 +133,7 @@ set_compiler_property(PROPERTY no_global_merge) # Compiler flag for warning about shadow variables set_compiler_property(PROPERTY warning_shadow_variables) + +# Compiler flags to avoid recognizing built-in functions +set_compiler_property(PROPERTY no_builtin) +set_compiler_property(PROPERTY no_builtin_malloc) diff --git a/cmake/compiler/gcc/compiler_flags.cmake b/cmake/compiler/gcc/compiler_flags.cmake index b77dfa4123f0c9d..db2520771015a6e 100644 --- a/cmake/compiler/gcc/compiler_flags.cmake +++ b/cmake/compiler/gcc/compiler_flags.cmake @@ -32,6 +32,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 +172,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() @@ -227,3 +232,6 @@ set_compiler_property(PROPERTY no_position_independent set_compiler_property(PROPERTY no_global_merge "") set_compiler_property(PROPERTY warning_shadow_variables -Wshadow) + +set_compiler_property(PROPERTY no_builtin -fno-builtin) +set_compiler_property(PROPERTY no_builtin_malloc -fno-builtin-malloc) diff --git a/cmake/compiler/gcc/generic.cmake b/cmake/compiler/gcc/generic.cmake index ca96eb93809c36c..c9cc643e3ddd4c3 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 86807bd8a4f69d2..5b1e5db12180a35 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 0cfaba43da01a9e..6659c7bf417018f 100644 --- a/cmake/compiler/gcc/target_arm.cmake +++ b/cmake/compiler/gcc/target_arm.cmake @@ -34,5 +34,29 @@ if(CONFIG_FP16) list(APPEND ARM_C_FLAGS -mfp16-format=alternative) endif() endif() + +if(CONFIG_THREAD_LOCAL_STORAGE) + list(APPEND ARM_C_FLAGS -mtp=soft) +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 000000000000000..177830427dbdda2 --- /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 ca96eb93809c36c..c9cc643e3ddd4c3 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/emu/qemu.cmake b/cmake/emu/qemu.cmake index a3a8a94515b537d..6103fc1cefc15f3 100644 --- a/cmake/emu/qemu.cmake +++ b/cmake/emu/qemu.cmake @@ -399,6 +399,13 @@ set(env_qemu $ENV{QEMU_EXTRA_FLAGS}) separate_arguments(env_qemu) list(APPEND QEMU_EXTRA_FLAGS ${env_qemu}) +# Also append QEMU flags from config +if(NOT CONFIG_QEMU_EXTRA_FLAGS STREQUAL "") + set(config_qemu_flags ${CONFIG_QEMU_EXTRA_FLAGS}) + separate_arguments(config_qemu_flags) + list(APPEND QEMU_EXTRA_FLAGS "${config_qemu_flags}") +endif() + list(APPEND MORE_FLAGS_FOR_debugserver_qemu -S) if(NOT CONFIG_QEMU_GDBSERVER_LISTEN_DEV STREQUAL "") diff --git a/cmake/extra_flags.cmake b/cmake/extra_flags.cmake index 2e41720991daffd..138262afb1f5bd0 100644 --- a/cmake/extra_flags.cmake +++ b/cmake/extra_flags.cmake @@ -1,6 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 foreach(extra_flags EXTRA_CPPFLAGS EXTRA_LDFLAGS EXTRA_CFLAGS EXTRA_CXXFLAGS EXTRA_AFLAGS) + # Note: zephyr_get MERGE should not be used until issue #43959 is resolved. + zephyr_get(${extra_flags}) list(LENGTH ${extra_flags} flags_length) if(flags_length LESS_EQUAL 1) # A length of zero means no argument. diff --git a/cmake/hex.cmake b/cmake/hex.cmake index 5823dc9109beaaf..f5eb586f7bd47e1 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/target.cmake b/cmake/linker/ld/target.cmake index 507188540b7a25b..b57f89020444587 100644 --- a/cmake/linker/ld/target.cmake +++ b/cmake/linker/ld/target.cmake @@ -57,6 +57,10 @@ macro(configure_linker_script linker_script_gen linker_pass_define) zephyr_get_include_directories_for_lang(C current_includes) get_property(current_defines GLOBAL PROPERTY PROPERTY_LINKER_SCRIPT_DEFINES) + if(DEFINED SOC_LINKER_SCRIPT) + cmake_path(GET SOC_LINKER_SCRIPT PARENT_PATH soc_linker_script_includes) + set(soc_linker_script_includes -I${soc_linker_script_includes}) + endif() add_custom_command( OUTPUT ${linker_script_gen} @@ -74,6 +78,7 @@ macro(configure_linker_script linker_script_gen linker_pass_define) -D_ASMLANGUAGE -imacros ${AUTOCONF_H} ${current_includes} + ${soc_linker_script_includes} ${current_defines} ${template_script_defines} -E ${LINKER_SCRIPT} diff --git a/cmake/linker/ld/target_relocation.cmake b/cmake/linker/ld/target_relocation.cmake index c290a330484cd12..a90941d04af9fc7 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/lld/target.cmake b/cmake/linker/lld/target.cmake index 77ebf8d31213abd..f71a217e5be2085 100644 --- a/cmake/linker/lld/target.cmake +++ b/cmake/linker/lld/target.cmake @@ -110,6 +110,6 @@ endfunction(toolchain_ld_link_elf) # Load toolchain_ld-family macros include(${ZEPHYR_BASE}/cmake/linker/${LINKER}/target_base.cmake) include(${ZEPHYR_BASE}/cmake/linker/${LINKER}/target_baremetal.cmake) -include(${ZEPHYR_BASE}/cmake/linker/ld/target_cpp.cmake) +include(${ZEPHYR_BASE}/cmake/linker/${LINKER}/target_cpp.cmake) include(${ZEPHYR_BASE}/cmake/linker/ld/target_relocation.cmake) include(${ZEPHYR_BASE}/cmake/linker/ld/target_configure.cmake) diff --git a/cmake/linker/lld/target_cpp.cmake b/cmake/linker/lld/target_cpp.cmake new file mode 100644 index 000000000000000..1004c0e68653177 --- /dev/null +++ b/cmake/linker/lld/target_cpp.cmake @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +# See root CMakeLists.txt for description and expectations of these macros + +macro(toolchain_ld_cpp) + + zephyr_link_libraries( + -lc++ + ) + +endmacro() diff --git a/cmake/linker_script/arm/linker.cmake b/cmake/linker_script/arm/linker.cmake index 0c7310ab9052cdc..332d44b24359e1b 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 e6ef59eaf29eb06..7e639043bce2c3e 100644 --- a/cmake/linker_script/common/common-ram.cmake +++ b/cmake/linker_script/common/common-ram.cmake @@ -94,9 +94,6 @@ endif() if(CONFIG_ZTEST) zephyr_iterable_section(NAME ztest_suite_node GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) zephyr_iterable_section(NAME ztest_suite_stats GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -endif() - -if(CONFIG_ZTEST_NEW_API) zephyr_iterable_section(NAME ztest_unit_test GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) zephyr_iterable_section(NAME ztest_test_rule GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) zephyr_iterable_section(NAME ztest_expected_result_entry GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) @@ -111,9 +108,6 @@ if(CONFIG_UVB) zephyr_iterable_section(NAME uvb_node GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) endif() -if(CONFIG_BT_MESH_ADV_EXT) - zephyr_iterable_section(NAME bt_mesh_ext_adv GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -endif() if(CONFIG_LOG) zephyr_iterable_section(NAME log_mpsc_pbuf GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) @@ -134,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 d81b215faccd11d..d955c8ad0b67432 100644 --- a/cmake/linker_script/common/common-rom.cmake +++ b/cmake/linker_script/common/common-rom.cmake @@ -67,13 +67,13 @@ if(CONFIG_USERSPACE) # Build-time assignment of permissions to kernel objects to # threads declared with K_THREAD_DEFINE() zephyr_linker_section( - NAME z_object_assignment_area + NAME k_object_assignment_area VMA FLASH NOINPUT SUBALIGN 4 ) zephyr_linker_section_configure( - SECTION z_object_assignment - INPUT ".z_object_assignment.static.*" + SECTION k_object_assignment + INPUT ".k_object_assignment.static.*" KEEP SORT NAME ) endif() @@ -216,5 +216,14 @@ 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() + +if(CONFIG_GNSS) + zephyr_iterable_section(NAME gnss_data_callback KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +endif() + +if(CONFIG_GNSS_SATELLITES) + zephyr_iterable_section(NAME gnss_satellites_callback KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +endif() diff --git a/cmake/mcuboot.cmake b/cmake/mcuboot.cmake index 3b29069ca354242..6dd0717f5157821 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 ae9b292af0921ed..875f243b0344cf4 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) @@ -131,5 +104,23 @@ if(NOT "${Deprecated_FIND_COMPONENTS}" STREQUAL "") "${Deprecated_FIND_COMPONENTS}") endif() +if("SEARCHED_LINKER_SCRIPT" IN_LIST Deprecated_FIND_COMPONENTS) + # This code was deprecated after Zephyr v3.5.0 + list(REMOVE_ITEM Deprecated_FIND_COMPONENTS SEARCHED_LINKER_SCRIPT) + + # Try a board specific linker file + set(LINKER_SCRIPT ${BOARD_DIR}/linker.ld) + if(NOT EXISTS ${LINKER_SCRIPT}) + # If not available, try an SoC specific linker file + set(LINKER_SCRIPT ${SOC_DIR}/${ARCH}/${SOC_PATH}/linker.ld) + endif() + message(DEPRECATION + "Pre-defined `linker.ld` script is deprecated. Please set " + "BOARD_LINKER_SCRIPT or SOC_LINKER_SCRIPT to point to ${LINKER_SCRIPT} " + "or one of the Zephyr provided common linker scripts for the ${ARCH} " + "architecture." + ) +endif() + set(Deprecated_FOUND True) set(DEPRECATED_FOUND True) diff --git a/cmake/modules/FindHostTools.cmake b/cmake/modules/FindHostTools.cmake index 82225b49e565b1a..b2d5257642daa53 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 76d19e5ebbb8c1a..d4357425d10c09f 100644 --- a/cmake/modules/configuration_files.cmake +++ b/cmake/modules/configuration_files.cmake @@ -68,9 +68,6 @@ elseif(CACHED_CONF_FILE) # 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) diff --git a/cmake/modules/dts.cmake b/cmake/modules/dts.cmake index 8236195ff85b43d..23659c186924470 100644 --- a/cmake/modules/dts.cmake +++ b/cmake/modules/dts.cmake @@ -9,9 +9,6 @@ include(pre_dt) find_package(HostTools) find_package(Dtc 1.4.6) -# Zephyr code is usually configured using devicetree, but this is -# still technically optional (see e.g. CONFIG_HAS_DTS). -# # This module makes information from the devicetree available to # various build stages, as well as to other arbitrary Python scripts: # @@ -125,23 +122,15 @@ set(DTS_CMAKE ${PROJECT_BINARY_DIR}/dts.cmake) # modules. set(VENDOR_PREFIXES dts/bindings/vendor-prefixes.txt) -# -# Halt execution early if there is no devicetree. -# - -# TODO: What to do about non-posix platforms where NOT CONFIG_HAS_DTS (xtensa)? -# Drop support for NOT CONFIG_HAS_DTS perhaps? 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() - # If we don't have a devicetree after all, there's not much to do. - set(header_template ${ZEPHYR_BASE}/misc/generated/generated_header.template) - zephyr_file_copy(${header_template} ${DEVICETREE_GENERATED_H} ONLY_IF_DIFFERENT) - return() + # If we don't have a devicetree, provide an empty stub + set(DTS_SOURCE ${ZEPHYR_BASE}/boards/common/stub.dts) endif() # diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 061ed7747c1eafa..4a96b50bb20a051 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 @@ -528,6 +529,10 @@ function(zephyr_library_cc_option) endforeach() endfunction() +function(zephyr_library_add_dependencies) + add_dependencies(${ZEPHYR_CURRENT_LIBRARY} ${ARGN}) +endfunction() + # Add the existing CMake library 'library' to the global list of # Zephyr CMake libraries. This is done automatically by the # constructor but must be called explicitly on CMake libraries that do @@ -769,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() @@ -1154,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. @@ -1165,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. @@ -1179,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 = .; @@ -1215,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") @@ -1232,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} "") @@ -1257,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") @@ -1291,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}) @@ -1326,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}" @@ -1388,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: @@ -1555,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 ######################################################## @@ -1819,6 +1932,12 @@ function(zephyr_linker_sources_ifdef feature_toggle) endif() endfunction() +function(zephyr_library_add_dependencies_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_library_add_dependencies(${ARGN}) + endif() +endfunction() + macro(list_append_ifdef feature_toggle list) if(${${feature_toggle}}) list(APPEND ${list} ${ARGN}) @@ -1965,6 +2084,12 @@ function(zephyr_linker_sources_ifndef feature_toggle) endif() endfunction() +function(zephyr_library_add_dependencies_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_library_add_dependencies(${ARGN}) + endif() +endfunction() + macro(list_append_ifndef feature_toggle list) if(NOT ${feature_toggle}) list(APPEND ${list} ${ARGN}) @@ -4770,3 +4895,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 aac3b39a6f9bef4..9b18e1794de0330 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/python.cmake b/cmake/modules/python.cmake index 78a29959b8b5926..6fc765f8f58f8de 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 77abc4d603bc623..ec172512b685c62 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/unittest.cmake b/cmake/modules/unittest.cmake index be5fa56741a45b4..8853f5a5b0cb6fa 100644 --- a/cmake/modules/unittest.cmake +++ b/cmake/modules/unittest.cmake @@ -6,6 +6,9 @@ include(root) include(boards) include(arch) include(configuration_files) + +include(west) +include(zephyr_module) include(kconfig) find_package(TargetTools) @@ -103,19 +106,12 @@ if(LIBS) message(FATAL_ERROR "This variable is not supported, see SOURCES instead") endif() -if(CONFIG_ZTEST_NEW_API) - target_sources(testbinary PRIVATE - ${ZEPHYR_BASE}/subsys/testsuite/ztest/src/ztest_new.c - ${ZEPHYR_BASE}/subsys/testsuite/ztest/src/ztest_mock.c - ${ZEPHYR_BASE}/subsys/testsuite/ztest/src/ztest_rules.c - ${ZEPHYR_BASE}/subsys/testsuite/ztest/src/ztest_defaults.c - ) -else() - target_sources(testbinary PRIVATE - ${ZEPHYR_BASE}/subsys/testsuite/ztest/src/ztest.c - ${ZEPHYR_BASE}/subsys/testsuite/ztest/src/ztest_mock.c - ) -endif() +target_sources(testbinary PRIVATE + ${ZEPHYR_BASE}/subsys/testsuite/ztest/src/ztest.c + ${ZEPHYR_BASE}/subsys/testsuite/ztest/src/ztest_mock.c + ${ZEPHYR_BASE}/subsys/testsuite/ztest/src/ztest_rules.c + ${ZEPHYR_BASE}/subsys/testsuite/ztest/src/ztest_defaults.c +) target_compile_definitions(test_interface INTERFACE ZTEST_UNITTEST) diff --git a/cmake/modules/version.cmake b/cmake/modules/version.cmake index 49d172871e7faec..34f2cf99d688e4c 100644 --- a/cmake/modules/version.cmake +++ b/cmake/modules/version.cmake @@ -33,8 +33,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) @@ -74,8 +72,8 @@ 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}") diff --git a/cmake/modules/zephyr_module.cmake b/cmake/modules/zephyr_module.cmake index 90afc1f02e5b1de..191c71c193b2c5c 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/gcc/sca.cmake b/cmake/sca/gcc/sca.cmake new file mode 100644 index 000000000000000..c106933c10155be --- /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/sparse.template b/cmake/sca/sparse/sparse.template index 8fde837aa26c5fe..b54d3e9ed14c103 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 35d2a01555a4a64..7d6f7eddf162e51 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/toolchain/llvm/target.cmake b/cmake/toolchain/llvm/target.cmake index 380972291254da0..5c06af5f25fa7c4 100644 --- a/cmake/toolchain/llvm/target.cmake +++ b/cmake/toolchain/llvm/target.cmake @@ -16,7 +16,7 @@ if("${ARCH}" STREQUAL "arm") elseif(DEFINED CONFIG_ARMV7_M_ARMV8_M_MAINLINE) # ARMV7_M_ARMV8_M_MAINLINE means that ARMv7-M or backward compatible ARMv8-M # processor is used. - set(triple armv7m-cros-eabi) + set(triple armv7m-none-eabi) elseif(DEFINED CONFIG_ARMV6_M_ARMV8_M_BASELINE) # ARMV6_M_ARMV8_M_BASELINE means that ARMv6-M or ARMv8-M supporting the # Baseline implementation processor is used. diff --git a/cmake/usage/usage.cmake b/cmake/usage/usage.cmake index 9472f2fa9bb0c5a..2f4b0b76ddd3b2e 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 ae72bf7ec6e0d77..4b4d92d49238d56 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 b988b6f05eda2bb..7114a0304353f51 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 526761db69ae1bf..853f6d6926e258a 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 8414dcbf65128d8..05ecbfe94c11d6c 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 9d24d69b7bef94b..efa3357e5943116 100644 --- a/doc/_doxygen/footer.html +++ b/doc/_doxygen/footer.html @@ -13,19 +13,5 @@ $generatedby doxygen $doxygenversion - diff --git a/doc/_doxygen/groups.dox b/doc/_doxygen/groups.dox index dbb67e7e69454bf..65b229a0ce96417 100644 --- a/doc/_doxygen/groups.dox +++ b/doc/_doxygen/groups.dox @@ -1,5 +1,11 @@ /** +@defgroup internal_api Internal and System API +@brief Internal and System API +@{ + +@} + @defgroup os_services Operating System Services @brief Operating System Services @{ @@ -60,4 +66,9 @@ @{ @} +@brief Modem APIs +@defgroup modem Modem APIs +@{ +@} + */ diff --git a/doc/_doxygen/header.html b/doc/_doxygen/header.html index 4422349d76682db..06be6c6529df9a4 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 9369fb7becf1c6b..5e012b43aa2b3ea 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 @@ -92,6 +96,9 @@ class ZephyrAppCommandsDirective(Directive): \:west-args: if set, additional arguments to the west invocation (ignored for CMake) + \:flash-args: + if set, additional arguments to the flash invocation + ''' has_content = False required_arguments = 0 @@ -110,10 +117,12 @@ 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, 'west-args': directives.unchanged, + 'flash-args': directives.unchanged, } TOOLS = ['cmake', 'west', 'all'] @@ -139,10 +148,12 @@ 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 west_args = self.options.get('west-args', None) + flash_args = self.options.get('flash-args', None) if tool not in self.TOOLS: raise self.error('Unknown tool {}; choose from: {}'.format( @@ -151,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)) @@ -190,11 +207,13 @@ 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, 'generator': generator, - 'west_args': west_args + 'west_args': west_args, + 'flash_args': flash_args, } if 'west' in tools: @@ -229,7 +248,7 @@ def _lit_block(self, content): # Create the nodes. literal = nodes.literal_block(content, content) self.add_name(literal) - literal['language'] = 'console' + literal['language'] = 'shell' return literal @@ -242,18 +261,29 @@ 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'] kwargs['board'] = None # west always defaults to ninja gen_arg = ' -G\'Unix Makefiles\'' if generator == 'make' else '' cmake_args = gen_arg + self._cmake_args(**kwargs) cmake_args = ' --{}'.format(cmake_args) if cmake_args != '' else '' west_args = ' {}'.format(west_args) if west_args else '' + flash_args = ' {}'.format(flash_args) if flash_args else '' # 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) @@ -272,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 @@ -284,7 +314,7 @@ def _generate_west(self, **kwargs): if goal in {'build', 'sign'}: continue elif goal == 'flash': - content.append('west flash{}'.format(dst)) + content.append('west flash{}{}'.format(flash_args, dst)) elif goal == 'debug': content.append('west debug{}'.format(dst)) elif goal == 'debugserver': @@ -407,7 +437,7 @@ def _generate_cmake(self, **kwargs): cmake_args, source_dir)) if not compact: content.extend(['', - '# Now run ninja on the generated build system:']) + '# Now run the build tool on the generated build system:']) if 'build' in goals: content.append('{}{}{}'.format(generator, tool_build_dir, diff --git a/doc/_extensions/zephyr/domain.py b/doc/_extensions/zephyr/domain.py index 46451e1f682369d..66327f9c7adcdc0 100644 --- a/doc/_extensions/zephyr/domain.py +++ b/doc/_extensions/zephyr/domain.py @@ -59,6 +59,9 @@ from sphinx.transforms.post_transforms import SphinxPostTransform from sphinx.util import logging from sphinx.util.nodes import NodeMatcher, make_refnode +from zephyr.gh_utils import gh_link_get_url + +import json __version__ = "0.1.0" @@ -98,9 +101,6 @@ def convert_node(self, node): new_section = nodes.section(ids=[node["id"]]) new_section += nodes.title(text=node["name"]) - # Move existing content from the custom node to the new section - new_section.extend(node.children) - # Move the sibling nodes under the new section new_section.extend(siblings_to_move) @@ -111,6 +111,30 @@ def convert_node(self, node): for sibling in siblings_to_move: parent.remove(sibling) + # Set sample description as the meta description of the document for improved SEO + meta_description = nodes.meta() + meta_description["name"] = "description" + meta_description["content"] = node.children[0].astext() + node.document += meta_description + + # Similarly, add a node with JSON-LD markup (only renders in HTML output) describing + # the code sample. + json_ld = nodes.raw( + "", + f"""""", + format="html", + ) + node.document += json_ld + class ProcessRelatedCodeSamplesNode(SphinxPostTransform): default_priority = 5 # before ReferencesResolver @@ -130,12 +154,15 @@ def run(self, **kwargs: Any) -> None: if len(code_samples) > 0: admonition = nodes.admonition() admonition += nodes.title(text="Related code samples") - admonition["collapsible"] = "" # used by sphinx-immaterial theme admonition["classes"].append("related-code-samples") admonition["classes"].append("dropdown") # used by sphinx-togglebutton extension - sample_ul = nodes.bullet_list() + admonition["classes"].append("toggle-shown") # show the content by default + + sample_dl = nodes.definition_list() + for code_sample in sorted(code_samples, key=lambda x: x["name"]): - sample_para = nodes.paragraph() + term = nodes.term() + sample_xref = addnodes.pending_xref( "", refdomain="zephyr", @@ -144,13 +171,14 @@ def run(self, **kwargs: Any) -> None: refwarn=True, ) sample_xref += nodes.inline(text=code_sample["name"]) - sample_para += sample_xref - sample_para += nodes.inline(text=" - ") - sample_para += nodes.inline(text=code_sample["description"].astext()) - sample_li = nodes.list_item() - sample_li += sample_para - sample_ul += sample_li - admonition += sample_ul + term += sample_xref + definition = nodes.definition() + definition += nodes.paragraph(text=code_sample["description"].astext()) + sample_dli = nodes.definition_list_item() + sample_dli += term + sample_dli += definition + sample_dl += sample_dli + admonition += sample_dl # replace node with the newly created admonition node.replace_self(admonition) @@ -203,6 +231,7 @@ def run(self): code_sample_node = CodeSampleNode() code_sample_node["id"] = code_sample_id code_sample_node["name"] = name + code_sample_node += description_node return [code_sample_node] @@ -220,7 +249,7 @@ class ZephyrDomain(Domain): directives = {"code-sample": CodeSampleDirective} object_types: Dict[str, ObjType] = { - "code-sample": ObjType("code sample", "code-sample"), + "code-sample": ObjType("code-sample", "code-sample"), } initial_data: Dict[str, Any] = {"code-samples": {}} @@ -238,9 +267,9 @@ def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: def get_objects(self): for _, code_sample in self.data["code-samples"].items(): yield ( + code_sample["id"], code_sample["name"], - code_sample["name"], - "code sample", + "code-sample", code_sample["docname"], code_sample["id"], 1, @@ -279,10 +308,16 @@ class CustomDoxygenGroupDirective(DoxygenGroupDirective): def run(self) -> List[Node]: nodes = super().run() - return [RelatedCodeSamplesNode(id=self.arguments[0]), *nodes] + + 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_breathe_insert_related_samples", False, "env") + app.add_domain(ZephyrDomain) app.add_transform(ConvertCodeSampleNode) diff --git a/doc/_extensions/zephyr/gh_utils.py b/doc/_extensions/zephyr/gh_utils.py new file mode 100644 index 000000000000000..f2795e8849667ba --- /dev/null +++ b/doc/_extensions/zephyr/gh_utils.py @@ -0,0 +1,256 @@ +""" +Git/GitHub utilities for Sphinx +############################### + +Copyright (c) 2021 Nordic Semiconductor ASA +Copyright (c) 2023 The Linux Foundation + +SPDX-License-Identifier: Apache-2.0 + +Introduction +============ + +This Sphinx extension can be used to obtain various Git and GitHub related metadata for a page. +This is useful, for example, when adding features like "Open on GitHub" on top +of pages, direct links to open a GitHub issue regarding a page, or date of the most recent commit +to a page. + +The extension installs the following Jinja filter: + +* ``gh_link_get_blob_url``: Returns a URL to the source of a page on GitHub. +* ``gh_link_get_edit_url``: Returns a URL to edit the given page on GitHub. +* ``gh_link_get_open_issue_url``: Returns a URL to open a new issue regarding the given page. +* ``git_info``: Returns the date and SHA1 of the last commit made to a page (if this page is + managed by Git). + +Configuration options +===================== + +- ``gh_link_version``: GitHub version to use in the URL (e.g. "main") +- ``gh_link_base_url``: Base URL used as a prefix for generated URLs. +- ``gh_link_prefixes``: Mapping of pages (regex) <> GitHub prefix. +- ``gh_link_exclude``: List of pages (regex) that will not report a URL. Useful + for, e.g., auto-generated pages not in Git. +""" + +from functools import partial +import os +import re +import subprocess +import sys +from datetime import datetime +from pathlib import Path +from textwrap import dedent +from typing import Final, Optional, Tuple +from urllib.parse import quote + +from sphinx.application import Sphinx +from sphinx.util.i18n import format_date + +ZEPHYR_BASE : Final[str] = Path(__file__).parents[3] +SCRIPTS : Final[str] = ZEPHYR_BASE / "scripts" +sys.path.insert(0, str(SCRIPTS)) + +from get_maintainer import Maintainers + +MAINTAINERS : Final[Maintainers] = Maintainers(filename=f"{ZEPHYR_BASE}/MAINTAINERS.yml") + + +__version__ = "0.1.0" + + +def get_page_prefix(app: Sphinx, pagename: str) -> str: + """Return the prefix that needs to be added to the page path to get its location in the + repository. + + If pagename refers to a page that is automatically generated by Sphinx or if it matches one of + the patterns in ``gh_link_exclude`` configuration option, return None. + + Args: + app: Sphinx instance. + pagename: Page name (path). + + Returns: + Prefix if applicable, None otherwise. + """ + + if not os.path.isfile(app.env.doc2path(pagename)): + return None + + for exclude in app.config.gh_link_exclude: + if re.match(exclude, pagename): + return None + + found_prefix = "" + for pattern, prefix in app.config.gh_link_prefixes.items(): + if re.match(pattern, pagename): + found_prefix = prefix + break + + return found_prefix + + +def gh_link_get_url(app: Sphinx, pagename: str, mode: str = "blob") -> Optional[str]: + """Obtain GitHub URL for the given page. + + Args: + app: Sphinx instance. + mode: Typically "edit", or "blob". + pagename: Page name (path). + + Returns: + GitHub URL if applicable, None otherwise. + """ + + page_prefix = get_page_prefix(app, pagename) + if page_prefix is None: + return None + + return "/".join( + [ + app.config.gh_link_base_url, + mode, + app.config.gh_link_version, + page_prefix, + app.env.doc2path(pagename, False), + ] + ) + + +def gh_link_get_open_issue_url(app: Sphinx, pagename: str, sha1: str) -> Optional[str]: + """Link to open a new Github issue regarding "pagename" with title, body, and + labels already pre-filled with useful information. + + Args: + app: Sphinx instance. + pagename: Page name (path). + + Returns: + URL to open a new issue if applicable, None otherwise. + """ + + page_prefix = get_page_prefix(app, pagename) + if page_prefix is None: + return None + + rel_path = os.path.join( + os.path.relpath(ZEPHYR_BASE), + page_prefix, + app.env.doc2path(pagename, False), + ) + + title = quote(f"doc: Documentation issue in '{pagename}'") + labels = quote("area: Documentation") + areas = MAINTAINERS.path2areas(rel_path) + if areas: + labels += "," + ",".join([label for area in areas for label in area.labels]) + body = quote( + dedent( + f"""\ + **Describe the bug** + + << Please describe the issue here >> + << You may also want to update the automatically generated issue title above. >> + + **Environment** + + * Page: `{pagename}` + * Version: {app.config.gh_link_version} + * SHA-1: {sha1} + """ + ) + ) + + return f"{app.config.gh_link_base_url}/issues/new?title={title}&labels={labels}&body={body}" + + +def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]: + """Return a tuple with the date and SHA1 of the last commit made to a page. + + Arguments: + app {Sphinx} -- Sphinx application object + pagename {str} -- Page name + + 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 (generated file, or manually authored file not + yet tracked by git). + """ + + page_prefix = get_page_prefix(app, pagename) + if page_prefix is None: + return None + + orig_path = os.path.join( + ZEPHYR_BASE, + page_prefix, + 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( + [ + "git", + "log", + "-1", + "--format=%ad %H", + "--date=unix", + orig_path, + ], + stderr=subprocess.STDOUT, + ) + .decode("utf-8") + .strip() + ) + date, sha1 = date_and_sha1.split(" ", 1) + date_object = datetime.fromtimestamp(int(date)) + last_update_fmt = app.config.html_last_updated_fmt + if last_update_fmt is not None: + date = format_date(last_update_fmt, date=date_object, language=app.config.language) + + return (date, sha1) + except subprocess.CalledProcessError: + return None + +def add_jinja_filter(app: Sphinx): + if app.builder.format != "html": + return + + app.builder.templates.environment.filters["gh_link_get_blob_url"] = partial( + gh_link_get_url, app, mode="blob" + ) + + app.builder.templates.environment.filters["gh_link_get_edit_url"] = partial( + gh_link_get_url, app, mode="edit" + ) + + app.builder.templates.environment.filters["gh_link_get_open_issue_url"] = partial( + gh_link_get_open_issue_url, app + ) + + app.builder.templates.environment.filters["git_info"] = partial(git_info_filter, app) + + +def setup(app: Sphinx): + app.add_config_value("gh_link_version", "", "") + app.add_config_value("gh_link_base_url", "", "") + app.add_config_value("gh_link_prefixes", {}, "") + app.add_config_value("gh_link_exclude", [], "") + + app.connect("builder-inited", add_jinja_filter) + + return { + "version": __version__, + "parallel_read_safe": True, + "parallel_write_safe": True, + } diff --git a/doc/_extensions/zephyr/kconfig/static/kconfig.mjs b/doc/_extensions/zephyr/kconfig/static/kconfig.mjs index ae27532ab6a8ef1..6c94845a1079e31 100644 --- a/doc/_extensions/zephyr/kconfig/static/kconfig.mjs +++ b/doc/_extensions/zephyr/kconfig/static/kconfig.mjs @@ -491,7 +491,7 @@ function setupKconfigSearch() { doSearchFromURL(); /* install event listeners */ - input.addEventListener('keyup', () => { + input.addEventListener('input', () => { searchOffset = 0; doSearch(); }); diff --git a/doc/_extensions/zephyr/vcs_link.py b/doc/_extensions/zephyr/vcs_link.py deleted file mode 100644 index 23aedb5ef332cf4..000000000000000 --- a/doc/_extensions/zephyr/vcs_link.py +++ /dev/null @@ -1,89 +0,0 @@ -""" -VCS Link -######## - -Copyright (c) 2021 Nordic Semiconductor ASA -SPDX-License-Identifier: Apache-2.0 - -Introduction -============ - -This Sphinx extension can be used to obtain the VCS URL for a given Sphinx page. -This is useful, for example, when adding features like "Open on GitHub" on top -of pages. The extension installs a Jinja filter which can be used on the -template to obtain VCS page URLs. - -Configuration options -===================== - -- ``vcs_link_base_url``: Base URL used as a prefix for generated URLs. -- ``vcs_link_prefixes``: Mapping of pages (regex) <> VCS prefix. -- ``vcs_link_exclude``: List of pages (regex) that will not report a URL. Useful - for, e.g., auto-generated pages not in VCS. -""" - -from functools import partial -import os -import re -from typing import Optional - -from sphinx.application import Sphinx - - -__version__ = "0.1.0" - - -def vcs_link_get_url(app: Sphinx, pagename: str) -> Optional[str]: - """Obtain VCS URL for the given page. - - Args: - app: Sphinx instance. - pagename: Page name (path). - - Returns: - VCS URL if applicable, None otherwise. - """ - - if not os.path.isfile(app.env.project.doc2path(pagename)): - return None - - for exclude in app.config.vcs_link_exclude: - if re.match(exclude, pagename): - return None - - found_prefix = "" - for pattern, prefix in app.config.vcs_link_prefixes.items(): - if re.match(pattern, pagename): - found_prefix = prefix - break - - return "/".join( - [ - app.config.vcs_link_base_url, - found_prefix, - app.env.project.doc2path(pagename, basedir=False), - ] - ) - - -def add_jinja_filter(app: Sphinx): - if app.builder.name != "html": - return - - app.builder.templates.environment.filters["vcs_link_get_url"] = partial( - vcs_link_get_url, app - ) - - -def setup(app: Sphinx): - app.add_config_value("vcs_link_base_url", "", "") - app.add_config_value("vcs_link_prefixes", {}, "") - app.add_config_value("vcs_link_exclude", [], "") - - app.connect("builder-inited", add_jinja_filter) - - return { - "version": __version__, - "parallel_read_safe": True, - "parallel_write_safe": True, - } diff --git a/doc/_scripts/redirects.py b/doc/_scripts/redirects.py index 8c9120e9899a612..b1d199a0d2f7043 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'), @@ -163,5 +171,8 @@ ('reference/usermode/overview', 'kernel/usermode/overview'), ('reference/usermode/syscalls', 'kernel/usermode/syscalls'), ('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 711edd9936f0b61..a374fda4d37fe89 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 { @@ -306,6 +207,12 @@ a.icon-home:visited { white-space: normal; } +/* Allow to control wrapping behavior per table */ +.wy-table-responsive table.wrap-normal td, +.wy-table-responsive table.wrap-normal th { + white-space: normal; +} + /* Make sure not to wrap keyboard shortcuts */ .wy-table-responsive table td kbd { white-space: nowrap; @@ -576,6 +483,14 @@ kbd, .kbd, vertical-align: middle; } +/* guilabel and menuselection tweaks */ +.rst-content .guilabel, +.rst-content .menuselection { + color: var(--body-color); + background-color: var(--guiitems-background-color); + border-color: var(--guiitems-border-color); +} + /* Buttons */ .btn-neutral { @@ -637,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 */ @@ -648,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; } @@ -974,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/dark.css b/doc/_static/css/dark.css index a577bd69d358e96..47d555242f6a87a 100644 --- a/doc/_static/css/dark.css +++ b/doc/_static/css/dark.css @@ -87,6 +87,9 @@ --kbd-shadow-color: #1e2023; --kbd-text-color: #e2f2ff; + --guiitems-background-color: #303d4f; + --guiitems-border-color: #7fbbe3; + --btn-neutral-background-color: #404040; --btn-neutral-hover-background-color: #505050; --footer-color: #aaa; diff --git a/doc/_static/css/gcs.css b/doc/_static/css/gcs.css new file mode 100644 index 000000000000000..1650110885248aa --- /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/css/light.css b/doc/_static/css/light.css index 625516dce31bb80..0389650278c7cdd 100644 --- a/doc/_static/css/light.css +++ b/doc/_static/css/light.css @@ -85,6 +85,9 @@ --kbd-shadow-color: #b0b7bf; --kbd-text-color: #444d56; + --guiitems-background-color: #e7f2fa; + --guiitems-border-color: #7fbbe3; + --btn-neutral-background-color: #f3f6f6; --btn-neutral-hover-background-color: #e5ebeb; --footer-color: #808080; diff --git a/doc/_static/js/custom.js b/doc/_static/js/custom.js new file mode 100644 index 000000000000000..52f254b38c786d4 --- /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 3213c955bdbd608..50ef29d4d2bc0dd 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/breadcrumbs.html b/doc/_templates/breadcrumbs.html index c0052e0ce539b2e..d1855e491fd392c 100644 --- a/doc/_templates/breadcrumbs.html +++ b/doc/_templates/breadcrumbs.html @@ -18,10 +18,16 @@
  • - {%- if display_vcs_link %} - {% set vcs_url = pagename | vcs_link_get_url %} - {% if vcs_url %} - {{ _('Open on GitHub') }} + {%- if display_gh_links %} + {% set gh_blob_url = pagename | gh_link_get_blob_url %} + {% if gh_blob_url %} + {{ _('Open on GitHub') }} + {% endif %} + {%- set git_last_updated, sha1 = pagename | git_info | default((None, None), true) %} + {%- if sha1 %} + + {{ _('Report an issue with this page')}} + {% endif %} {% endif %}
  • diff --git a/doc/_templates/footer.html b/doc/_templates/footer.html new file mode 100644 index 000000000000000..757bb27529d00f2 --- /dev/null +++ b/doc/_templates/footer.html @@ -0,0 +1,30 @@ +{% extends "!footer.html" %} +{% block contentinfo %} +

    + {%- if show_copyright %} + © Copyright {{ copyright }}. + {%- endif %} + + {%- if last_updated %} + + Last generated on {{ last_updated }}. + + {%- endif -%} +

    +{%- 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! +

    +

    + The human-authored contents on this page was last updated on {{ git_last_updated }}. +

    +

    + If you find any errors on this page, outdated information, or have any other suggestion for + improving its contents, please consider + opening an issue. +

    +
    +{%- endif %} +{% endblock %} diff --git a/doc/_templates/gsearch.html b/doc/_templates/gsearch.html new file mode 100644 index 000000000000000..1953466355bcebe --- /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 205b24885551461..6d58c015548a5cd 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 000000000000000..4779a49c03beca4 --- /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/cmake/index.rst b/doc/build/cmake/index.rst index 479e044b68e2cc6..534c3ff34e106bc 100644 --- a/doc/build/cmake/index.rst +++ b/doc/build/cmake/index.rst @@ -108,7 +108,7 @@ Devicetree :ref:`dt-guide`. Kconfig - :file:`Kconfig` files define available configuration options for for the + :file:`Kconfig` files define available configuration options for the target architecture, SoC, board, and application, as well as dependencies between options. diff --git a/doc/build/dts/api/api.rst b/doc/build/dts/api/api.rst index 7d802838041d3ee..44b87653cc3fe14 100644 --- a/doc/build/dts/api/api.rst +++ b/doc/build/dts/api/api.rst @@ -140,6 +140,7 @@ depends on" relation: - a node directly depends on any nodes its properties refer to by phandle - a node directly depends on its ``interrupt-parent`` if it has an ``interrupts`` property +- a parent node inherits all dependencies from its child nodes A *dependency ordering* of a devicetree is a list of its nodes, where each node ``n`` appears earlier in the list than any nodes that depend on ``n``. A node's @@ -423,6 +424,9 @@ device. interprocess-communication (IPC) * - zephyr,itcm - Instruction Tightly Coupled Memory node on some Arm SoCs + * - zephyr,log-uart + - Sets the UART device(s) used by the logging subsystem's UART backend. + If defined, the UART log backend would output to the devices listed in this node. * - zephyr,ocm - On-chip memory node on Xilinx Zynq-7000 and ZynqMP SoCs * - zephyr,osdp-uart diff --git a/doc/build/dts/bindings-syntax.rst b/doc/build/dts/bindings-syntax.rst index aff8bb641055ded..4cdadf6263125f0 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/howtos.rst b/doc/build/dts/howtos.rst index 02580ad223dacd0..cb556bb782d6fdc 100644 --- a/doc/build/dts/howtos.rst +++ b/doc/build/dts/howtos.rst @@ -149,7 +149,9 @@ that the node has ``status = "okay"``, like this: If you see the ``#error`` output, make sure to enable the node in your devicetree. In some situations your code will compile but it will fail to link -with a message similar to:: +with a message similar to: + +.. code-block:: none ...undefined reference to `__device_dts_ord_N' collect2: error: ld returned 1 exit status @@ -299,6 +301,7 @@ For example, if your BOARD.dts contains this node: These are equivalent ways to override the ``current-speed`` value in an overlay: +.. Disable syntax highlighting as this construct does not seem supported by pygments .. code-block:: none /* Option 1 */ @@ -316,7 +319,7 @@ We'll use the ``&serial0`` style for the rest of these examples. You can add aliases to your devicetree using overlays: an alias is just a property of the ``/aliases`` node. For example: -.. code-block:: none +.. code-block:: devicetree / { aliases { @@ -326,7 +329,7 @@ property of the ``/aliases`` node. For example: Chosen nodes work the same way. For example: -.. code-block:: none +.. code-block:: devicetree / { chosen { @@ -337,7 +340,7 @@ Chosen nodes work the same way. For example: To delete a property (in addition to deleting properties in general, this is how to set a boolean property to false if it's true in BOARD.dts): -.. code-block:: none +.. code-block:: devicetree &serial0 { /delete-property/ some-unwanted-property; @@ -346,7 +349,7 @@ how to set a boolean property to false if it's true in BOARD.dts): You can add subnodes using overlays. For example, to configure a SPI or I2C child device on an existing bus node, do something like this: -.. code-block:: none +.. code-block:: devicetree /* SPI device example */ &spi1 { diff --git a/doc/build/dts/intro-input-output.rst b/doc/build/dts/intro-input-output.rst index 7b2c2a1119c8c4a..365d9fd3c377f8a 100644 --- a/doc/build/dts/intro-input-output.rst +++ b/doc/build/dts/intro-input-output.rst @@ -23,7 +23,9 @@ There are four types of devicetree input files: - overlays (``.overlay``) - bindings (``.yaml``) -The devicetree files inside the :file:`zephyr` directory look like this:: +The devicetree files inside the :file:`zephyr` directory look like this: + +.. code-block:: none boards///.dts dts/common/skeleton.dtsi diff --git a/doc/build/dts/intro-syntax-structure.rst b/doc/build/dts/intro-syntax-structure.rst index 8f5d3aa84d0d60a..1fd7eead9f85cc8 100644 --- a/doc/build/dts/intro-syntax-structure.rst +++ b/doc/build/dts/intro-syntax-structure.rst @@ -370,7 +370,7 @@ curious about details, see the devicetree specification. Additional notes on the above: - The values in the ``phandle``, ``phandles``, and ``phandle-array`` types are - are described further in :ref:`dt-phandles` + described further in :ref:`dt-phandles` - Boolean properties are true if present. They should not have a value. A boolean property is only false if it is completely missing in the DTS. @@ -387,9 +387,11 @@ Additional notes on the above: that order. - Parentheses, arithmetic operators, and bitwise operators are allowed. The - ``bar`` property contains a single cell with value 64:: + ``bar`` property contains a single cell with value 64: - bar = <(2 * (1 << 5))>; + .. code-block:: devicetree + + bar = <(2 * (1 << 5))>; Note that the entire expression must be parenthesized. @@ -419,7 +421,7 @@ Additional notes on the above: - Array and similar type property values can be split into several ``<>`` blocks, like this: - .. code-block:: none + .. code-block:: devicetree foo = <1 2>, <3 4>; // Okay for 'type: array' foo = <&label1 &label2>, <&label3 &label4>; // Okay for 'type: phandles' diff --git a/doc/build/dts/macros.bnf b/doc/build/dts/macros.bnf index 66e74bfbf55c0de..f42f483887749c6 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/dts/troubleshooting.rst b/doc/build/dts/troubleshooting.rst index 563ce04aac5c654..54169b3ab425275 100644 --- a/doc/build/dts/troubleshooting.rst +++ b/doc/build/dts/troubleshooting.rst @@ -193,7 +193,7 @@ as you enable the devicetree node. Otherwise, it is sometimes as simple as adding a line like this to your application's :file:`prj.conf` file and then making sure to :ref:`dt-trouble-try-pristine`: -.. code-block:: none +.. code-block:: cfg CONFIG_FOO=y diff --git a/doc/build/kconfig/extensions.rst b/doc/build/kconfig/extensions.rst index c8cb285aeb5c151..9ee8b33c85f04ac 100644 --- a/doc/build/kconfig/extensions.rst +++ b/doc/build/kconfig/extensions.rst @@ -8,6 +8,42 @@ implementation of `Kconfig `__, which includes some Kconfig extensions: +- Default values can be applied to existing symbols without + :ref:`weakening ` the symbols dependencies + through the use of ``configdefault``. + + .. code-block:: none + + config FOO + bool "FOO" + depends on BAR + + configdefault FOO + default y if FIZZ + + The statement above is equivalent to: + + .. code-block:: none + + config FOO + bool "Foo" + default y if FIZZ + depends on BAR + + ``configdefault`` symbols cannot contain any fields other than ``default``, + however they can be wrapped in ``if`` statements. The two statements below + are equivalent: + + .. code-block:: none + + configdefault FOO + default y if BAR + + if BAR + configdefault FOO + default y + endif # BAR + - Environment variables in ``source`` statements are expanded directly, meaning no "bounce" symbols with ``option env="ENV_VAR"`` need to be defined. @@ -26,7 +62,7 @@ which includes some Kconfig extensions: Consider the following example: - .. code-block:: none + .. code-block:: kconfig source "foo/bar/*/Kconfig" @@ -34,7 +70,7 @@ which includes some Kconfig extensions: :file:`foo/bar/baz/Kconfig` and :file:`foo/bar/qaz/Kconfig`, the statement above is equivalent to the following two ``source`` statements: - .. code-block:: none + .. code-block:: kconfig source "foo/bar/baz/Kconfig" source "foo/bar/qaz/Kconfig" @@ -61,7 +97,7 @@ which includes some Kconfig extensions: :file:`Kconfig` file, and that :file:`foo/bar/Kconfig` has the following statements: - .. code-block:: none + .. code-block:: kconfig source "qaz/Kconfig1" rsource "qaz/Kconfig2" @@ -83,7 +119,7 @@ which includes some Kconfig extensions: For example, the following statement will include :file:`Kconfig1` and :file:`Kconfig2` from the current directory (if they exist): - .. code-block:: none + .. code-block:: kconfig orsource "Kconfig[12]" diff --git a/doc/build/kconfig/preprocessor-functions.rst b/doc/build/kconfig/preprocessor-functions.rst index 295d50af7c48c4c..ae3777444d84509 100644 --- a/doc/build/kconfig/preprocessor-functions.rst +++ b/doc/build/kconfig/preprocessor-functions.rst @@ -28,45 +28,43 @@ while the ``*_hex`` version returns a hexadecimal value starting with ``0x``. .. code-block:: none - $(dt_has_compat,) - $(dt_compat_enabled,) - $(dt_compat_on_bus,,) - $(dt_chosen_label,) + $(dt_alias_enabled,) + $(dt_chosen_bool_prop, , ) $(dt_chosen_enabled,) - $(dt_chosen_path,) $(dt_chosen_has_compat,) - $(dt_path_enabled,) - $(dt_alias_enabled,) - $(dt_nodelabel_enabled,) - $(dt_nodelabel_enabled_with_compat,,) - $(dt_chosen_reg_addr_int,[,,]) + $(dt_chosen_label,) + $(dt_chosen_path,) $(dt_chosen_reg_addr_hex,[,,]) - $(dt_chosen_reg_size_int,[,,]) + $(dt_chosen_reg_addr_int,[,,]) $(dt_chosen_reg_size_hex,[,,]) - $(dt_node_reg_addr_int,[,,]) - $(dt_node_reg_addr_hex,[,,]) - $(dt_node_reg_size_int,[,,]) - $(dt_node_reg_size_hex,[,,]) - $(dt_nodelabel_reg_addr_int,[,,]) - $(dt_nodelabel_reg_addr_hex,[,,]) - $(dt_nodelabel_reg_size_int,[,,]) - $(dt_nodelabel_reg_size_hex,[,,]) + $(dt_chosen_reg_size_int,[,,]) $(dt_compat_enabled,) - $(dt_chosen_enabled,) + $(dt_compat_on_bus,,) + $(dt_gpio_hogs_enabled) + $(dt_has_compat,) $(dt_node_bool_prop,,) - $(dt_nodelabel_bool_prop,,) - $(dt_chosen_bool_prop, , ) + $(dt_node_has_compat,,) $(dt_node_has_prop,,) - $(dt_nodelabel_has_prop,,) - $(dt_node_int_prop_int,,[,]) $(dt_node_int_prop_hex,,[,]) + $(dt_node_int_prop_int,,[,]) + $(dt_node_parent,) + $(dt_node_reg_addr_hex,[,,]) + $(dt_node_reg_addr_int,[,,]) + $(dt_node_reg_size_hex,[,,]) + $(dt_node_reg_size_int,[,,]) $(dt_node_str_prop_equals,,,) + $(dt_nodelabel_array_prop_has_val, , , ) + $(dt_nodelabel_bool_prop,,) + $(dt_nodelabel_enabled,) + $(dt_nodelabel_enabled_with_compat,,) $(dt_nodelabel_has_compat,,) - $(dt_node_has_compat,,) + $(dt_nodelabel_has_prop,,) $(dt_nodelabel_path,) - $(dt_node_parent,) - $(dt_nodelabel_array_prop_has_val, , , ) - $(dt_gpio_hogs_enabled) + $(dt_nodelabel_reg_addr_hex,[,,]) + $(dt_nodelabel_reg_addr_int,[,,]) + $(dt_nodelabel_reg_size_hex,[,,]) + $(dt_nodelabel_reg_size_int,[,,]) + $(dt_path_enabled,) $(shields_list_contains,) @@ -75,7 +73,7 @@ Example Usage Assume that the devicetree for some board looks like this: -.. code-block:: none +.. code-block:: devicetree { soc { @@ -94,14 +92,14 @@ The second entry in ``reg`` in ``spi@1001400`` (``<0x20010000 0x3c0900>``) corresponds to ``mem``, and has the address ``0x20010000``. This address can be inserted into Kconfig as follows: -.. code-block:: none +.. code-block:: kconfig config FLASH_BASE_ADDRESS default $(dt_node_reg_addr_hex,/soc/spi@1001400,1) After preprocessor expansion, this turns into the definition below: -.. code-block:: none +.. code-block:: kconfig config FLASH_BASE_ADDRESS default 0x20010000 diff --git a/doc/build/kconfig/setting.rst b/doc/build/kconfig/setting.rst index dbc1ff845d858d4..57dd7828978c446 100644 --- a/doc/build/kconfig/setting.rst +++ b/doc/build/kconfig/setting.rst @@ -28,7 +28,7 @@ between *visible* and *invisible* symbols. Here's an example of a visible symbol: - .. code-block:: none + .. code-block:: kconfig config FPU bool "Support floating point operations" @@ -47,7 +47,7 @@ between *visible* and *invisible* symbols. Here's an example of an invisible symbol: - .. code-block:: none + .. code-block:: kconfig config CPU_HAS_FPU bool @@ -68,7 +68,7 @@ board with application settings, usually from :file:`prj.conf`. See Assignments in configuration files use this syntax: -.. code-block:: none +.. code-block:: cfg CONFIG_= @@ -78,7 +78,7 @@ There should be no spaces around the equals sign. respectively. The ``FPU`` symbol from the example above could be enabled like this: -.. code-block:: none +.. code-block:: cfg CONFIG_FPU=y @@ -87,7 +87,7 @@ this: A boolean symbol can also be set to ``n`` with a comment formatted like this: - .. code-block:: none + .. code-block:: cfg # CONFIG_SOME_OTHER_BOOL is not set @@ -100,14 +100,14 @@ this: Other symbol types are assigned like this: -.. code-block:: none +.. code-block:: cfg CONFIG_SOME_STRING="cool value" CONFIG_SOME_INT=123 Comments use a #: -.. code-block:: none +.. code-block:: cfg # This is a comment @@ -212,7 +212,7 @@ Assigning values in :file:`Kconfig.defconfig` relies on defining a Kconfig symbol in multiple locations. As an example, say we want to set ``FOO_WIDTH`` below to 32: -.. code-block:: none +.. code-block:: kconfig config FOO_WIDTH int @@ -220,7 +220,7 @@ below to 32: To do this, we extend the definition of ``FOO_WIDTH`` as follows, in :file:`Kconfig.defconfig`: -.. code-block:: none +.. code-block:: kconfig if BOARD_MY_BOARD @@ -246,25 +246,51 @@ Note that conditions from surrounding top-level ``if``\ s are propagated to symbol properties, so the above ``default`` is equivalent to ``default 32 if BOARD_MY_BOARD``. -.. warning:: +.. _multiple_symbol_definitions: - When defining a symbol in multiple locations, dependencies are ORed together - rather than ANDed together. It is not possible to make the dependencies of a - symbol more restrictive by defining it in multiple locations. +Multiple symbol definitions +--------------------------- - For example, the direct dependencies of the symbol below becomes - ``DEP1 || DEP2``: +When a symbol is defined in multiple locations, each definition acts as an +independent symbol that happens to share the same name. This means that +properties are not appended to previous definitions. If the conditions +for **ANY** definition result in the symbol resolving to ``y``, the symbol +will be ``y``. It is therefore not possible to make the dependencies of a +symbol more restrictive by defining it in multiple locations. - .. code-block:: none +For example, the dependencies of the symbol ``FOO`` below are satisfied if +either ``DEP1`` **OR** ``DEP2`` are true, it does not require both: + +.. code-block:: none + + config FOO + ... + depends on DEP1 + + config FOO + ... + depends on DEP2 + +.. warning:: + Symbols without explicit dependencies still follow the above rule. A + symbol without any dependencies will result in the symbol always being + assignable. The definition below will result in ``FOO`` always being + enabled by default, regardless of the value of ``DEP1``. + + .. code-block:: kconfig config FOO - ... - depends on DEP1 + bool "FOO" + depends on DEP1 config FOO - ... - depends on DEP2 + default y + This dependency weakening can be avoided with the :ref:`configdefault + ` extension if the desire is only to add a new default + without modifying any other behaviour of the symbol. + +.. note:: When making changes to :file:`Kconfig.defconfig` files, always check the symbol's direct dependencies in one of the :ref:`interactive configuration interfaces ` afterwards. It is often necessary to repeat @@ -312,7 +338,7 @@ There are two ways to configure a Kconfig ``choice``: As an example, assume that a choice has the following base definition (here, the name of the choice is ``FOO``): - .. code-block:: none + .. code-block:: kconfig choice FOO bool "Foo choice" @@ -329,7 +355,7 @@ There are two ways to configure a Kconfig ``choice``: To change the default symbol of ``FOO`` to ``A``, you would add the following definition to :file:`Kconfig.defconfig`: - .. code-block:: none + .. code-block:: kconfig choice FOO default A @@ -347,5 +373,4 @@ The :ref:`kconfig_tips_and_tricks` page has some tips for writing Kconfig files. The :zephyr_file:`kconfiglib.py ` docstring -docstring (at the top of the file) goes over how symbol values are calculated -in detail. +(at the top of the file) goes over how symbol values are calculated in detail. diff --git a/doc/build/kconfig/tips.rst b/doc/build/kconfig/tips.rst index 276157cdc08a360..9bae4d2a1c75796 100644 --- a/doc/build/kconfig/tips.rst +++ b/doc/build/kconfig/tips.rst @@ -92,7 +92,7 @@ The ``select`` statement is used to force one symbol to ``y`` whenever another symbol is ``y``. For example, the following code forces ``CONSOLE`` to ``y`` whenever ``USB_CONSOLE`` is ``y``: -.. code-block:: none +.. code-block:: kconfig config CONSOLE bool "Console support" @@ -116,7 +116,7 @@ For example, say that a new dependency is added to the ``CONSOLE`` symbol above, by a developer who is unaware of the ``USB_CONSOLE`` symbol (or simply forgot about it): -.. code-block:: none +.. code-block:: kconfig config CONSOLE bool "Console support" @@ -128,7 +128,7 @@ Enabling ``USB_CONSOLE`` now forces ``CONSOLE`` to ``y``, even if To fix the problem, the ``STRING_ROUTINES`` dependency needs to be added to ``USB_CONSOLE`` as well: -.. code-block:: none +.. code-block:: kconfig config USB_CONSOLE bool "USB console support" @@ -146,7 +146,7 @@ statements are common. An alternative attempt to solve the issue might be to turn the ``depends on`` into another ``select``: -.. code-block:: none +.. code-block:: kconfig config CONSOLE bool "Console support" @@ -181,7 +181,7 @@ Alternatives to ``select`` For the example in the previous section, a better solution is usually to turn the ``select`` into a ``depends on``: -.. code-block:: none +.. code-block:: kconfig config CONSOLE bool "Console support" @@ -198,7 +198,7 @@ dependencies only ever have to be updated in a single spot. An objection to using ``depends on`` here might be that configuration files that enable ``USB_CONSOLE`` now also need to enable ``CONSOLE``: -.. code-block:: none +.. code-block:: cfg CONFIG_CONSOLE=y CONFIG_USB_CONSOLE=y @@ -206,7 +206,7 @@ that enable ``USB_CONSOLE`` now also need to enable ``CONSOLE``: This comes down to a trade-off, but if enabling ``CONSOLE`` is the norm, then a mitigation is to make ``CONSOLE`` default to ``y``: -.. code-block:: none +.. code-block:: kconfig config CONSOLE bool "Console support" @@ -214,14 +214,14 @@ mitigation is to make ``CONSOLE`` default to ``y``: This gives just a single assignment in configuration files: -.. code-block:: none +.. code-block:: cfg CONFIG_USB_CONSOLE=y Note that configuration files that do not want ``CONSOLE`` enabled now have to explicitly disable it: -.. code-block:: none +.. code-block:: cfg CONFIG_CONSOLE=n @@ -238,7 +238,7 @@ dependencies. For example, a helper symbol for indicating that a particular CPU/SoC has an FPU could be defined as follows: -.. code-block:: none +.. code-block:: kconfig config CPU_HAS_FPU bool @@ -260,7 +260,7 @@ FPU could be defined as follows: This makes it possible for other symbols to check for FPU support in a generic way, without having to look for particular architectures: -.. code-block:: none +.. code-block:: kconfig config FPU bool "Support floating point operations" @@ -269,7 +269,7 @@ way, without having to look for particular architectures: The alternative would be to have dependencies like the following, possibly duplicated in several spots: -.. code-block:: none +.. code-block:: kconfig config FPU bool "Support floating point operations" @@ -279,7 +279,7 @@ Invisible helper symbols can also be useful without ``select``. For example, the following code defines a helper symbol that has the value ``y`` if the machine has some arbitrarily-defined "large" amount of memory: -.. code-block:: none +.. code-block:: kconfig config LARGE_MEM def_bool MEM_SIZE >= 64 @@ -288,7 +288,7 @@ machine has some arbitrarily-defined "large" amount of memory: This is short for the following: - .. code-block:: none + .. code-block:: kconfig config LARGE_MEM bool @@ -325,7 +325,7 @@ on`` was used. A common misunderstanding related to ``if`` is to think that the following code conditionally includes the file :file:`Kconfig.other`: -.. code-block:: none +.. code-block:: kconfig if DEP source "Kconfig.other" @@ -342,14 +342,14 @@ meaning around a ``source``. Say that :file:`Kconfig.other` above contains this definition: -.. code-block:: none +.. code-block:: kconfig config FOO bool "Support foo" In this case, ``FOO`` will end up with this definition: -.. code-block:: none +.. code-block:: kconfig config FOO bool "Support foo" @@ -371,7 +371,7 @@ twice. There is a common subtle gotcha related to interdependent configuration symbols with prompts. Consider these symbols: -.. code-block:: none +.. code-block:: kconfig config FOO bool "Foo" @@ -396,7 +396,7 @@ To understand what's going on, remember that ``STACK_SIZE`` has a prompt, meaning it is user-configurable, and consider that all Kconfig has to go on from the initial configuration is this: -.. code-block:: none +.. code-block:: cfg CONFIG_STACK_SIZE=0x100 @@ -412,7 +412,7 @@ with suggestions: - If ``STACK_SIZE`` can always be derived automatically and does not need to be user-configurable, then just remove the prompt: - .. code-block:: none + .. code-block:: kconfig config STACK_SIZE hex @@ -425,7 +425,7 @@ with suggestions: 0x200 when ``FOO`` is enabled, then disable its prompt when ``FOO`` is enabled, as described in `optional prompts`_: - .. code-block:: none + .. code-block:: kconfig config STACK_SIZE hex "Stack size" if !FOO @@ -436,7 +436,7 @@ with suggestions: set to a custom value in rare circumstances, then add another option for making ``STACK_SIZE`` user-configurable: - .. code-block:: none + .. code-block:: kconfig config CUSTOM_STACK_SIZE bool "Use a custom stack size" @@ -500,7 +500,7 @@ calculating symbol values. The Kconfig definitions below will hide the ``FOO_DEVICE_FREQUENCY`` symbol and disable any configuration output for it when ``FOO_DEVICE`` is disabled. -.. code-block:: none +.. code-block:: kconfig config FOO_DEVICE bool "Foo device" @@ -530,7 +530,7 @@ children in a separate menu rooted at ``FOO``. ``menuconfig`` can cut down on the number of menus and make the menu structure easier to navigate. For example, say you have the following definitions: -.. code-block:: none +.. code-block:: kconfig menu "Foo subsystem" @@ -557,7 +557,7 @@ easier to navigate. For example, say you have the following definitions: In this case, it's probably better to get rid of the ``menu`` and turn ``FOO_SUBSYSTEM`` into a ``menuconfig`` symbol: -.. code-block:: none +.. code-block:: kconfig menuconfig FOO_SUBSYSTEM bool "Foo subsystem" @@ -599,7 +599,7 @@ Commas in macro arguments Kconfig uses commas to separate macro arguments. This means a construct like this will fail: -.. code-block:: none +.. code-block:: kconfig config FOO bool @@ -608,7 +608,7 @@ This means a construct like this will fail: To solve this problem, create a variable with the text and use this variable as argument, as follows: -.. code-block:: none +.. code-block:: kconfig DT_CHOSEN_ZEPHYR_BAR := zephyr,bar @@ -688,7 +688,7 @@ be factored out with an ``if``. As an example, consider the following code: -.. code-block:: none +.. code-block:: kconfig config FOO bool "Foo" @@ -712,7 +712,7 @@ As an example, consider the following code: Here, the ``DEP`` dependency can be factored out like this: -.. code-block:: none +.. code-block:: kconfig if DEP @@ -742,7 +742,7 @@ Here, the ``DEP`` dependency can be factored out like this: If a sequence of symbols/choices with shared dependencies are all in the same menu, the dependency can be put on the menu itself: -.. code-block:: none +.. code-block:: kconfig menu "Foo features" depends on FOO_SUPPORT @@ -782,7 +782,7 @@ a previously defined ``default y``. That is, FOO will be set to ``n`` in the example below. If the ``default n`` was omitted in the first definition, FOO would have been set to ``y``. - .. code-block:: none + .. code-block:: kconfig config FOO bool "foo" @@ -794,7 +794,7 @@ omitted in the first definition, FOO would have been set to ``y``. In the following example FOO will get the value ``y``. - .. code-block:: none + .. code-block:: kconfig config FOO bool "foo" @@ -814,12 +814,12 @@ Kconfig has two shorthands that deal with prompts and defaults. - `` "prompt"`` is a shorthand for giving a symbol/choice a type and a prompt at the same time. These two definitions are equal: - .. code-block:: none + .. code-block:: kconfig config FOO bool "foo" - .. code-block:: none + .. code-block:: kconfig config FOO bool @@ -830,12 +830,12 @@ Kconfig has two shorthands that deal with prompts and defaults. - ``def_ `` is a shorthand for giving a type and a value at the same time. These two definitions are equal: - .. code-block:: none + .. code-block:: kconfig config FOO def_bool BAR && BAZ - .. code-block:: none + .. code-block:: kconfig config FOO bool @@ -907,7 +907,7 @@ doesn't force a value. For example, the following code could be used to enable USB keyboard support by default on the FOO SoC, while still allowing the user to turn it off: -.. code-block:: none +.. code-block:: kconfig config SOC_FOO bool "FOO SoC" @@ -928,7 +928,7 @@ A condition can be put on a symbol's prompt to make it optionally configurable by the user. For example, a value ``MASK`` that's hardcoded to 0xFF on some boards and configurable on others could be expressed as follows: -.. code-block:: none +.. code-block:: kconfig config MASK hex "Bitmask" if HAS_CONFIGURABLE_MASK @@ -938,7 +938,7 @@ boards and configurable on others could be expressed as follows: This is short for the following: - .. code-block:: none + .. code-block:: kconfig config MASK hex @@ -956,7 +956,7 @@ Optional choices Defining a choice with the ``optional`` keyword allows the whole choice to be toggled off to select none of the symbols: -.. code-block:: none +.. code-block:: kconfig choice prompt "Use legacy protocol" @@ -983,7 +983,7 @@ within it, while still allowing symbol default values to kick in. As a motivating example, consider the following code: -.. code-block:: none +.. code-block:: kconfig menu "Foo subsystem" depends on HAS_CONFIGURABLE_FOO @@ -1002,7 +1002,7 @@ When ``HAS_CONFIGURABLE_FOO`` is ``n``, no configuration output is generated for ``FOO_SETTING_1`` and ``FOO_SETTING_2``, as the code above is logically equivalent to the following code: -.. code-block:: none +.. code-block:: kconfig config FOO_SETTING_1 int "Foo setting 1" @@ -1018,7 +1018,7 @@ If we want the symbols to still get their default values even when ``HAS_CONFIGURABLE_FOO`` is ``n``, but not be configurable by the user, then we can use ``visible if`` instead: -.. code-block:: none +.. code-block:: kconfig menu "Foo subsystem" visible if HAS_CONFIGURABLE_FOO @@ -1035,7 +1035,7 @@ can use ``visible if`` instead: This is logically equivalent to the following: -.. code-block:: none +.. code-block:: kconfig config FOO_SETTING_1 int "Foo setting 1" if HAS_CONFIGURABLE_FOO @@ -1053,7 +1053,7 @@ This is logically equivalent to the following: When ``HAS_CONFIGURABLE`` is ``n``, we now get the following configuration output for the symbols, instead of no output: -.. code-block:: none +.. code-block:: cfg ... CONFIG_FOO_SETTING_1=1 diff --git a/doc/build/sysbuild/index.rst b/doc/build/sysbuild/index.rst index e09ee3e5617020a..b66ec8938c782b5 100644 --- a/doc/build/sysbuild/index.rst +++ b/doc/build/sysbuild/index.rst @@ -104,21 +104,27 @@ As mentioned above, you can run sysbuild via ``west build`` or ``cmake``. .. tip:: To configure ``west build`` to use ``--sysbuild`` by default from now on, - run:: + run: - west config build.sysbuild True + .. code-block:: shell + + west config build.sysbuild True Since sysbuild supports both single- and multi-image builds, this lets you use sysbuild all the time, without worrying about what type of build you are running. - To turn this off, run this before generating your build system:: + To turn this off, run this before generating your build system: + + .. code-block:: shell + + west config build.sysbuild False - west config build.sysbuild False + To turn this off for just one ``west build`` command, run: - To turn this off for just one ``west build`` command, run:: + .. code-block:: shell - west build --no-sysbuild ... + west build --no-sysbuild ... .. group-tab:: ``cmake`` @@ -206,15 +212,15 @@ build system to the value ``BAR``, run the following commands: .. group-tab:: ``west build`` - :: + .. code-block:: shell west build --sysbuild ... -- -Dmy_sample_FOO=BAR .. group-tab:: ``cmake`` - :: + .. code-block:: shell - cmake -Dmy_sample_FOO=BAR ... + cmake -Dmy_sample_FOO=BAR ... .. _sysbuild_kconfig_namespacing: @@ -242,13 +248,13 @@ build system to the value ``BAR``, run the following commands: .. group-tab:: ``west build`` - :: + .. code-block:: shell west build --sysbuild ... -- -Dmy_sample_CONFIG_FOO=BAR .. group-tab:: ``cmake`` - :: + .. code-block:: shell cmake -Dmy_sample_CONFIG_FOO=BAR ... @@ -263,13 +269,13 @@ build system to the value ``BAR``, run the following commands: the same syntax for setting Kconfig values at CMake time. For example, the following commands will work in the same way: - :: + .. code-block:: shell - west build -b my_sample -- -DCONFIG_FOO=BAR + west build -b my_sample -- -DCONFIG_FOO=BAR - :: + .. code-block:: shell - west build -b --sysbuild my_sample -- -DCONFIG_FOO=BAR + west build -b --sysbuild my_sample -- -DCONFIG_FOO=BAR Sysbuild flashing using ``west flash`` ************************************** @@ -359,7 +365,7 @@ MCUboot whenever sysbuild is used: └── sysbuild.conf -.. code-block:: none +.. code-block:: cfg SB_CONFIG_BOOTLOADER_MCUBOOT=y @@ -432,7 +438,7 @@ target to execute and it will run. location, the ``rom_report`` build target for ``mcuboot`` can be ran with: - .. code-block:: bash + .. code-block:: shell west build -d build/mcuboot -t rom_report @@ -442,7 +448,7 @@ target to execute and it will run. using ``ninja`` using sysbuild with mcuboot enabled, the ``rom_report`` build target for ``mcuboot`` can be ran with: - .. code-block:: bash + .. code-block:: shell ninja -C mcuboot rom_report @@ -452,7 +458,7 @@ target to execute and it will run. using ``make`` using sysbuild with mcuboot enabled, the ``rom_report`` build target for ``mcuboot`` can be ran with: - .. code-block:: bash + .. code-block:: shell make -C mcuboot rom_report @@ -607,7 +613,7 @@ file or a devicetree overlay :file:`sysbuild/my_sample.overlay`. A Kconfig fragment could look as: -.. code-block:: none +.. code-block:: cfg # sysbuild/my_sample.conf CONFIG_FOO=n diff --git a/doc/build/version/index.rst b/doc/build/version/index.rst index de4e713c6b60926..8d169a85bf59df8 100644 --- a/doc/build/version/index.rst +++ b/doc/build/version/index.rst @@ -26,7 +26,7 @@ which must be placed at the base directory of the application, where the CMakeLi located. This is a simple text file which contains the various version information fields, each on a newline. The basic ``VERSION`` file has the following structure: -.. code-block:: none +.. code-block:: cfg VERSION_MAJOR = VERSION_MINOR = @@ -58,7 +58,7 @@ manually re-ran for changes to this file. For the sections below, examples are provided for the following :file:`VERSION` file: -.. code-block:: none +.. code-block:: cfg VERSION_MAJOR = 1 VERSION_MINOR = 2 diff --git a/doc/build/zephyr_cmake_package.rst b/doc/build/zephyr_cmake_package.rst index fd8eeadd2706619..499765556bdc0f7 100644 --- a/doc/build/zephyr_cmake_package.rst +++ b/doc/build/zephyr_cmake_package.rst @@ -233,15 +233,17 @@ In case no Zephyr is found which satisfies the version required, as example, the find_package(Zephyr 2.z) project(app) -then an error similar to below will be printed:: +then an error similar to below will be printed: - Could not find a configuration file for package "Zephyr" that is compatible - with requested version "2.z". +.. code-block:: none + + Could not find a configuration file for package "Zephyr" that is compatible + with requested version "2.z". - The following configuration files were considered but not accepted: + The following configuration files were considered but not accepted: - /zephyr-workspace-2.a/zephyr/share/zephyr-package/cmake/ZephyrConfig.cmake, version: 2.a.0 - /zephyr-workspace-2.b/zephyr/share/zephyr-package/cmake/ZephyrConfig.cmake, version: 2.b.0 + /zephyr-workspace-2.a/zephyr/share/zephyr-package/cmake/ZephyrConfig.cmake, version: 2.a.0 + /zephyr-workspace-2.b/zephyr/share/zephyr-package/cmake/ZephyrConfig.cmake, version: 2.b.0 .. note:: It can also be beneficial to specify a version number for Zephyr repository applications diff --git a/doc/conf.py b/doc/conf.py index 2785ec5438b5eb5..a570eef7c35c528 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -5,10 +5,9 @@ import os from pathlib import Path import re +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] @@ -26,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: @@ -36,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 @@ -64,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", @@ -81,7 +88,7 @@ "sphinx_tabs.tabs", "zephyr.warnings_filter", "zephyr.doxyrunner", - "zephyr.vcs_link", + "zephyr.gh_utils", "zephyr.manifest_projects_table", "notfound.extension", "sphinx_copybutton", @@ -104,6 +111,7 @@ exclude_patterns.append("**/*west-not-found*") pygments_style = "sphinx" +highlight_language = "none" todo_include_todos = False @@ -127,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 @@ -150,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 = "" @@ -163,17 +187,21 @@ "current_version": version, "versions": ( ("latest", "/"), + ("3.5.0", "/3.5.0/"), ("3.4.0", "/3.4.0/"), - ("3.3.0", "/3.3.0/"), ("2.7.5 (LTS)", "/2.7.5/"), ), - "display_vcs_link": True, + "display_gh_links": True, "reference_links": { "API": f"{reference_prefix}/doxygen/html/index.html", "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 --------------------------------------------- @@ -182,7 +210,12 @@ "papersize": "a4paper", "maketitle": open(ZEPHYR_BASE / "doc" / "_static" / "latex" / "title.tex").read(), "preamble": open(ZEPHYR_BASE / "doc" / "_static" / "latex" / "preamble.tex").read(), - "fontpkg": r"\usepackage{charter}", + "makeindex": r"\usepackage[columns=1]{idxlayout}\makeindex", + "fontpkg": textwrap.dedent(r""" + \usepackage{noto} + \usepackage{inconsolata-nerd-font} + \usepackage[T1]{fontenc} + """), "sphinxsetup": ",".join( ( # NOTE: colors match those found in light.css stylesheet @@ -199,12 +232,7 @@ latex_documents = [ ("index-tex", "zephyr.tex", "Zephyr Project Documentation", author, "manual"), ] - -# -- Options for linkcheck ------------------------------------------------ - -linkcheck_ignore = [ - r"https://github.com/zephyrproject-rtos/zephyr/issues/.*" -] +latex_engine = "xelatex" # -- Options for zephyr.doxyrunner plugin --------------------------------- @@ -259,17 +287,17 @@ notfound_urls_prefix = f"/{version}/" if is_release else "/latest/" -# -- Options for zephyr.vcs_link ------------------------------------------ +# -- Options for zephyr.gh_utils ------------------------------------------ -vcs_link_version = f"v{version}" if is_release else "main" -vcs_link_base_url = f"https://github.com/zephyrproject-rtos/zephyr/blob/{vcs_link_version}" -vcs_link_prefixes = { +gh_link_version = f"v{version}" if is_release else "main" +gh_link_base_url = f"https://github.com/zephyrproject-rtos/zephyr" +gh_link_prefixes = { "samples/.*": "", "boards/.*": "", "snippets/.*": "", ".*": "doc", } -vcs_link_exclude = [ +gh_link_exclude = [ "reference/kconfig.*", "build/dts/api/bindings.*", "build/dts/api/compatibles.*", @@ -300,6 +328,10 @@ "build/dts/api/compatibles/**/*", ] +# -- Options for zephyr.domain -------------------------------------------- + +zephyr_breathe_insert_related_samples = True + # -- Options for sphinx.ext.graphviz -------------------------------------- graphviz_dot = os.environ.get("DOT_EXECUTABLE", "dot") @@ -313,8 +345,17 @@ "-Ecolor=gray60", ] +# -- Options for sphinx_copybutton ---------------------------------------- + +copybutton_prompt_text = r"\$ |uart:~\$ " +copybutton_prompt_is_regexp = True + # -- Linkcheck options ---------------------------------------------------- +linkcheck_ignore = [ + r"https://github.com/zephyrproject-rtos/zephyr/issues/.*" +] + extlinks = { "github": ("https://github.com/zephyrproject-rtos/zephyr/issues/%s", "GitHub #%s"), } @@ -327,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/gatt.rst b/doc/connectivity/bluetooth/api/gatt.rst index 3cc1af64387b862..bb4487f57dd833f 100644 --- a/doc/connectivity/bluetooth/api/gatt.rst +++ b/doc/connectivity/bluetooth/api/gatt.rst @@ -56,7 +56,7 @@ respective operations. thus it is not recommended to block for long periods of time in them. Attribute value changes can be notified using :c:func:`bt_gatt_notify` API, -alternatively there is :c:func:`bt_gatt_notify_cb` where is is possible to +alternatively there is :c:func:`bt_gatt_notify_cb` where it is possible to pass a callback to be called when it is necessary to know the exact instant when the data has been transmitted over the air. Indications are supported by :c:func:`bt_gatt_indicate` API. diff --git a/doc/connectivity/bluetooth/api/index.rst b/doc/connectivity/bluetooth/api/index.rst index 51c3638611400c0..fa7e357f7d84e35 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 6e2fca1b111938d..358ba3dc62e1032 100644 --- a/doc/connectivity/bluetooth/api/mesh.rst +++ b/doc/connectivity/bluetooth/api/mesh.rst @@ -3,14 +3,11 @@ Bluetooth Mesh Profile ###################### -The Bluetooth mesh profile adds secure wireless multi-hop communication for +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 `_. +`Bluetooth Mesh Protocol Specification v1.1 `_. -Implementation of the `Bluetooth Mesh Protocol Specification v1.1 `_ -is in experimental state. - -Read more about Bluetooth mesh on the +Read more about Bluetooth Mesh on the `Bluetooth SIG Website `_. .. toctree:: diff --git a/doc/connectivity/bluetooth/api/mesh/access.rst b/doc/connectivity/bluetooth/api/mesh/access.rst index 151e74add28624b..aa6082f5df48e87 100644 --- a/doc/connectivity/bluetooth/api/mesh/access.rst +++ b/doc/connectivity/bluetooth/api/mesh/access.rst @@ -3,7 +3,7 @@ Access layer ############ -The access layer is the application's interface to the Bluetooth mesh network. +The access layer is the application's interface to the Bluetooth Mesh network. The access layer provides mechanisms for compartmentalizing the node behavior into elements and models, which are implemented by the application. @@ -113,7 +113,7 @@ number within one publication interval. Extended models =============== -The Bluetooth mesh specification allows the mesh models to extend each other. +The Bluetooth Mesh specification allows the mesh models to extend each other. When a model extends another, it inherits that model's functionality, and extension can be used to construct complex models out of simple ones, leveraging the existing model functionality to avoid defining new opcodes. @@ -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 @@ -185,17 +176,15 @@ information about the device. In order to access this information, the user may use the :ref:`bluetooth_mesh_models_cfg_srv` model or, if supported, the :ref:`bluetooth_mesh_lcd_srv` model. -Composition Data Page 0 and 128 -------------------------------- +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. Composition Data Page 128 -mirrors Page 0 and is used to represent the new content of the Composition Data -Page 0 after a device firmware update. +the supported features, and manufacturer information. -Composition Data Page 1 and 129 -------------------------------- +Composition Data Page 1 +----------------------- Composition Data Page 1 provides information about the relationships between models, and is mandatory for all mesh devices. A model may extend and/or correspond to one @@ -204,11 +193,9 @@ or correspond to another model by calling :c:func:`bt_mesh_model_correspond`. :kconfig:option:`CONFIG_BT_MESH_MODEL_EXTENSION_LIST_SIZE` specifies how many model relations can be stored in the composition on a device, and this number should reflect the number of :c:func:`bt_mesh_model_extend` and :c:func:`bt_mesh_model_correspond` calls. -Composition Data Page 129 mirrors Page 1 and is used to represent the new content of -the Composition Data Page 1 after a device firmware update. -Composition Data Page 2 and 130 -------------------------------- +Composition Data Page 2 +----------------------- Composition Data Page 2 provides information for supported mesh profiles. Mesh profile specifications define product requirements for devices that want to support a specific @@ -216,8 +203,63 @@ Bluetooth SIG defined profile. Currently supported profiles can be found in sect 3.12 in `Bluetooth SIG Assigned Numbers `_. Composition Data Page 2 is only mandatory for devices that claim support for one or more -mesh profile(s). Composition Data Page 130 mirrors Page 2 and is used to represent the -new content of the Composition Data Page 2 after a device firmware update. +mesh profile(s). + +Composition Data Pages 128, 129 and 130 +--------------------------------------- + +Composition Data Pages 128, 129 and 130 mirror Composition Data Pages 0, 1 and 2 respectively. +They are used to represent the new content of the mirrored pages when the Composition Data will +change after a firmware update. See :ref:`bluetooth_mesh_dfu_srv_comp_data_and_models_metadata` +for details. + +Delayable messages +================== + +The delayable message functionality is enabled with Kconfig option +:kconfig:option:`CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG`. +This is an optional functionality that implements specification recommendations for +messages that are transmitted by a model in a response to a received message, also called +response messages. + +Response messages should be sent with the following random delays: + +* Between 20 and 50 milliseconds if the received message was sent + to a unicast address +* Between 20 and 500 milliseconds if the received message was sent + to a group or virtual address + +The delayable message functionality is triggered if the :c:member:`bt_mesh_msg_ctx.rnd_delay` +flag is set. +The delayable message functionality stores messages in the local memory while they are +waiting for the random delay expiration. + +If the transport layer doesn't have sufficient memory to send a message at the moment +the random delay expires, the message is postponed for another 10 milliseconds. +If the transport layer cannot send a message for any other reason, the delayable message +functionality raises the :c:member:`bt_mesh_send_cb.start` callback with a transport layer +error code. + +If the delayable message functionality cannot find enough free memory to store an incoming +message, it will send messages with delay close to expiration to free memory. + +When the mesh stack is suspended or reset, messages not yet sent are removed and +the :c:member:`bt_mesh_send_cb.start` callback is raised with an error code. + +Delayable publications +====================== + +The delayable publication functionality implements the specification recommendations for message +publication delays in the following cases: + +* Between 20 to 500 milliseconds when the Bluetooth Mesh stack starts or when the publication is + triggered by the :c:func:`bt_mesh_model_publish` function +* Between 20 to 50 milliseconds for periodically published messages + +This feature is optional and enabled with the :kconfig:option:`CONFIG_BT_MESH_DELAYABLE_PUBLICATION` +Kconfig option. When enabled, each model can enable or disable the delayable publication by setting +the :c:member:`bt_mesh_model_pub.delayable` bit field to ``1`` or ``0`` correspondingly. This bit +field can be changed at any time. API reference ************* diff --git a/doc/connectivity/bluetooth/api/mesh/blob.rst b/doc/connectivity/bluetooth/api/mesh/blob.rst index 31f45289560554f..8395026afe4e6da 100644 --- a/doc/connectivity/bluetooth/api/mesh/blob.rst +++ b/doc/connectivity/bluetooth/api/mesh/blob.rst @@ -5,7 +5,7 @@ BLOB Transfer models The Binary Large Object (BLOB) Transfer models implement the Bluetooth Mesh Binary Large Object Transfer Model specification version 1.0 and provide functionality for sending large binary objects -from a single source to many Target nodes over the Bluetooth mesh network. It is the underlying +from a single source to many Target nodes over the Bluetooth Mesh network. It is the underlying transport method for the :ref:`bluetooth_mesh_dfu`, but may be used for other object transfer purposes. The implementation is in experimental state. @@ -50,7 +50,7 @@ structure of the BLOB, and applications are free to define any encoding or compr on the data itself. The BLOB transfer protocol does not provide any built-in integrity checks, encryption or -authentication of the BLOB data. However, the underlying encryption of the Bluetooth mesh protocol +authentication of the BLOB data. However, the underlying encryption of the Bluetooth Mesh protocol provides data integrity checks and protects the contents of the BLOB from third parties using network and application level encryption. @@ -68,7 +68,7 @@ Chunks ------ Each block is divided into chunks. A chunk is the smallest data unit in the BLOB transfer, and must -fit inside a single Bluetooth mesh access message excluding the opcode (379 bytes or less). The +fit inside a single Bluetooth Mesh access message excluding the opcode (379 bytes or less). The mechanism for transferring chunks depends on the transfer mode. When operating in Push BLOB Transfer Mode, the chunks are sent as unacknowledged packets from the diff --git a/doc/connectivity/bluetooth/api/mesh/blob_cli.rst b/doc/connectivity/bluetooth/api/mesh/blob_cli.rst index 2232153f5498b50..b4193d5033472ff 100644 --- a/doc/connectivity/bluetooth/api/mesh/blob_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/blob_cli.rst @@ -25,7 +25,7 @@ The BLOB Transfer Client is instantiated on an element with a set of event handl .cb = &blob_cb, }; - static struct bt_mesh_model models[] = { + static const struct bt_mesh_model models[] = { BT_MESH_MODEL_BLOB_CLI(&blob_cli), }; @@ -67,7 +67,7 @@ Target nodes having the BLOB Transfer Server model subscribe to this group addre Using group addresses for transferring the BLOBs can generally increase the transfer speed, as the BLOB Transfer Client sends each message to all Target nodes at the same time. However, sending -large, segmented messages to group addresses in Bluetooth mesh is generally less reliable than +large, segmented messages to group addresses in Bluetooth Mesh is generally less reliable than sending them to unicast addresses, as there is no transport layer acknowledgment mechanism for groups. This can lead to longer recovery periods at the end of each block, and increases the risk of losing Target nodes. Using group addresses for BLOB transfers will generally only pay off if the diff --git a/doc/connectivity/bluetooth/api/mesh/blob_srv.rst b/doc/connectivity/bluetooth/api/mesh/blob_srv.rst index a76ac34d6fb6a72..0d13e92148e7561 100644 --- a/doc/connectivity/bluetooth/api/mesh/blob_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/blob_srv.rst @@ -35,7 +35,7 @@ The BLOB Transfer Server is instantiated on an element with a set of event handl .cb = &blob_cb, }; - static struct bt_mesh_model models[] = { + static const struct bt_mesh_model models[] = { BT_MESH_MODEL_BLOB_SRV(&blob_srv), }; @@ -77,7 +77,7 @@ Transfer recovery ***************** The state of the BLOB transfer is stored persistently. If a reboot occurs, the BLOB Transfer Server -will attempt to recover the transfer. When the Bluetooth mesh subsystem is started (for instance by +will attempt to recover the transfer. When the Bluetooth Mesh subsystem is started (for instance by calling :c:func:`bt_mesh_init`), the BLOB Transfer Server will check for aborted transfers, and call the :c:member:`recover ` callback if there is any. In the recover callback, the user must provide a BLOB stream to use for the rest of the transfer. If the recover diff --git a/doc/connectivity/bluetooth/api/mesh/cfg.rst b/doc/connectivity/bluetooth/api/mesh/cfg.rst index 01d3c9ca2e520bb..e178984210d67dd 100644 --- a/doc/connectivity/bluetooth/api/mesh/cfg.rst +++ b/doc/connectivity/bluetooth/api/mesh/cfg.rst @@ -6,7 +6,7 @@ Runtime Configuration The runtime configuration API allows applications to change their runtime configuration directly, without going through the Configuration models. -Bluetooth mesh nodes should generally be configured by a central network +Bluetooth Mesh nodes should generally be configured by a central network configurator device with a :ref:`bluetooth_mesh_models_cfg_cli` model. Each mesh node instantiates a :ref:`bluetooth_mesh_models_cfg_srv` model that the Configuration Client can communicate with to change the node configuration. In some diff --git a/doc/connectivity/bluetooth/api/mesh/cfg_cli.rst b/doc/connectivity/bluetooth/api/mesh/cfg_cli.rst index bf84edc6b86c8fb..300c8ee3bc1daa1 100644 --- a/doc/connectivity/bluetooth/api/mesh/cfg_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/cfg_cli.rst @@ -3,7 +3,7 @@ Configuration Client #################### -The Configuration Client model is a foundation model defined by the Bluetooth mesh +The Configuration Client model is a foundation model defined by the Bluetooth Mesh specification. It provides functionality for configuring most parameters of a mesh node, including encryption keys, model configuration and feature enabling. diff --git a/doc/connectivity/bluetooth/api/mesh/cfg_srv.rst b/doc/connectivity/bluetooth/api/mesh/cfg_srv.rst index 84f174df88bd0e2..8f595bf9b11aea8 100644 --- a/doc/connectivity/bluetooth/api/mesh/cfg_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/cfg_srv.rst @@ -3,7 +3,7 @@ Configuration Server #################### -The Configuration Server model is a foundation model defined by the Bluetooth mesh +The Configuration Server model is a foundation model defined by the Bluetooth Mesh specification. The Configuration Server model controls most parameters of the mesh node. It does not have an API of its own, but relies on a :ref:`bluetooth_mesh_models_cfg_cli` to control it. @@ -14,7 +14,7 @@ mesh node. It does not have an API of its own, but relies on a should be set through Kconfig, and the Heartbeat feature should be controlled through the :ref:`bluetooth_mesh_heartbeat` API. -The Configuration Server model is mandatory on all Bluetooth mesh nodes, and +The Configuration Server model is mandatory on all Bluetooth Mesh nodes, and must only be instantiated on the primary element. API reference diff --git a/doc/connectivity/bluetooth/api/mesh/core.rst b/doc/connectivity/bluetooth/api/mesh/core.rst index b9fdd164257e341..94e2b8a6e5ef139 100644 --- a/doc/connectivity/bluetooth/api/mesh/core.rst +++ b/doc/connectivity/bluetooth/api/mesh/core.rst @@ -3,7 +3,7 @@ Core #### -The core provides functionality for managing the general Bluetooth mesh +The core provides functionality for managing the general Bluetooth Mesh state. .. _bluetooth_mesh_lpn: @@ -117,7 +117,7 @@ Advertisement identity All mesh stack bearers advertise data with the :c:macro:`BT_ID_DEFAULT` local identity. The value is preset in the mesh stack implementation. When Bluetooth® Low Energy (LE) -and Bluetooth mesh coexist on the same device, the application should allocate and +and Bluetooth Mesh coexist on the same device, the application should allocate and configure another local identity for Bluetooth LE purposes before starting the communication. API reference diff --git a/doc/connectivity/bluetooth/api/mesh/dfu.rst b/doc/connectivity/bluetooth/api/mesh/dfu.rst index a929f8a53fc55ea..d2bf4ced2ce3259 100644 --- a/doc/connectivity/bluetooth/api/mesh/dfu.rst +++ b/doc/connectivity/bluetooth/api/mesh/dfu.rst @@ -3,16 +3,16 @@ Device Firmware Update (DFU) ############################ -Bluetooth mesh supports the distribution of firmware images across a mesh network. The Bluetooth +Bluetooth Mesh supports the distribution of firmware images across a mesh network. The Bluetooth mesh DFU subsystem implements the Bluetooth Mesh Device Firmware Update Model specification version 1.0. The implementation is in experimental state. -Bluetooth mesh DFU implements a distribution mechanism for firmware images, and does not put any +Bluetooth Mesh DFU implements a distribution mechanism for firmware images, and does not put any restrictions on the size, format or usage of the images. The primary design goal of the subsystem is -to provide the qualifiable parts of the Bluetooth mesh DFU specification, and leave the usage, +to provide the qualifiable parts of the Bluetooth Mesh DFU specification, and leave the usage, firmware validation and deployment to the application. -The DFU specification is implemented in the Zephyr Bluetooth mesh DFU subsystem as three separate +The DFU specification is implemented in the Zephyr Bluetooth Mesh DFU subsystem as three separate models: .. toctree:: @@ -28,7 +28,7 @@ Overview DFU roles ========= -The Bluetooth mesh DFU subsystem defines three different roles the mesh nodes have to assume in the +The Bluetooth Mesh DFU subsystem defines three different roles the mesh nodes have to assume in the distribution of firmware images: Target node @@ -47,20 +47,20 @@ Distributor image to the Target nodes. Initiator - The Initiator role is typically implemented by the same device that implements the Bluetooth mesh + The Initiator role is typically implemented by the same device that implements the Bluetooth Mesh :ref:`Provisioner ` and :ref:`Configurator ` roles. The Initiator needs a full overview of the potential Target nodes and their firmware, and will control (and initiate) all firmware updates. The - Initiator role is not implemented in the Zephyr Bluetooth mesh DFU subsystem. + Initiator role is not implemented in the Zephyr Bluetooth Mesh DFU subsystem. .. figure:: images/dfu_roles_mesh.svg :align: center :alt: Graphic overview of the DFU roles mesh nodes can have during the process of image distribution - DFU roles and the associated Bluetooth mesh models + DFU roles and the associated Bluetooth Mesh models -Bluetooth mesh applications may combine the DFU roles in any way they'd like, and even take on +Bluetooth Mesh applications may combine the DFU roles in any way they'd like, and even take on multiple instances of the same role by instantiating the models on separate elements. For instance, the Distributor and Initiator role can be combined by instantiating the :ref:`bluetooth_mesh_dfu_cli` on the Initiator node and calling its API directly. @@ -76,7 +76,7 @@ Firmware Update Client model directly, e.g. over a serial protocol. Stages ====== -The Bluetooth mesh DFU process is designed to act in three stages: +The Bluetooth Mesh DFU process is designed to act in three stages: Upload stage First, the image is uploaded to a Distributor in a mesh network by an external entity, such as a @@ -131,7 +131,7 @@ Firmware metadata Target node. The firmware metadata is optional, and its maximum length is determined by :kconfig:option:`CONFIG_BT_MESH_DFU_METADATA_MAXLEN`. - The Bluetooth mesh DFU subsystem in Zephyr provides its own metadata format + The Bluetooth Mesh DFU subsystem in Zephyr provides its own metadata format (:c:struct:`bt_mesh_dfu_metadata`) together with a set of related functions that can be used by an end product. The support for it is enabled using the :kconfig:option:`CONFIG_BT_MESH_DFU_METADATA` option. The format of the metadata is presented in @@ -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. | @@ -184,6 +184,8 @@ Firmware URI The out-of-band distribution mechanism is not supported. +.. _bluetooth_mesh_dfu_firmware_effect: + Firmware effect --------------- @@ -210,7 +212,12 @@ re-provisioned. The complete list of available options is defined in :c:enum:`bt When the Target node receives the Firmware Update Firmware Metadata Check message, the Firmware Update Server model calls the :c:member:`bt_mesh_dfu_srv_cb.check` callback, the application can -then process the metadata and provide the effect value. +then process the metadata and provide the effect value. If the effect is +:c:enum:`BT_MESH_DFU_EFFECT_COMP_CHANGE`, the application must call functions +:c:func:`bt_mesh_comp_change_prepare` and :c:func:`bt_mesh_models_metadata_change_prepare` to +prepare the Composition Data Page and Models Metadata Page contents before applying the new +firmware image. See :ref:`bluetooth_mesh_dfu_srv_comp_data_and_models_metadata` for more +information. DFU procedures @@ -292,7 +299,7 @@ following steps: node firmware image index and the firmware image metadata. Each Target node performs a metadata check and prepares their BLOB Transfer Server model for the transfer, before sending a status response to the Firmware Update Client, indicating if the firmware update will have any effect on - the Bluetooth mesh state of the node. + the Bluetooth Mesh state of the node. #. The Distributor's BLOB Transfer Client model transfers the firmware image to all Target nodes. #. Once the BLOB transfer has been received, the Target nodes' applications verify that the firmware is valid by performing checks such as signature verification or image checksums against the image diff --git a/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst b/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst index b78d4ce2c1d96a9..105bdecb86cceec 100644 --- a/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst @@ -16,7 +16,7 @@ Firmware images The Firmware Update Server holds a list of all the updatable firmware images on the device. The full list shall be passed to the server through the ``_imgs`` parameter in -:c:macro:`BT_MESH_DFU_SRV_INIT`, and must be populated before the Bluetooth mesh subsystem is +:c:macro:`BT_MESH_DFU_SRV_INIT`, and must be populated before the Bluetooth Mesh subsystem is started. Each firmware image in the image list must be independently updatable, and should have its own firmware ID. @@ -33,9 +33,9 @@ application is described below: .. figure:: images/dfu_srv.svg :align: center - :alt: Bluetooth mesh Firmware Update Server transfer + :alt: Bluetooth Mesh Firmware Update Server transfer - Bluetooth mesh Firmware Update Server transfer + Bluetooth Mesh Firmware Update Server transfer Transfer check ============== @@ -47,9 +47,37 @@ firmware image metadata. The Firmware Update Server performs the transfer check The result of the transfer check is a pass/fail status return and the expected :c:type:`bt_mesh_dfu_effect`. The DFU effect return parameter will be communicated back to the Distributor, and should indicate what effect the firmware update will have on the mesh state of the -device. If the transfer will cause the device to change its Composition Data or become +device. + +.. _bluetooth_mesh_dfu_srv_comp_data_and_models_metadata: + +Composition Data and Models Metadata +------------------------------------ + +If the transfer will cause the device to change its Composition Data or become unprovisioned, this should be communicated through the effect parameter of the metadata check. +When the transfer will cause the Composition Data to change, and the +:ref:`bluetooth_mesh_models_rpr_srv` is supported, the Composition Data of the new firmware image +will be represented by Composition Data Pages 128, 129, and 130. The Models Metadata of the new +firmware image will be represented by Models Metadata Page 128. Composition Data Pages 0, 1 and 2, +and Models Metadata Page 0, will represent the Composition Data and the Models Metadata of the old +firmware image until the device is reprovisioned with Node Provisioning Protocol Interface (NPPI) +procedures using the :ref:`bluetooth_mesh_models_rpr_cli`. + +The application must call functions :c:func:`bt_mesh_comp_change_prepare` and +:c:func:`bt_mesh_models_metadata_change_prepare` to store the existing Composition Data and Models +Metadata pages before booting into the firmware with the updated Composition Data and Models +Metadata. The old Composition Data will then be loaded into Composition Data Pages 0, 1 and 2, +while the Composition Data in the new firmware will be loaded into Composition Data Pages 128, 129 +and 130. The Models Metadata for the old image will be loaded into Models Metadata Page 0, and the +Models Metadata for the new image will be loaded into Models Metadata Page 128. + +Limitation: + +* It is not possible to change the Composition Data of the device and keep the device provisioned + and working with the old firmware after the new firmware image is applied. + Start ===== @@ -90,7 +118,7 @@ updated image. When the transfer applies to the mesh application itself, the device might have to reboot as part of the swap. This restart can be performed from inside the apply callback, or done asynchronously. After booting up with the new firmware, the firmware image table should be updated before the -Bluetooth mesh subsystem is started. +Bluetooth Mesh subsystem is started. The Distributor will read out the firmware image table to confirm that the transfer was successfully applied. If the metadata check indicated that the device would become unprovisioned, the Target node diff --git a/doc/connectivity/bluetooth/api/mesh/health_srv.rst b/doc/connectivity/bluetooth/api/mesh/health_srv.rst index 84c543b4766fa19..6f7b1fc3f3358c9 100644 --- a/doc/connectivity/bluetooth/api/mesh/health_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/health_srv.rst @@ -21,7 +21,7 @@ necessarily damaging to the device. Errors indicate conditions that are outside of the node's design limits, and may have caused invalid behavior or permanent damage to the device. -Fault values ``0x01`` to ``0x7f`` are reserved for the Bluetooth mesh +Fault values ``0x01`` to ``0x7f`` are reserved for the Bluetooth Mesh specification, and the full list of specification defined faults are available in :ref:`bluetooth_mesh_health_faults`. Fault values ``0x80`` to ``0xff`` are vendor specific. The list of faults are always reported with a company ID to @@ -57,6 +57,6 @@ API reference Health faults ============= -Fault values defined by the Bluetooth mesh specification. +Fault values defined by the Bluetooth Mesh specification. .. doxygengroup:: bt_mesh_health_faults diff --git a/doc/connectivity/bluetooth/api/mesh/heartbeat.rst b/doc/connectivity/bluetooth/api/mesh/heartbeat.rst index 16c2bfa784071fe..706625849c15369 100644 --- a/doc/connectivity/bluetooth/api/mesh/heartbeat.rst +++ b/doc/connectivity/bluetooth/api/mesh/heartbeat.rst @@ -3,7 +3,7 @@ Heartbeat ######### -The Heartbeat feature provides functionality for monitoring Bluetooth mesh nodes +The Heartbeat feature provides functionality for monitoring Bluetooth Mesh nodes and determining the distance between nodes. The Heartbeat feature is configured through the :ref:`bluetooth_mesh_models_cfg_srv` model. diff --git a/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst b/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst index 0eca28f1b2ae455..96189e21dd31cec 100644 --- a/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst @@ -3,7 +3,7 @@ Large Composition Data Client ############################# -The Large Composition Data Client model is a foundation model defined by the Bluetooth mesh +The Large Composition Data Client model is a foundation model defined by the Bluetooth Mesh specification. The model is optional, and is enabled through the :kconfig:option:`CONFIG_BT_MESH_LARGE_COMP_DATA_CLI` option. diff --git a/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst b/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst index f96436138b7d77f..f67b31c27f835d4 100644 --- a/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst @@ -3,7 +3,7 @@ Large Composition Data Server ############################# -The Large Composition Data Server model is a foundation model defined by the Bluetooth mesh +The Large Composition Data Server model is a foundation model defined by the Bluetooth Mesh specification. The model is optional, and is enabled through the :kconfig:option:`CONFIG_BT_MESH_LARGE_COMP_DATA_SRV` option. diff --git a/doc/connectivity/bluetooth/api/mesh/models.rst b/doc/connectivity/bluetooth/api/mesh/models.rst index 3f5f94152ce3ca1..94c3914ca53ccff 100644 --- a/doc/connectivity/bluetooth/api/mesh/models.rst +++ b/doc/connectivity/bluetooth/api/mesh/models.rst @@ -6,7 +6,7 @@ Mesh models Foundation models ***************** -The Bluetooth mesh specification defines foundation models that can be +The Bluetooth Mesh specification defines foundation models that can be used by network administrators to configure and diagnose mesh nodes. .. toctree:: @@ -34,7 +34,7 @@ used by network administrators to configure and diagnose mesh nodes. Model specification models ************************** -In addition to the foundation models defined in the Bluetooth mesh specification, the Bluetooth Mesh +In addition to the foundation models defined in the Bluetooth Mesh specification, the Bluetooth Mesh Model Specification defines several models, some of which are implemented in Zephyr: .. toctree:: diff --git a/doc/connectivity/bluetooth/api/mesh/msg.rst b/doc/connectivity/bluetooth/api/mesh/msg.rst index ae8b968198afc39..614d2604d9086c9 100644 --- a/doc/connectivity/bluetooth/api/mesh/msg.rst +++ b/doc/connectivity/bluetooth/api/mesh/msg.rst @@ -3,7 +3,7 @@ Message ####### -The Bluetooth mesh message provides set of structures, macros and functions used +The Bluetooth Mesh message provides set of structures, macros and functions used for preparing message buffers, managing message and acknowledged message contexts. diff --git a/doc/connectivity/bluetooth/api/mesh/od_cli.rst b/doc/connectivity/bluetooth/api/mesh/od_cli.rst index 5fc841716ceb516..e419acb7572cf08 100644 --- a/doc/connectivity/bluetooth/api/mesh/od_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/od_cli.rst @@ -3,7 +3,7 @@ On-Demand Private Proxy Client ############################## -The On-Demand Private Proxy Client model is a foundation model defined by the Bluetooth mesh +The On-Demand Private Proxy Client model is a foundation model defined by the Bluetooth Mesh specification. The model is optional, and is enabled with the :kconfig:option:`CONFIG_BT_MESH_OD_PRIV_PROXY_CLI` option. diff --git a/doc/connectivity/bluetooth/api/mesh/od_srv.rst b/doc/connectivity/bluetooth/api/mesh/od_srv.rst index 700517e42833e18..3c2f993bb302d96 100644 --- a/doc/connectivity/bluetooth/api/mesh/od_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/od_srv.rst @@ -3,7 +3,7 @@ On-Demand Private Proxy Server ############################## -The On-Demand Private Proxy Server model is a foundation model defined by the Bluetooth mesh +The On-Demand Private Proxy Server model is a foundation model defined by the Bluetooth Mesh specification. It is enabled with the :kconfig:option:`CONFIG_BT_MESH_OD_PRIV_PROXY_SRV` option. The On-Demand Private Proxy Server model was introduced in the Bluetooth Mesh Protocol Specification diff --git a/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst b/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst index 148557a4e81c100..4648b4495cd46aa 100644 --- a/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst @@ -3,7 +3,7 @@ Opcodes Aggregator Client ######################### -The Opcodes Aggregator Client model is a foundation model defined by the Bluetooth mesh +The Opcodes Aggregator Client model is a foundation model defined by the Bluetooth Mesh specification. It is an optional model, enabled with the :kconfig:option:`CONFIG_BT_MESH_OP_AGG_CLI` option. diff --git a/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst b/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst index cb531a4c3c8ba55..c9bcc8e5eb1c06c 100644 --- a/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst @@ -11,7 +11,7 @@ The Private Beacon Client model is introduced in the Bluetooth Mesh Protocol Specification version 1.1, and provides functionality for configuring the :ref:`bluetooth_mesh_models_priv_beacon_srv` models. -The Private Beacons feature adds privacy to the different Bluetooth mesh +The Private Beacons feature adds privacy to the different Bluetooth Mesh beacons by periodically randomizing the beacon input data. This protects the mesh node from being tracked by devices outside the mesh network, and hides the network's IV index, IV update and the Key Refresh state. diff --git a/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst b/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst index 3c17cc446752c76..62450634a317f18 100644 --- a/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst @@ -11,7 +11,7 @@ The Private Beacon Server model is introduced in the Bluetooth Mesh Protocol Specification version 1.1, and controls the mesh node's Private Beacon state, Private GATT Proxy state and Private Node Identity state. -The Private Beacons feature adds privacy to the different Bluetooth mesh +The Private Beacons feature adds privacy to the different Bluetooth Mesh beacons by periodically randomizing the beacon input data. This protects the mesh node from being tracked by devices outside the mesh network, and hides the network's IV index, IV update and the Key Refresh state. The Private Beacon Server diff --git a/doc/connectivity/bluetooth/api/mesh/provisioning.rst b/doc/connectivity/bluetooth/api/mesh/provisioning.rst index 0985234b86cd380..685c9dda455a795 100644 --- a/doc/connectivity/bluetooth/api/mesh/provisioning.rst +++ b/doc/connectivity/bluetooth/api/mesh/provisioning.rst @@ -12,15 +12,15 @@ two devices operating in the following roles: Provisioning process. Before the provisioning process starts, the provisionee is an *unprovisioned device*. -The Provisioning module in the Zephyr Bluetooth mesh stack supports both the +The Provisioning module in the Zephyr Bluetooth Mesh stack supports both the Advertising and GATT Provisioning bearers for the provisionee role, as well as the Advertising Provisioning bearer for the provisioner role. The Provisioning process ************************ -All Bluetooth mesh nodes must be provisioned before they can participate in a -Bluetooth mesh network. The Provisioning API provides all the functionality +All Bluetooth Mesh nodes must be provisioned before they can participate in a +Bluetooth Mesh network. The Provisioning API provides all the functionality necessary for a device to become a provisioned mesh node. Provisioning is a five-step process, involving the following steps: @@ -176,11 +176,11 @@ Depending on the choice of public key exchange mechanism and authentication meth the provisioning process can be secure or insecure. On May 24th 2021, ANSSI `disclosed `_ -a set of vulnerabilities in the Bluetooth mesh provisioning protocol that showcased +a set of vulnerabilities in the Bluetooth Mesh provisioning protocol that showcased how the low entropy provided by the Blink, Vibrate, Push, Twist and Input/Output numeric OOB methods could be exploited in impersonation and MITM attacks. In response, the Bluetooth SIG has reclassified these OOB methods as -insecure in the Mesh Profile specification `erratum 16350 `_, +insecure in the Bluetooth Mesh Profile Specification v1.0.1 `erratum 16350 `_, as AuthValue may be brute forced in real time. To ensure secure provisioning, applications should use a static OOB value and OOB public key transfer. diff --git a/doc/connectivity/bluetooth/api/mesh/proxy.rst b/doc/connectivity/bluetooth/api/mesh/proxy.rst index d9212e24bc07df2..5e905f2c9ef7dea 100644 --- a/doc/connectivity/bluetooth/api/mesh/proxy.rst +++ b/doc/connectivity/bluetooth/api/mesh/proxy.rst @@ -3,7 +3,7 @@ Proxy ##### -The Proxy feature allows legacy devices like phones to access the Bluetooth mesh network through +The Proxy feature allows legacy devices like phones to access the Bluetooth Mesh network through GATT. The Proxy feature is only compiled in if the :kconfig:option:`CONFIG_BT_MESH_GATT_PROXY` option is set. The Proxy feature state is controlled by the :ref:`bluetooth_mesh_models_cfg_srv`, and the initial value can be set with :c:member:`bt_mesh_cfg_srv.gatt_proxy`. @@ -31,7 +31,7 @@ In the case where both GATT Proxy and Private GATT Proxy states are disabled on device cannot connect to it. A node supporting the :ref:`bluetooth_mesh_od_srv` may however be solicited to advertise connectable advertising events without enabling the Private GATT Proxy state. To solicit the node, the legacy device can send a Solicitation PDU by calling the -:func:`bt_mesh_proxy_solicit` function. To enable this feature, the client must to be compiled with +:func:`bt_mesh_proxy_solicit` function. To enable this feature, the device must to be compiled with the :kconfig:option:`CONFIG_BT_MESH_PROXY_SOLICITATION` option set. Solicitation PDUs are non-mesh, non-connectable, undirected advertising messages containing Proxy diff --git a/doc/connectivity/bluetooth/api/mesh/rpr_srv.rst b/doc/connectivity/bluetooth/api/mesh/rpr_srv.rst index 63c159cd2b09d24..e51d3c8fac91191 100644 --- a/doc/connectivity/bluetooth/api/mesh/rpr_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/rpr_srv.rst @@ -21,6 +21,15 @@ Note that after refreshing the device key, node address or Composition Data thro Provisioning Protocol Interface (NPPI) procedure, the :c:member:`bt_mesh_prov.reprovisioned` callback is triggered. See section :ref:`bluetooth_mesh_models_rpr_cli` for further details. +Limitations +----------- + +The following limitations apply to Remote Provisioning Server model: + +* Provisioning of unprovisioned device using PB-GATT is not supported. +* All Node Provisioning Protocol Interface (NPPI) procedures are supported. However, if the composition data of a device gets changed after device firmware update (see :ref:`firmware effect `), it is not possible for the device to remain provisioned. The device should be unprovisioned if its composition data is expected to change. + + API reference ************* diff --git a/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst b/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst index a0aa2b46a3ea078..76bd0330a980002 100644 --- a/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst +++ b/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst @@ -4,7 +4,7 @@ Segmentation and reassembly (SAR) ################################# Segmentation and reassembly (SAR) provides a way of handling larger upper transport layer messages -in a mesh network, with a purpose of enhancing the Bluetooth mesh throughput. The segmentation and +in a mesh network, with a purpose of enhancing the Bluetooth Mesh throughput. The segmentation and reassembly mechanism is used by the lower transport layer. The lower transport layer defines how the upper transport layer PDUs are segmented and reassembled @@ -23,7 +23,7 @@ required. Set the ``send rel`` flag (see :c:struct:`bt_mesh_msg_ctx`) to use the transmission and acknowledge single-segment segmented messages. The transport layer is able to transport up to 32 segments with its SAR mechanism, with a maximum -message (PDU) size of 384 octets. To configure message size for the Bluetooth mesh stack, use the +message (PDU) size of 384 octets. To configure message size for the Bluetooth Mesh stack, use the following Kconfig options: * :kconfig:option:`CONFIG_BT_MESH_RX_SEG_MAX` to set the maximum number of segments in an incoming message. @@ -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/sar_cfg_cli.rst b/doc/connectivity/bluetooth/api/mesh/sar_cfg_cli.rst index b017b53a01a8fa0..1e2ab6c47a16f22 100644 --- a/doc/connectivity/bluetooth/api/mesh/sar_cfg_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/sar_cfg_cli.rst @@ -3,7 +3,7 @@ SAR Configuration Client ######################## -The SAR Configuration Client model is a foundation model defined by the Bluetooth mesh +The SAR Configuration Client model is a foundation model defined by the Bluetooth Mesh specification. It is an optional model, enabled with the :kconfig:option:`CONFIG_BT_MESH_SAR_CFG_CLI` configuration option. diff --git a/doc/connectivity/bluetooth/api/mesh/sar_cfg_srv.rst b/doc/connectivity/bluetooth/api/mesh/sar_cfg_srv.rst index 2ea1446c9ea3953..4280fae1350676f 100644 --- a/doc/connectivity/bluetooth/api/mesh/sar_cfg_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/sar_cfg_srv.rst @@ -3,13 +3,13 @@ SAR Configuration Server ######################## -The SAR Configuration Server model is a foundation model defined by the Bluetooth mesh +The SAR Configuration Server model is a foundation model defined by the Bluetooth Mesh specification. It is an optional model, enabled with the :kconfig:option:`CONFIG_BT_MESH_SAR_CFG_SRV` configuration option. The SAR Configuration Server model is introduced in the Bluetooth Mesh Protocol Specification version 1.1, and it supports the configuration of the -:ref:`segmentation and reassembly (SAR) ` behavior of a Bluetooth mesh node. +:ref:`segmentation and reassembly (SAR) ` behavior of a Bluetooth Mesh node. The model defines a set of states and messages for the SAR configuration. The SAR Configuration Server model defines two states, SAR Transmitter state and SAR Receiver state. diff --git a/doc/connectivity/bluetooth/api/mesh/shell.rst b/doc/connectivity/bluetooth/api/mesh/shell.rst index 2522cd9f38b4ad2..366e5d9ebada14e 100644 --- a/doc/connectivity/bluetooth/api/mesh/shell.rst +++ b/doc/connectivity/bluetooth/api/mesh/shell.rst @@ -3,32 +3,32 @@ Bluetooth Mesh Shell #################### -The Bluetooth mesh shell subsystem provides a set of Bluetooth mesh shell commands for the -:ref:`shell_api` module. It allows for testing and exploring the Bluetooth mesh API through an +The Bluetooth Mesh shell subsystem provides a set of Bluetooth Mesh shell commands for the +:ref:`shell_api` module. It allows for testing and exploring the Bluetooth Mesh API through an interactive interface, without having to write an application. -The Bluetooth mesh shell interface provides access to most Bluetooth mesh features, including +The Bluetooth Mesh shell interface provides access to most Bluetooth Mesh features, including provisioning, configuration, and message sending. Prerequisites ************* -The Bluetooth mesh shell subsystem depends on the application to create the composition data and do +The Bluetooth Mesh shell subsystem depends on the application to create the composition data and do the mesh initialization. Application *********** -The Bluetooth mesh shell subsystem is most easily used through the Bluetooth mesh shell application +The Bluetooth Mesh shell subsystem is most easily used through the Bluetooth Mesh shell application under ``tests/bluetooth/mesh_shell``. See :ref:`shell_api` for information on how to connect and -interact with the Bluetooth mesh shell application. +interact with the Bluetooth Mesh shell application. Basic usage *********** -The Bluetooth mesh shell subsystem adds a single ``mesh`` command, which holds a set of +The Bluetooth Mesh shell subsystem adds a single ``mesh`` command, which holds a set of sub-commands. Every time the device boots up, make sure to call ``mesh init`` before any of the -other Bluetooth mesh shell commands can be called:: +other Bluetooth Mesh shell commands can be called:: uart:~$ mesh init @@ -82,7 +82,7 @@ Message sending =============== With an application key added (see above), the mesh node's transition parameters are all valid, and -the Bluetooth mesh shell can send raw mesh messages through the network. +the Bluetooth Mesh shell can send raw mesh messages through the network. For example, to send a Generic OnOff Set message, call:: @@ -107,7 +107,7 @@ configured network and application keys will receive and process the messages we Sending raw mesh packets is a good way to test model message handler implementations during development, as it can be done without having to implement the sending model. By default, only the -reception of the model messages can be tested this way, as the Bluetooth mesh shell only includes +reception of the model messages can be tested this way, as the Bluetooth Mesh shell only includes the foundation models. To receive a packet in the mesh node, you have to add a model with a valid opcode handler list to the composition data in ``subsys/bluetooth/mesh/shell.c``, and print the incoming message to the shell in the handler callback. @@ -115,7 +115,7 @@ incoming message to the shell in the handler callback. Parameter formats ***************** -The Bluetooth mesh shell commands are parsed with a variety of formats: +The Bluetooth Mesh shell commands are parsed with a variety of formats: .. list-table:: Parameter formats :widths: 1 4 2 @@ -139,12 +139,12 @@ The Bluetooth mesh shell commands are parsed with a variety of formats: Commands ******** -The Bluetooth mesh shell implements a large set of commands. Some of the commands accept parameters, +The Bluetooth Mesh shell implements a large set of commands. Some of the commands accept parameters, which are mentioned in brackets after the command name. For example, ``mesh lpn set ``. Mandatory parameters are marked with angle brackets (e.g. ````), and optional parameters are marked with square brackets (e.g. ``[DstAddr]``). -The Bluetooth mesh shell commands are divided into the following groups: +The Bluetooth Mesh shell commands are divided into the following groups: .. contents:: :depth: 1 @@ -282,7 +282,7 @@ Provisioning ============ To allow a device to broadcast connectable unprovisioned beacons, the -:kconfig:option:`CONFIG_BT_MESH_PROV_DEVICE` configuration option must be enabled, along with the +:kconfig:option:`CONFIG_BT_MESH_PROVISIONEE` configuration option must be enabled, along with the :kconfig:option:`CONFIG_BT_MESH_PB_GATT` option. ``mesh prov pb-gatt `` @@ -295,7 +295,7 @@ To allow a device to broadcast connectable unprovisioned beacons, the * ``Val``: Enable or disable provisioning with GATT To allow a device to broadcast unprovisioned beacons, the -:kconfig:option:`CONFIG_BT_MESH_PROV_DEVICE` configuration option must be enabled, along with the +:kconfig:option:`CONFIG_BT_MESH_PROVISIONEE` configuration option must be enabled, along with the :kconfig:option:`CONFIG_BT_MESH_PB_ADV` option. ``mesh prov pb-adv `` @@ -344,7 +344,7 @@ and :kconfig:option:`CONFIG_BT_MESH_PB_GATT_CLIENT` configuration options must b Get or set the mesh node's UUID, used in the unprovisioned beacons. - * ``UUID``: If present, new 128-bit UUID value. Providing a hex-string shorter than 16 bytes will populate the N most significant bytes of the array and zero-pad the rest. If omitted, the current UUID will be printed. To enable this command, the :kconfig:option:`BT_MESH_SHELL_PROV_CTX_INSTANCE` option must be enabled. + * ``UUID``: If present, new 128-bit UUID value. Providing a hex-string shorter than 16 bytes will populate the N most significant bytes of the array and zero-pad the rest. If omitted, the current UUID will be printed. To enable this command, the :kconfig:option:`CONFIG_BT_MESH_SHELL_PROV_CTX_INSTANCE` option must be enabled. ``mesh prov input-num `` @@ -373,7 +373,7 @@ and :kconfig:option:`CONFIG_BT_MESH_PB_GATT_CLIENT` configuration options must b Set or clear the static OOB authentication value. The static OOB authentication value must be set before provisioning starts to have any effect. The static OOB value must be same on both participants in the provisioning. To enable this command, the - :kconfig:option:`BT_MESH_SHELL_PROV_CTX_INSTANCE` option must be enabled. + :kconfig:option:`CONFIG_BT_MESH_SHELL_PROV_CTX_INSTANCE` option must be enabled. * ``Val``: If present, indicates the new hexadecimal value of the static OOB. Providing a hex-string shorter than 16 bytes will populate the N most significant bytes of the array and zero-pad the rest. If omitted, the static OOB value is cleared. @@ -394,7 +394,7 @@ and :kconfig:option:`CONFIG_BT_MESH_PB_GATT_CLIENT` configuration options must b Enable or disable printing of incoming unprovisioned beacons. Allows a provisioner device to detect nearby unprovisioned devices and provision them. To enable this command, the - :kconfig:option:`BT_MESH_SHELL_PROV_CTX_INSTANCE` option must be enabled. + :kconfig:option:`CONFIG_BT_MESH_SHELL_PROV_CTX_INSTANCE` option must be enabled. * ``Val``: Whether to enable the unprovisioned beacon printing. @@ -499,16 +499,16 @@ enabled, and as long as the Configuration Client model is present in the model c application. This shell module can be used for configuring itself and other nodes in the mesh network. -The Configuration Client uses general message parameters set by ``mesh target dst`` and -``mesh target net`` to target specific nodes. When the Bluetooth mesh shell node is provisioned, -given that the :kconfig:option:`BT_MESH_SHELL_PROV_CTX_INSTANCE` option is enabled with the shell +The Configuration Client uses general message parameters set by ``mesh target dst`` and ``mesh +target net`` to target specific nodes. When the Bluetooth Mesh shell node is provisioned, given that +the :kconfig:option:`CONFIG_BT_MESH_SHELL_PROV_CTX_INSTANCE` option is enabled with the shell provisioning context initialized, the Configuration Client model targets itself by default. -Similarly, when another node has been provisioned by the Bluetooth mesh shell, the Configuration +Similarly, when another node has been provisioned by the Bluetooth Mesh shell, the Configuration Client model targets the new node. In most common use-cases, the Configuration Client is depending on the provisioning features and the Configuration database to be fully functional. The -Configuration Client always sends messages using the Device key bound to the destination address, -so it will only be able to configure itself and the mesh nodes it provisioned. The following steps -are an example of how you can set up a device to start using the Configuration Client commands: +Configuration Client always sends messages using the Device key bound to the destination address, so +it will only be able to configure itself and the mesh nodes it provisioned. The following steps are +an example of how you can set up a device to start using the Configuration Client commands: * Initialize the client node (``mesh init``). * Create the CDB (``mesh cdb create``). @@ -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``, @@ -1645,7 +1645,7 @@ The Private Beacon Client model is an optional mesh subsystem that can be enable Opcodes Aggregator Client ------------------------- -The Opcodes Aggregator client is an optional Bluetooth mesh model that can be enabled through the +The Opcodes Aggregator client is an optional Bluetooth Mesh model that can be enabled through the :kconfig:option:`CONFIG_BT_MESH_OP_AGG_CLI` configuration option. The Opcodes Aggregator Client model is used to support the functionality of dispatching a sequence of access layer messages to nodes supporting the Opcodes Aggregator Server model. @@ -1675,7 +1675,7 @@ nodes supporting the Opcodes Aggregator Server model. Remote Provisioning Client -------------------------- -The Remote Provisioning Client is an optional Bluetooth mesh model enabled through the +The Remote Provisioning Client is an optional Bluetooth Mesh model enabled through the :kconfig:option:`CONFIG_BT_MESH_RPR_CLI` configuration option. The Remote Provisioning Client model provides support for remote provisioning of devices into a mesh network by using the Remote Provisioning Server model. diff --git a/doc/connectivity/bluetooth/api/shell/cap.rst b/doc/connectivity/bluetooth/api/shell/cap.rst index 74bf5bac72fc069..32d752d71fc831d 100644 --- a/doc/connectivity/bluetooth/api/shell/cap.rst +++ b/doc/connectivity/bluetooth/api/shell/cap.rst @@ -14,7 +14,7 @@ Using the CAP Acceptor ====================== When the Bluetooth stack has been initialized (:code:`bt init`), the Acceptor can be registered by -by calling :code:`cap_acceptor init`, which will register the CAS and CSIS services, as well as +calling :code:`cap_acceptor init`, which will register the CAS and CSIS services, as well as register callbacks. .. code-block:: console @@ -137,3 +137,59 @@ 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 + + +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 diff --git a/doc/connectivity/bluetooth/api/shell/csip.rst b/doc/connectivity/bluetooth/api/shell/csip.rst index e2daf744cacbea1..d0fddaa61f3c41a 100644 --- a/doc/connectivity/bluetooth/api/shell/csip.rst +++ b/doc/connectivity/bluetooth/api/shell/csip.rst @@ -14,7 +14,7 @@ or a laptop. The client is able to lock and release members of a coordinated set. While the coordinated set is locked, no other clients may lock the set. To lock a set, the client must connect to each of the set members it wants to -lock. This implementation will always try to to connect to all the members of +lock. This implementation will always try to connect to all the members of the set, and at the same time. Thus if the set size is 3, then :code:`BT_MAX_CONN` shall be at least 3. diff --git a/doc/connectivity/bluetooth/api/shell/gmap.rst b/doc/connectivity/bluetooth/api/shell/gmap.rst new file mode 100644 index 000000000000000..11259297a5b36a4 --- /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/mcp.rst b/doc/connectivity/bluetooth/api/shell/mcp.rst index a48ef50685c2c92..e0930852e10c232 100644 --- a/doc/connectivity/bluetooth/api/shell/mcp.rst +++ b/doc/connectivity/bluetooth/api/shell/mcp.rst @@ -27,8 +27,7 @@ Also note that this documentation does not list all shell commands, it just shows examples of some of them. The set of commands is explorable from the mcc shell and the mpl shell, by typing :code:`mcc` or :code:`mpl` and pressing TAB. A help text for each command can be -found by doing :code:`mcc help` or or :code:`mpl -help`. +found by doing :samp:`mcc {} help` or :samp:`mpl {} help`. Overview ******** diff --git a/doc/connectivity/bluetooth/api/shell/pbp.rst b/doc/connectivity/bluetooth/api/shell/pbp.rst new file mode 100644 index 000000000000000..ba3e0f459fd5e49 --- /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/api/shell/tmap.rst b/doc/connectivity/bluetooth/api/shell/tmap.rst index 416644b30692944..8a562a813615718 100644 --- a/doc/connectivity/bluetooth/api/shell/tmap.rst +++ b/doc/connectivity/bluetooth/api/shell/tmap.rst @@ -10,7 +10,7 @@ Using the TMAP Shell ******************** When the Bluetooth stack has been initialized (:code:`bt init`), the TMAS can be registered by -by calling :code:`tmap init`. +calling :code:`tmap init`. .. code-block:: console diff --git a/doc/connectivity/bluetooth/autopts/autopts-linux.rst b/doc/connectivity/bluetooth/autopts/autopts-linux.rst index 6388673f0256b07..eac940e97378995 100644 --- a/doc/connectivity/bluetooth/autopts/autopts-linux.rst +++ b/doc/connectivity/bluetooth/autopts/autopts-linux.rst @@ -16,11 +16,11 @@ Supported methods to test zephyr bluetooth host: - Testing Zephyr Host Stack on QEMU -- Testing Zephyr Host Stack on native posix +- Testing Zephyr Host Stack on :ref:`native_sim ` - Testing Zephyr combined (controller + host) build on Real hardware (such as nRF52) -For running with QEMU or native posix, see :ref:`bluetooth_qemu_posix`. +For running with QEMU or :ref:`native_sim `, see :ref:`bluetooth_qemu_native`. Setup Linux =========================== @@ -293,14 +293,14 @@ Testing Zephyr Host Stack on QEMU: ~/zephyrproject/build/zephyr/zephyr.elf -i SERVER_IP -l LOCAL_IP -Testing Zephyr Host Stack on native posix: +Testing Zephyr Host Stack on :ref:`native_sim `: .. code-block:: # A Bluetooth controller needs to be mounted. # For running with HCI UART, please visit: https://docs.zephyrproject.org/latest/samples/bluetooth/hci_uart/README.html#bluetooth-hci-uart - west build -b native_posix zephyr/tests/bluetooth/tester/ -DEXTRA_CONF_FILE=overlay-native.conf + west build -b native_sim zephyr/tests/bluetooth/tester/ -DEXTRA_CONF_FILE=overlay-native.conf sudo python ./autoptsclient-zephyr.py "C:\Users\USER_NAME\Documents\Profile Tuning Suite\PTS_PROJECT\PTS_PROJECT.pqw6" \ ~/zephyrproject/build/zephyr/zephyr.exe -i SERVER_IP -l LOCAL_IP --hci 0 diff --git a/doc/connectivity/bluetooth/bluetooth-arch.rst b/doc/connectivity/bluetooth/bluetooth-arch.rst index 9b455e680d0a785..ed0cf1ea9f609df 100644 --- a/doc/connectivity/bluetooth/bluetooth-arch.rst +++ b/doc/connectivity/bluetooth/bluetooth-arch.rst @@ -248,7 +248,7 @@ Each role comes with its own build-time configuration option: connection-oriented roles central implicitly enables observer role, and peripheral implicitly enables broadcaster role. Usually the first step when creating an application is to decide which roles are needed and go -from there. Bluetooth mesh is a slightly special case, requiring at +from there. Bluetooth Mesh is a slightly special case, requiring at least the observer and broadcaster roles, and possibly also the Peripheral role. This will be described in more detail in a later section. diff --git a/doc/connectivity/bluetooth/bluetooth-audio-arch.rst b/doc/connectivity/bluetooth/bluetooth-audio-arch.rst index 494611282706f29..85388b6dc0f68f3 100644 --- a/doc/connectivity/bluetooth/bluetooth-audio-arch.rst +++ b/doc/connectivity/bluetooth/bluetooth-audio-arch.rst @@ -43,6 +43,181 @@ GAF has been implemented in Zephyr with the following structure. Zephyr Generic Audio Framework +Bluetooth Audio Stack Status +============================ + +The following table shows the current status and support of the profiles in the +Bluetooth Audio Stack. + +.. table:: Bluetooth Audio Profile status + :widths: auto + + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | Module | Role | Version | Added in Release | Status | Remaining | + +========+===============================+=========+==================+=======================+==================================================+ + | VCP | Volume Renderer | 1.0 | 2.6 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Volume Controller | 1.0 | 2.6 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | MICP | Microphone Device | 1.0 | 2.7 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Microphone Controller | 1.0 | 2.7 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | CSIP | Set Member | 1.0.1 | 3.0 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Set Coordinator | 1.0.1 | 3.0 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | CCP | Call Control Server | 1.0 | 3.0 | - Feature complete | - API refactor | + | | | | | - Shell Module | - Sample Application | + | | | | | - BSIM test | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Call Control Client | 1.0 | 3.0 | - Feature complete | - API refactor | + | | | | | - Shell Module | - Sample Application | + | | | | | - BSIM test | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | MCP | Media Control Server | 1.0 | 3.0 | - Feature complete | - API refactor | + | | | | | - Shell Module | - Support for multiple instances and connections | + | | | | | - BSIM test | - Sample Application | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Media Control Client | 1.0 | 3.0 | - Feature complete | - API refactor | + | | | | | - Shell Module | - Sample Application | + | | | | | - BSIM test | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | BAP | Unicast Server | 1.0.1 | 3.0 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Unicast Client | 1.0.1 | 3.0 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Broadcast Source | 1.0.1 | 3.0 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Broadcast Sink | 1.0.1 | 3.0 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Scan Delegator | 1.0.1 | 3.3 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Broadcast Assistant | 1.0.1 | 3.3 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | CAP | Acceptor | 1.0 | 3.2 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Initiator | 1.0 | 3.3 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Commander | | | - WIP | - Feature complete | + | | | | | | - Shell Module | + | | | | | | - BSIM test | + | | | | | | - Sample Application | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | HAP | Hearing Aid | 1.0 | 3.1 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Hearing Aid Unicast Client | 1.0 | 3.1 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Hearing Aid Remote Controller | | | - WIP | - Feature complete | + | | | | | | - Shell Module | + | | | | | | - BSIM test | + | | | | | | - Sample Application | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | TMAP | Call Gateway | 1.0 | 3.4 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Call Terminal | 1.0 | 3.4 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Unicast Media Sender | 1.0 | 3.4 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Unicast Media Receiver | 1.0 | 3.4 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Broadcast Media Sender | 1.0 | 3.4 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Broadcast Media Receiver | 1.0 | 3.4 | - 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 | | 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 | | 3.5 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Unicast Game Terminal | | 3.5 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Broadcast Game Sender | | 3.5 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | | | + | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + | | Broadcast Game Receiver | | 3.5 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | | | + +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ + Using the Bluetooth Audio Stack =============================== diff --git a/doc/connectivity/bluetooth/bluetooth-dev.rst b/doc/connectivity/bluetooth/bluetooth-dev.rst index dd3c2058c2cde93..865eb22d049f4d8 100644 --- a/doc/connectivity/bluetooth/bluetooth-dev.rst +++ b/doc/connectivity/bluetooth/bluetooth-dev.rst @@ -33,8 +33,8 @@ There are 4 possible hardware setups to use with Zephyr and Bluetooth: #. Embedded #. QEMU with an external Controller -#. Native POSIX with an external Controller -#. Simulated nRF52 with BabbleSim +#. :ref:`native_sim ` with an external Controller +#. Simulated nRF5x with BabbleSim Embedded ======== @@ -90,7 +90,7 @@ This setup relies on a "dual-chip" :ref:`configuration ` which is comprised of the following devices: #. A :ref:`Host-only ` application running in the - :ref:`QEMU ` emulator or the ``native_posix`` native + :ref:`QEMU ` emulator or the :ref:`native_sim ` native port of Zephyr #. A Controller, which can be one of the following types: @@ -117,52 +117,55 @@ QEMU You can run the Zephyr Host on the :ref:`QEMU emulator` and have it interact with a physical external Bluetooth Controller. -Refer to :ref:`bluetooth_qemu_posix` for full instructions on how to build and +Refer to :ref:`bluetooth_qemu_native` for full instructions on how to build and run an application in this setup. -Native POSIX ------------- +native_sim +---------- .. note:: This is currently only available on GNU/Linux -The :ref:`Native POSIX ` target builds your Zephyr application +The :ref:`native_sim ` target builds your Zephyr application with the Zephyr kernel, and some minimal HW emulation as a native Linux executable. This executable is a normal Linux program, which can be debugged and instrumented like any other, and it communicates with a physical or virtual external Controller. -Refer to :ref:`bluetooth_qemu_posix` for full instructions on how to build and +Refer to :ref:`bluetooth_qemu_native` for full instructions on how to build and run an application with a physical controller. For the virtual controller refer to :ref:`bluetooth_virtual_posix`. -Simulated nRF52 with BabbleSim +Simulated nRF5x with BabbleSim ============================== .. note:: This is currently only available on GNU/Linux -The :ref:`nrf52_bsim board `, is a simulated target board -which emulates the necessary peripherals of a nrf52 SOC to be able to develop +The :ref:`nrf52_bsim ` and :ref:`nrf5340bsim ` boards, +are simulated target boards +which emulate the necessary peripherals of a nRF52/53 SOC to be able to develop and test BLE applications. -This board, uses: +These boards, use: - * `BabbleSim`_ to simulate the nrf52 modem and the radio environment. - * The POSIX arch to emulate the processor. - * `Models of the nrf52 HW `_ + * `BabbleSim`_ to simulate the nRF5x modem and the radio environment. + * The POSIX arch and native simulator to emulate the processor, and run natively on your host. + * `Models of the nrf5x HW `_ -Just like with the ``native_posix`` target, the build result is a normal Linux +Just like with the :ref:`native_sim ` target, the build result is a normal Linux executable. You can find more information on how to run simulations with one or several -devices in -:ref:`this board's documentation ` +devices in either of :ref:`these boards's documentation `. -Currently, only :ref:`Combined builds +With the :ref:`nrf52_bsim `, only :ref:`Combined builds ` are possible, as this board does not yet have any models of a UART, or USB which could be used for an HCI interface towards another real or simulated device. +With the :ref:`nrf5340bsim `, you can build with either, both controller and host +on its network core, or, with the network core running only the controller, the application +core running the host and your application, and the HCI transport over IPC. Initialization ************** diff --git a/doc/connectivity/bluetooth/bluetooth-tools.rst b/doc/connectivity/bluetooth/bluetooth-tools.rst index 35453dd5f673ed6..9da5c5feb1ea3d2 100644 --- a/doc/connectivity/bluetooth/bluetooth-tools.rst +++ b/doc/connectivity/bluetooth/bluetooth-tools.rst @@ -74,13 +74,13 @@ Finally, reload and restart the daemon: sudo systemctl daemon-reload sudo systemctl restart bluetooth -.. _bluetooth_qemu_posix: +.. _bluetooth_qemu_native: -Running on QEMU and Native POSIX -******************************** +Running on QEMU or native_sim +***************************** It's possible to run Bluetooth applications using either the :ref:`QEMU -emulator` or :ref:`Native POSIX `. +emulator` or :ref:`native_sim `. In either case, a Bluetooth controller needs to be exported from the host OS (Linux) to the emulator. For this purpose you will need some tools described in the :ref:`bluetooth_bluez` section. @@ -94,14 +94,14 @@ The host OS's Bluetooth controller is connected in the following manner: with the help of the QEMU option :literal:`-serial unix:/tmp/bt-server-bredr`. This option gets passed to QEMU through :makevar:`QEMU_EXTRA_FLAGS` automatically whenever an application has enabled Bluetooth support. -* To a serial port in Native POSIX through the use of a command-line option - passed to the Native POSIX executable: ``--bt-dev=hci0`` +* To a serial port in :ref:`native_sim ` through the use of a command-line option + passed to the native_sim executable: ``--bt-dev=hci0`` On the host side, BlueZ allows you to export its Bluetooth controller -through a so-called user channel for QEMU and Native POSIX to use. +through a so-called user channel for QEMU and :ref:`native_sim ` to use. .. note:: - You only need to run ``btproxy`` when using QEMU. Native POSIX handles + You only need to run ``btproxy`` when using QEMU. native_sim handles the UNIX socket proxying automatically If you are using QEMU, in order to make the Controller available you will need @@ -142,12 +142,12 @@ building and running a sample: the :literal:`bt-server-bredr` UNIX socket, letting the application access the Bluetooth controller. -* To run a Bluetooth application in Native POSIX, first build it: +* To run a Bluetooth application in :ref:`native_sim `, first build it: .. zephyr-app-commands:: :zephyr-app: samples/bluetooth/ :host-os: unix - :board: native_posix + :board: native_sim :goals: build :compact: @@ -180,8 +180,8 @@ In order to see those logs, you can use the built-in ``btmon`` tool from BlueZ: .. _bluetooth_virtual_posix: -Running on a Virtual Controller and Native POSIX -************************************************* +Running on a Virtual Controller and native_sim +********************************************** An alternative to a Bluetooth physical controller is the use of a virtual controller. This controller can be connected over an HCI TCP server. @@ -212,7 +212,7 @@ To connect your application to the Android Emulator follow the next steps: #. Build your Zephyr application and disable the HCI ACL flow control (i.e. ``CONFIG_BT_HCI_ACL_FLOW_CONTROL=n``) as the - the virtual controller from android does not support it at the moment. + virtual controller from android does not support it at the moment. #. Install Android Emulator version >= 33.1.4.0. The easiest way to do this is by installing the latest `Android Studio Preview`_ version. diff --git a/doc/connectivity/bluetooth/img/cap_proc.svg b/doc/connectivity/bluetooth/img/cap_proc.svg index ef476096ad21ca9..70e56eebc25e852 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/bluetooth/overview.rst b/doc/connectivity/bluetooth/overview.rst index fece4ade4963f9a..1f727736b2de9c1 100644 --- a/doc/connectivity/bluetooth/overview.rst +++ b/doc/connectivity/bluetooth/overview.rst @@ -76,7 +76,7 @@ Bluetooth stack. * Non-volatile storage support for permanent storage of Bluetooth-specific settings and data - * Bluetooth mesh support + * Bluetooth Mesh support * Relay, Friend Node, Low-Power Node (LPN) and GATT Proxy features * Both Provisioning roles and bearers supported (PB-ADV & PB-GATT) diff --git a/doc/connectivity/canbus/index.rst b/doc/connectivity/canbus/index.rst new file mode 100644 index 000000000000000..78271d4181ea5ab --- /dev/null +++ b/doc/connectivity/canbus/index.rst @@ -0,0 +1,9 @@ +.. _canbus: + +Controller Area Network (CAN) Bus Protocols +########################################### + +.. toctree:: + :maxdepth: 2 + + isotp.rst diff --git a/doc/hardware/peripherals/canbus/isotp.rst b/doc/connectivity/canbus/isotp.rst similarity index 96% rename from doc/hardware/peripherals/canbus/isotp.rst rename to doc/connectivity/canbus/isotp.rst index 325a45cc0366c5e..4fea2c952322dfc 100644 --- a/doc/hardware/peripherals/canbus/isotp.rst +++ b/doc/connectivity/canbus/isotp.rst @@ -18,7 +18,7 @@ over Controller Area Networks. Nevertheless, it's not limited to applications in road vehicles or the automotive domain. This transport protocol extends the limited payload data size for classical -CAN (8 bytes) and CAN-FD (64 bytes) to theoretically four gigabytes. +CAN (8 bytes) and CAN FD (64 bytes) to theoretically four gigabytes. Additionally, it adds a flow control mechanism to influence the sender's behavior. ISO-TP segments packets into small fragments depending on the payload size of the CAN frame. The header of those segments is called Protocol Control diff --git a/doc/hardware/peripherals/canbus/isotp_sequence.svg b/doc/connectivity/canbus/isotp_sequence.svg similarity index 100% rename from doc/hardware/peripherals/canbus/isotp_sequence.svg rename to doc/connectivity/canbus/isotp_sequence.svg diff --git a/doc/connectivity/index.rst b/doc/connectivity/index.rst index c135ed410bb109b..be81417d0ba6daa 100644 --- a/doc/connectivity/index.rst +++ b/doc/connectivity/index.rst @@ -7,6 +7,7 @@ Connectivity :maxdepth: 1 bluetooth/index.rst + canbus/index.rst networking/index.rst lora_lorawan/index.rst usb/index.rst diff --git a/doc/connectivity/networking/api/coap.rst b/doc/connectivity/networking/api/coap.rst index 4f0654a57d4c8ea..e3a4d01d594bb55 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. @@ -28,8 +29,6 @@ See :ref:`lwm2m_interface` for more information. Supported RFCs: -Supported RFCs: - - `RFC7252: The Constrained Application Protocol (CoAP) `_ - `RFC6690: Constrained RESTful Environments (CoRE) Link Format `_ - `RFC7959: Block-Wise Transfers in the Constrained Application Protocol (CoAP) `_ @@ -43,6 +42,11 @@ Sample Usage CoAP Server =========== +.. note:: + + A :ref:`coap_server_interface` subsystem is available, the following is for creating a custom + server implementation. + To create a CoAP server, resources for the server need to be defined. The ``.well-known/core`` resource should be added before all other resources that should be included in the responses of the ``.well-known/core`` @@ -97,6 +101,11 @@ with resource path like '/some_resource/+/#'. CoAP Client =========== +.. note:: + + A :ref:`coap_client_interface` subsystem is available, the following is for creating a custom + client implementation. + If the CoAP client knows about resources in the CoAP server, the client can start prepare CoAP requests and wait for responses. If the client doesn't know about resources in the CoAP server, it can request resources through diff --git a/doc/connectivity/networking/api/coap_client.rst b/doc/connectivity/networking/api/coap_client.rst index 2251bb3d0da6ffe..0d682a047465b22 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 new file mode 100644 index 000000000000000..1666880f2fc26f0 --- /dev/null +++ b/doc/connectivity/networking/api/coap_server.rst @@ -0,0 +1,284 @@ +.. _coap_server_interface: + +CoAP server +########### + +.. contents:: + :local: + :depth: 2 + +Overview +******** + +Zephyr comes with a batteries-included CoAP server, which uses services to listen for CoAP +requests. The CoAP services handle communication over sockets and pass requests to registered +CoAP resources. + +Setup +***** + +Some configuration is required to make sure services can be started using the CoAP server. The +:kconfig:option:`CONFIG_COAP_SERVER` option should be enabled in your project: + +.. code-block:: cfg + :caption: ``prj.conf`` + + CONFIG_COAP_SERVER=y + +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 with ``coap_resource_`` and added to a linker file: + +.. code-block:: c + :caption: ``sections-ram.ld`` + + #include + + ITERABLE_SECTION_RAM(coap_resource_my_service, 4) + +Add this linker file to your application using CMake: + +.. code-block:: cmake + :caption: ``CMakeLists.txt`` + + zephyr_linker_sources(DATA_SECTIONS sections-ram.ld) + +You can now define your service as part of the application: + +.. code-block:: c + + #include + + static const uint16_t my_service_port = 5683; + + COAP_SERVICE_DEFINE(my_service, "0.0.0.0", &my_service_port, COAP_SERVICE_AUTOSTART); + +.. note:: + + Services defined with the ``COAP_SERVICE_AUTOSTART`` flag will be started together with the CoAP + server thread. Services can be manually started and stopped with ``coap_service_start`` and + ``coap_service_stop`` respectively. + +Sample Usage +************ + +The following is an example of a CoAP resource registered with our service: + +.. code-block:: c + + #include + + static int my_get(struct coap_resource *resource, struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) + { + static const char *msg = "Hello, world!"; + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + uint16_t id; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint8_t tkl, type; + + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + /* Determine response type */ + type = (type == COAP_TYPE_CON) ? COAP_TYPE_ACK : COAP_TYPE_NON_CON; + + coap_packet_init(&response, data, sizeof(data), COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + + /* Set content format */ + coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, + COAP_CONTENT_FORMAT_TEXT_PLAIN); + + /* Append payload */ + coap_packet_append_payload_marker(&response); + coap_packet_append_payload(&response, (uint8_t *)msg, sizeof(msg)); + + /* Send to response back to the client */ + return coap_resource_send(resource, &response, addr, addr_len, NULL); + } + + static int my_put(struct coap_resource *resource, struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) + { + /* ... Handle the incoming request ... */ + + /* Return a CoAP response code as a shortcut for an empty ACK message */ + return COAP_RESPONSE_CODE_CHANGED; + } + + static const char * const my_resource_path[] = { "test", NULL }; + COAP_RESOURCE_DEFINE(my_resource, my_service, { + .path = my_resource_path, + .get = my_get, + .put = my_put, + }); + +.. note:: + + As demonstrated in the example above, a CoAP resource handler can return response codes to let + the server respond with an empty ACK response. + +Observable resources +******************** + +The CoAP server provides logic for parsing observe requests and stores these using the runtime data +of CoAP services. An example using a temperature sensor can look like: + +.. code-block:: c + + #include + #include + #include + + static void notify_observers(struct k_work *work); + K_WORK_DELAYABLE_DEFINE(temp_work, notify_observers); + + 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, + bool is_response) + { + const struct device *dev = DEVICE_DT_GET(DT_ALIAS(ambient_temp0)); + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + char payload[14]; + struct sensor_value value; + double temp; + uint8_t type; + + /* Determine response type */ + type = is_response ? COAP_TYPE_ACK : COAP_TYPE_CON; + + if (!is_response) { + id = coap_next_id(); + } + + coap_packet_init(&response, data, sizeof(data), COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + + if (age >= 2U) { + coap_append_option_int(&response, COAP_OPTION_OBSERVE, age); + } + + /* Set content format */ + coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, + COAP_CONTENT_FORMAT_TEXT_PLAIN); + + /* Get the sensor date */ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_AMBIENT_TEMP); + sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &value); + temp = sensor_value_to_double(&value); + + snprintk(payload, sizeof(payload), "%0.2f°C", temp); + + /* Append payload */ + coap_packet_append_payload_marker(&response); + coap_packet_append_payload(&response, (uint8_t *)payload, strlen(payload)); + + return coap_resource_send(resource, &response, addr, addr_len, NULL); + } + + static int temp_get(struct coap_resource *resource, struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) + { + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint8_t tkl; + int r; + + /* Let the CoAP server parse the request and add/remove observers if needed */ + r = coap_resource_parse_observe(resource, request, addr); + + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + return send_temperature(resource, addr, addr_len, r == 0 ? resource->age : 0, + id, token, tkl, true); + } + + static void temp_notify(struct coap_resource *resource, struct coap_observer *observer) + { + send_temperature(resource, &observer->addr, sizeof(observer->addr), resource->age, 0, + observer->token, observer->tkl, false); + } + + static const char * const temp_resource_path[] = { "sensors", "temp1", NULL }; + COAP_RESOURCE_DEFINE(temp_resource, my_service, { + .path = temp_resource_path, + .get = temp_get, + .notify = temp_notify, + }); + + static void notify_observers(struct k_work *work) + { + if (sys_slist_is_empty(&temp_resource.observers)) { + return; + } + + coap_resource_notify(&temp_resource); + 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 +**************** + +The :kconfig:option:`CONFIG_COAP_SERVER_WELL_KNOWN_CORE` option enables handling the +``.well-known/core`` GET requests by the server. This allows clients to get a list of hypermedia +links to other resources hosted in that server. + +API Reference +************* + +.. doxygengroup:: coap_service +.. doxygengroup:: coap_mgmt diff --git a/doc/connectivity/networking/api/gptp.rst b/doc/connectivity/networking/api/gptp.rst index 12dedeaab0b4eec..58788ee003d63b4 100644 --- a/doc/connectivity/networking/api/gptp.rst +++ b/doc/connectivity/networking/api/gptp.rst @@ -40,7 +40,7 @@ Boards supported: - :ref:`nucleo_h745zi_q_board` - :ref:`nucleo_f767zi_board` - :ref:`sam_e70_xplained` -- :ref:`native_posix` (only usable for simple testing, limited capabilities +- :ref:`native_sim` (only usable for simple testing, limited capabilities due to lack of hardware clock) - :ref:`qemu_x86` (emulated, limited capabilities due to lack of hardware clock) diff --git a/doc/connectivity/networking/api/http.rst b/doc/connectivity/networking/api/http.rst index 060a41643d9a056..d32748e77fae5be 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 b367a17dbeee312..000000000000000 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 000000000000000..c9da075b2a3686d --- /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/images/lwm2m_lifetime_both.png b/doc/connectivity/networking/api/images/lwm2m_lifetime_both.png new file mode 100644 index 000000000000000..1cdf0bbb662965d Binary files /dev/null and b/doc/connectivity/networking/api/images/lwm2m_lifetime_both.png differ diff --git a/doc/connectivity/networking/api/images/lwm2m_lifetime_seconds_early.png b/doc/connectivity/networking/api/images/lwm2m_lifetime_seconds_early.png new file mode 100644 index 000000000000000..119005ce5c7f0ea Binary files /dev/null and b/doc/connectivity/networking/api/images/lwm2m_lifetime_seconds_early.png differ diff --git a/doc/connectivity/networking/api/index.rst b/doc/connectivity/networking/api/index.rst index 2386a075460f0c3..1264ff2aafb9d8d 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 ce6cafd53a7472e..8aab68e54caa590 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; } } @@ -404,6 +409,11 @@ NoSec In all modes, Server URI resource (ID 0) must contain the full URI for the target server. When DNS names are used, the DNS resolver must be enabled. +When DTLS is used, following options are recommended to reduce DTLS handshake traffic when connection is re-established: + +* :kconfig:option:`CONFIG_LWM2M_DTLS_CID` enables DTLS Connection Identifier support. When server supports it, this completely removes the handshake when device resumes operation after long idle period. Greatly helps when NAT mappings have timed out. +* :kconfig:option:`CONFIG_LWM2M_TLS_SESSION_CACHING` uses session cache when before falling back to full DTLS handshake. Reduces few packets from handshake, when session is still cached on server side. Most significant effect is to avoid full registration. + LwM2M stack provides callbacks in the :c:struct:`lwm2m_ctx` structure. They are used to feed keys from the LwM2M security object into the TLS credential subsystem. By default, these callbacks can be left as NULL pointers, in which case default callbacks are used. @@ -440,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 @@ -478,7 +488,7 @@ Support for time series data LwM2M version 1.1 adds support for SenML CBOR and SenML JSON data formats. These data formats add support for time series data. Time series formats can be used for READ, NOTIFY and SEND operations. When data cache is enabled for a resource, each write will create a timestamped entry in a cache, -and its content is then returned as a content in in READ, NOTIFY or SEND operation for a given +and its content is then returned as a content in READ, NOTIFY or SEND operation for a given resource. Data cache is only supported for resources with a fixed data size. @@ -540,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 @@ -552,78 +562,162 @@ 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 +**************************************** + +In LwM2M engine, there are three Kconfig options and one runtime value that configures how often the +client will send LwM2M Update message. + +.. list-table:: Update period variables + :widths: auto + :header-rows: 1 + + * - Variable + - Effect + * - LwM2M registration lifetime + - The lifetime parameter in LwM2M specifies how long a device's registration with an LwM2M server remains valid. + Device is expected to send LwM2M Update message before the lifetime exprires. + * - :kconfig:option:`CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME` + - Default lifetime value, unless set by the bootstrap server. + Also defines lower limit that client accepts as a lifetime. + * - :kconfig:option:`CONFIG_LWM2M_UPDATE_PERIOD` + - How long the client can stay idle before sending a next update. + * - :kconfig:option:`CONFIG_LWM2M_SECONDS_TO_UPDATE_EARLY` + - Minimum time margin to send the update message before the registration lifetime expires. + +.. figure:: images/lwm2m_lifetime_seconds_early.png + :alt: LwM2M seconds to update early + + Default way of calculating when to update registration. + +By default, the client uses :kconfig:option:`CONFIG_LWM2M_SECONDS_TO_UPDATE_EARLY` to calculate how +many seconds before the expiration of lifetime it is going to send the registration update. +The problem with default mode is when the server changes the lifetime of the registration. +This is then affecting the period of updates the client is doing. +If this is used with the QUEUE mode, which is typical in IPv4 networks, it is also affecting the +period of when the device is reachable from the server. + +.. figure:: images/lwm2m_lifetime_both.png + :alt: LwM2M update time when both values are set + + Update time is controlled by UPDATE_PERIOD. + +When also the :kconfig:option:`CONFIG_LWM2M_UPDATE_PERIOD` is set, time to send the update message +is the earliest when any of these values expire. This allows setting long lifetime for the +registration and configure the period accurately, even if server changes the lifetime parameter. + +In runtime, the update frequency is limited to once in 15 seconds to avoid flooding. .. _lwm2m_shell: @@ -670,7 +764,10 @@ required actions from the server side. -t Write value as time_t create :create PATH - Create object instance + Create object or resource instance + + delete :delete PATH + Delete object or resource instance cache :cache PATH NUM Enable data cache for resource diff --git a/doc/connectivity/networking/api/mqtt.rst b/doc/connectivity/networking/api/mqtt.rst index 973b61860e35ca3..b232f125333d9b5 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 3da4d903725f9dc..3235725f2e39213 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 ed6c512a742ebf2..2973ee82b0410fb 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/net_shell.rst b/doc/connectivity/networking/api/net_shell.rst index cf51291d0c91e10..710b544eb7bdaed 100644 --- a/doc/connectivity/networking/api/net_shell.rst +++ b/doc/connectivity/networking/api/net_shell.rst @@ -38,6 +38,9 @@ The following net-shell commands are implemented: "net ping", "Ping a network host." "net route", "Show IPv6 network routes. Only available if :kconfig:option:`CONFIG_NET_ROUTE` is set." + "net sockets", "Show network socket information and statistics. Only available if + :kconfig:option:`CONFIG_NET_SOCKETS_OBJ_CORE` and :kconfig:option:`CONFIG_OBJ_CORE` + are set." "net stats", "Show network statistics." "net tcp", "Connect/send data/close TCP connection. Only available if :kconfig:option:`CONFIG_NET_TCP` is set." diff --git a/doc/connectivity/networking/api/ppp.rst b/doc/connectivity/networking/api/ppp.rst index d0028a075aae394..74e2da248f7fdf4 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/protocols.rst b/doc/connectivity/networking/api/protocols.rst index 8f2bc2af3d5a58c..aea485b74aa6d03 100644 --- a/doc/connectivity/networking/api/protocols.rst +++ b/doc/connectivity/networking/api/protocols.rst @@ -9,6 +9,7 @@ Protocols coap coap_client + coap_server http lwm2m mqtt diff --git a/doc/connectivity/networking/api/sockets.rst b/doc/connectivity/networking/api/sockets.rst index 3f632e3bea93e3a..5ea4429cf1355b6 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 @@ -73,6 +77,8 @@ To enable secure sockets, set the :kconfig:option:`CONFIG_NET_SOCKETS_SOCKOPT_TL option. To enable DTLS support, use :kconfig:option:`CONFIG_NET_SOCKETS_ENABLE_DTLS` option. +.. _sockets_tls_credentials_subsys: + TLS credentials subsystem ========================= @@ -155,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/system_mgmt.rst b/doc/connectivity/networking/api/system_mgmt.rst index 59aab16d3b72dfc..a09ed2b2787f279 100644 --- a/doc/connectivity/networking/api/system_mgmt.rst +++ b/doc/connectivity/networking/api/system_mgmt.rst @@ -18,3 +18,4 @@ Network System Management traffic-class.rst net_pkt_filter.rst net_shell.rst + tls_credentials_shell.rst diff --git a/doc/connectivity/networking/api/tftp.rst b/doc/connectivity/networking/api/tftp.rst index 36d9d2cf0bba4e6..6bb309e07917c79 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 new file mode 100644 index 000000000000000..76c074ae67d0eed --- /dev/null +++ b/doc/connectivity/networking/api/tls_credentials_shell.rst @@ -0,0 +1,259 @@ +.. _tls_credentials_shell: + +TLS Credentials Shell +##################### + +The TLS Credentials shell provides a command-line interface for managing installed TLS credentials. + +Commands +******** + +.. _tls_credentials_shell_buf_cred: + +Buffer Credential (``buf``) +=========================== + +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. + +Usage +----- + +To append ```` to the credential buffer, use: + +.. code-block:: shell + + cred buf + +Use this as many times as needed to load the full credential into the credential buffer, then use the :ref:`tls_credentials_shell_add_cred` command to store it. + +To clear the credential buffer, use: + +.. code-block:: shell + + cred buf clear + +Arguments +--------- + +.. csv-table:: + :header: "Argument", "Description" + :widths: 15 85 + + "````", "Text data to be appended to credential buffer. It can be either text, or base64-encoded binary. See :ref:`tls_credentials_shell_add_cred` and :ref:`tls_credentials_shell_data_formats` for details." + +.. _tls_credentials_shell_add_cred: + +Add Credential (``add``) +========================= + +Add a TLS credential to the TLS Credential store. + +Credential contents can be provided in-line with the call to ``cred add``, or will otherwise be sourced from the credential buffer. + +Usage +----- + +To add a TLS credential using the data from the credential buffer, use: + +.. code-block:: shell + + cred add + +To add a TLS credential using data provided with the same command, use: + +.. code-block:: shell + + cred add + + +Arguments +--------- + +.. csv-table:: + :header: "Argument", "Description" + :widths: 15 85 + + "````", "The sectag to use for the new credential. Can be any non-negative integer." + "````", "The type of credential to add. See :ref:`tls_credentials_shell_cred_types` for valid values." + "````", "Reserved. Must always be ``DEFAULT`` (case-insensitive)." + "````", "Specifies the storage format of the provided credential. See :ref:`tls_credentials_shell_data_formats` for valid values." + "````", "If provided, this argument will be used as the credential data, instead of any data in the credential buffer. Can be either text, or base64-encoded binary." + +.. _tls_credentials_shell_del_cred: + +Delete Credential (``del``) +=========================== + +Delete a specified credential from the credential store. + +Usage +----- + +To delete a credential matching a specified sectag and credential type (if it exists), use: + +.. code-block:: shell + + cred del + +Arguments +--------- + +.. csv-table:: + :header: "Argument", "Description" + :widths: 15 85 + + "````", "The sectag of the credential to delete. Can be any non-negative integer." + "````", "The type of credential to delete. See :ref:`tls_credentials_shell_cred_types` for valid values." + +.. _tls_credentials_shell_get_cred: + +Get Credential Contents (``get``) +================================= + +Retrieve and print the contents of a specified credential. + +Usage +----- + +To retrieve and print a credential matching a specified sectag and credential type (if it exists), use: + +.. code-block:: shell + + cred get + +Arguments +--------- + +.. csv-table:: + :header: "Argument", "Description" + :widths: 15 85 + + "````", "The sectag of the credential to get. Can be any non-negative integer." + "````", "The type of credential to get. See :ref:`tls_credentials_shell_cred_types` for valid values." + "````", "Specifies the retrieval format for the provided credential. See :ref:`tls_credentials_shell_data_formats` for valid values." + +.. _tls_credentials_shell_list_cred: + +List Credentials (``list``) +=========================== + +List TLS credentials in the credential store. + +Usage +----- + +To list all available credentials, use: + +.. code-block:: shell + + cred list + +To list all credentials with a specified sectag, use: + +.. code-block:: shell + + cred list + +To list all credentials with a specified credential type, use: + +.. code-block:: shell + + cred list any + +To list all credentials with a specified credential type and sectag, use: + +.. code-block:: shell + + cred list + + +Arguments +--------- + +.. csv-table:: + :header: "Argument", "Description" + :widths: 15 85 + + "````", "Optional. If provided, only list credentials with this sectag. Pass ``any`` or omit to allow any sectag. Otherwise, can be any non-negative integer." + "````", "Optional. If provided, only list credentials with this credential type. Pass ``any`` or omit to allow any credential type. Otherwise, see :ref:`tls_credentials_shell_cred_types` for valid values." + + +Output +------ + +The command outputs all matching credentials in the following (CSV-compliant) format: + +.. code-block:: shell + + ,,, + +Where: + +.. csv-table:: + :header: "Symbol", "Value" + :widths: 15 85 + + "````", "The sectag of the listed credential. A non-negative integer." + "````", "Credential type short-code (see :ref:`tls_credentials_shell_cred_types` for details) of the listed credential." + "````", "A string digest representing the credential contents. The exact nature of this digest may vary depending on credentials storage backend, but currently for all backends this is a base64 encoded SHA256 hash of the raw credential contents (so different storage formats for essentially identical credentials will have different digests)." + "````", "Status code indicating success or failure with generating a digest of the listed credential. 0 if successful, negative error code specific to the storage backend otherwise. Lines for which status is not zero will be printed with error formatting." + +After the list is printed, a final summary of the found credentials will be printed in the form: + +.. code-block:: shell + + credentials found. + +Where `` is the number of credentials found, and is zero if none are found. + +.. _tls_credentials_shell_cred_types: + +Credential Types +**************** + +The following keywords (case-insensitive) may be used to specify a credential type: + +.. csv-table:: + :header: "Keyword(s)", "Meaning" + :widths: 15 85 + + "``CA_CERT``, ``CA``", "A trusted CA certificate." + "``SERVER_CERT``, ``SELF_CERT``, ``CLIENT_CERT``, ``CLIENT``, ``SELF``, ``SERV``", "Self or server certificate." + "``PRIVATE_KEY``, ``PK``", "A private key." + "``PRE_SHARED_KEY``, ``PSK``", "A pre-shared key." + "``PRE_SHARED_KEY_ID``, ``PSK_ID``", "ID for pre-shared key." + +.. _tls_credentials_shell_data_formats: + +Storage/Retrieval Formats +************************* + +The :ref:`tls_credentials ` module treats stored credentials as arbitrary binary buffers. + +For convenience, the TLS credentials shell offers four formats for providing and later retrieving these buffers using the shell. + +These formats and their (case-insensitive) keywords are as follows: + +.. csv-table:: + :header: "Keyword", "Meaning", "Behavior during storage (``cred add``)", "Behavior during retrieval (``cred get``)" + :widths: 3, 32, 34, 34 + + "``BIN``", "Credential is handled by shell as base64 and stored without NULL termination.", "Data entered into shell will be decoded from base64 into raw binary before storage. No terminator will be appended.", "Stored data will be encoded into base64 before being printed." + "``BINT``", "Credential is handled by shell as base64 and stored with NULL termination.", "Data entered into shell will be decoded from base64 into raw binary and a NULL terminator will be appended before storage.", "NULL terminator will be truncated from stored data before said data is encoded into base64 and then printed." + "``STR``", "Credential is handled by shell as literal string and stored without NULL termination.", "Text data entered into shell will be passed into storage as-written, without a NULL terminator.", "Stored data will be printed as text. Non-printable characters will be printed as ``?``" + "``STRT``", "Credential is handled by shell as literal string and stored with NULL-termination.", "Text data entered into shell will be passed into storage as-written, with a NULL terminator.", "NULL terminator will be truncated from stored data before said data is printed as text. Non-printable characters will be printed as ``?``" + +The ``BIN`` format can be used to install credentials of any type, since base64 can be used to encode any concievable binary buffer. +The remaining three formats are provided for convenience in special use-cases. + +For example: + +- To install printable pre-shared-keys, use ``STR`` to enter the PSK without first encoding it. + This ensures it is stored without a NULL terminator. +- To install DER-formatted X.509 certificates (or other raw-binary credentials, such as non-printable PSKs) base64-encode the binary and use the ``BIN`` format. +- To install PEM-formatted X.509 certificates or certificate chains, base64 encode the full PEM string (including new-lines and ``----BEGIN X ----`` / ``----END X----`` markers), and then use the ``BINT`` format to make sure the stored string is NULL-terminated. + This is required because Zephyr does not support multi-line strings in the shell. + Otherwise, the ``STRT`` format could be used for this purpose without base64 encoding. + It is possible to use ``BIN`` instead if you manually encode a NULL terminator into the base64. diff --git a/doc/connectivity/networking/api/websocket.rst b/doc/connectivity/networking/api/websocket.rst index f803e7b2ef878c9..b1450ae8f90ad4f 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 932ec7668d22270..f598d571d5edbca 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 4bde856f0ce01d4..fd7a8bf87eec54c 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. @@ -421,7 +421,7 @@ There are a few actions related to connectivity that are (by default at least) p By default, Connection Manager will automatically take any bound iface admin-down if it has given up on associating. - Applications can disable this for all ifaces by disabling the :kconfig:option:`CONFIG_NET_CONNECTION_MANAGER_AUTO_IF_DOWN` Kconfig option, or for individual ifaces by setting the :c:enumerator:`~conn_mgr_if_flag.CONN_MGR_IF_NO_AUTO_DOWN` connectivity flag with with :c:func:`conn_mgr_if_set_flag`. + Applications can disable this for all ifaces by disabling the :kconfig:option:`CONFIG_NET_CONNECTION_MANAGER_AUTO_IF_DOWN` Kconfig option, or for individual ifaces by setting the :c:enumerator:`~conn_mgr_if_flag.CONN_MGR_IF_NO_AUTO_DOWN` connectivity flag with :c:func:`conn_mgr_if_set_flag`. .. _conn_mgr_control_api: diff --git a/doc/connectivity/networking/index.rst b/doc/connectivity/networking/index.rst index f900bb563304111..26dfbb141472970 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/native_posix_setup.rst b/doc/connectivity/networking/native_posix_setup.rst deleted file mode 100644 index cc94c9f790bc367..000000000000000 --- a/doc/connectivity/networking/native_posix_setup.rst +++ /dev/null @@ -1,91 +0,0 @@ -.. _networking_with_native_posix: - -Networking with native_posix board -################################## - -.. contents:: - :local: - :depth: 2 - -This page describes how to set up a virtual network between a (Linux) host -and a Zephyr application running in a native_posix board. - -In this example, the :zephyr:code-sample:`sockets-echo-server` sample application from -the Zephyr source distribution is run in native_posix board. The Zephyr -native_posix board instance is connected to a Linux host using a tuntap device -which is modeled in Linux as an Ethernet network interface. - -Prerequisites -************* - -On the Linux Host, fetch the Zephyr ``net-tools`` project, which is located -in a separate Git repository: - -.. code-block:: console - - git clone https://github.com/zephyrproject-rtos/net-tools - - -Basic Setup -*********** - -For the steps below, you will need three terminal windows: - -* Terminal #1 is terminal window with net-tools being the current - directory (``cd net-tools``) -* Terminal #2 is your usual Zephyr development terminal, - with the Zephyr environment initialized. -* Terminal #3 is the console to the running Zephyr native_posix - instance (optional). - -Step 1 - Create Ethernet interface -================================== - -Before starting native_posix with network emulation, a network interface -should be created. - -In terminal #1, type: - -.. code-block:: console - - ./net-setup.sh - -You can tweak the behavior of the net-setup.sh script. See various options -by running ``net-setup.sh`` like this: - -.. code-block:: console - - ./net-setup.sh --help - - -Step 2 - Start app in native_posix board -======================================== - -Build and start the ``echo_server`` sample application. - -In terminal #2, type: - -.. zephyr-app-commands:: - :zephyr-app: samples/net/sockets/echo_server - :host-os: unix - :board: native_posix - :goals: run - :compact: - - -Step 3 - Connect to console (optional) -====================================== - -The console window should be launched automatically when the Zephyr instance is -started but if it does not show up, you can manually connect to the console. -The native_posix board will print a string like this when it starts: - -.. code-block:: console - - UART connected to pseudotty: /dev/pts/5 - -You can manually connect to it like this: - -.. code-block:: console - - screen /dev/pts/5 diff --git a/doc/connectivity/networking/native_sim_setup.rst b/doc/connectivity/networking/native_sim_setup.rst new file mode 100644 index 000000000000000..166ff707c899e88 --- /dev/null +++ b/doc/connectivity/networking/native_sim_setup.rst @@ -0,0 +1,91 @@ +.. _networking_with_native_sim: + +Networking with native_sim board +################################ + +.. contents:: + :local: + :depth: 2 + +This page describes how to set up a virtual network between a (Linux) host +and a Zephyr application running in a :ref:`native_sim ` board. + +In this example, the :zephyr:code-sample:`sockets-echo-server` sample application from +the Zephyr source distribution is run in native_sim board. The Zephyr +native_sim board instance is connected to a Linux host using a tuntap device +which is modeled in Linux as an Ethernet network interface. + +Prerequisites +************* + +On the Linux Host, fetch the Zephyr ``net-tools`` project, which is located +in a separate Git repository: + +.. code-block:: console + + git clone https://github.com/zephyrproject-rtos/net-tools + + +Basic Setup +*********** + +For the steps below, you will need three terminal windows: + +* Terminal #1 is terminal window with net-tools being the current + directory (``cd net-tools``) +* Terminal #2 is your usual Zephyr development terminal, + with the Zephyr environment initialized. +* Terminal #3 is the console to the running Zephyr native_sim + instance (optional). + +Step 1 - Create Ethernet interface +================================== + +Before starting native_sim with network emulation, a network interface +should be created. + +In terminal #1, type: + +.. code-block:: console + + ./net-setup.sh + +You can tweak the behavior of the net-setup.sh script. See various options +by running ``net-setup.sh`` like this: + +.. code-block:: console + + ./net-setup.sh --help + + +Step 2 - Start app in native_sim board +====================================== + +Build and start the ``echo_server`` sample application. + +In terminal #2, type: + +.. zephyr-app-commands:: + :zephyr-app: samples/net/sockets/echo_server + :host-os: unix + :board: native_sim + :goals: run + :compact: + + +Step 3 - Connect to console (optional) +====================================== + +The console window should be launched automatically when the Zephyr instance is +started but if it does not show up, you can manually connect to the console. +The native_sim board will print a string like this when it starts: + +.. code-block:: console + + UART connected to pseudotty: /dev/pts/5 + +You can manually connect to it like this: + +.. code-block:: console + + screen /dev/pts/5 diff --git a/doc/connectivity/networking/net_config_guide.rst b/doc/connectivity/networking/net_config_guide.rst new file mode 100644 index 000000000000000..b83417449796c64 --- /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/network_monitoring.rst b/doc/connectivity/networking/network_monitoring.rst index b0a20b287d08397..a5f2dcfee7140a6 100644 --- a/doc/connectivity/networking/network_monitoring.rst +++ b/doc/connectivity/networking/network_monitoring.rst @@ -104,7 +104,7 @@ need to terminate the network connection like this. Zephyr Configuration ******************** -In this example, we use ``native_posix`` board. You can also use any other board +In this example, we use the ``native_sim`` board. You can also use any other board that supports networking. In terminal #3, type: @@ -112,7 +112,7 @@ In terminal #3, type: .. zephyr-app-commands:: :zephyr-app: samples/net/capture :host-os: unix - :board: native_posix + :board: native_sim :gen-args: -DCONFIG_NATIVE_UART_AUTOATTACH_DEFAULT_CMD=\""gnome-terminal -- screen %s"\" :goals: build :compact: @@ -189,7 +189,7 @@ Then we need to enable the network packet monitoring like this: net capture enable 2 The ``2`` tells the network interface which traffic we want to capture. In -this example, the ``2`` is the ``native_posix`` board Ethernet interface. +this example, the ``2`` is the ``native_sim`` board Ethernet interface. Note that we send the network traffic to the same interface that we are monitoring in this example. The monitoring system avoids to capture already captured network traffic as that would lead to recursion. diff --git a/doc/connectivity/networking/networking-api-usage.rst b/doc/connectivity/networking/networking-api-usage.rst deleted file mode 100644 index 0145482fec9bd81..000000000000000 --- 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/networking/networking_with_host.rst b/doc/connectivity/networking/networking_with_host.rst index 063e065730aaa7a..995e7dc0f801a4b 100644 --- a/doc/connectivity/networking/networking_with_host.rst +++ b/doc/connectivity/networking/networking_with_host.rst @@ -7,7 +7,7 @@ Networking with the host system :maxdepth: 1 :hidden: - native_posix_setup.rst + native_sim_setup.rst qemu_eth_setup.rst qemu_setup.rst usbnet_setup.rst @@ -53,14 +53,14 @@ possible: the host on which the model is running. See :ref:`networking_with_armfvp` for details. -* native_posix board. +* native_sim board. * The Zephyr instance can be executed as a user space process in the host system. This is the most convenient way to debug the Zephyr system as one can attach host debugger directly to the running Zephyr instance. This requires that there is an adaptation driver in Zephyr for interfacing with the host system. An Ethernet driver exists in Zephyr for this purpose. - See :ref:`networking_with_native_posix` for details. + See :ref:`networking_with_native_sim` for details. * USB device networking. @@ -70,7 +70,7 @@ possible: * Connecting multiple Zephyr instances together. - * If you have multiple Zephyr instances, either QEMU or native_posix ones, + * If you have multiple Zephyr instances, either QEMU or native_sim ones, and want to create a connection between them, see :ref:`networking_with_multiple_instances` for details. diff --git a/doc/connectivity/networking/networking_with_multiple_instances.rst b/doc/connectivity/networking/networking_with_multiple_instances.rst index c83f7e04ed6554e..6489db455514652 100644 --- a/doc/connectivity/networking/networking_with_multiple_instances.rst +++ b/doc/connectivity/networking/networking_with_multiple_instances.rst @@ -9,7 +9,7 @@ Networking with multiple Zephyr instances This page describes how to set up a virtual network between multiple Zephyr instances. The Zephyr instances could be running inside QEMU -or could be native_posix board processes. The Linux host can be used +or could be native_sim board processes. The Linux host can be used to route network traffic between these systems. Prerequisites @@ -34,10 +34,10 @@ For the steps below, you will need five terminal windows: with the Zephyr environment initialized. As there are multiple ways to setup the Zephyr network, the example below uses -``qemu_x86`` board with ``e1000`` Ethernet controller and native_posix board +``qemu_x86`` board with ``e1000`` Ethernet controller and native_sim board to simplify the setup instructions. You can use other QEMU boards and drivers if needed, see :ref:`networking_with_eth_qemu` for details. You can also use -two or more native_posix board Zephyr instances and connect them together. +two or more native_sim board Zephyr instances and connect them together. Step 1 - Create configuration files @@ -141,11 +141,11 @@ In terminal #4, if you are using QEMU, type this: -DCONFIG_ETH_QEMU_IFACE_NAME=\"zeth.1\" \ -DCONFIG_ETH_QEMU_EXTRA_ARGS=\"mac=00:00:5e:00:53:01\" -or if you want to use native_posix board, type this: +or if you want to use native_sim board, type this: .. code-block:: console - west build -d build/server -b native_posix -t run \ + west build -d build/server -b native_sim -t run \ samples/net/sockets/echo_server -- \ -DCONFIG_NET_CONFIG_MY_IPV4_ADDR=\"198.51.100.1\" \ -DCONFIG_NET_CONFIG_PEER_IPV4_ADDR=\"203.0.113.1\" \ @@ -172,11 +172,11 @@ In terminal #5, if you are using QEMU, type this: -DCONFIG_ETH_QEMU_IFACE_NAME=\"zeth.2\" \ -DCONFIG_ETH_QEMU_EXTRA_ARGS=\"mac=00:00:5e:00:53:02\" -or if you want to use native_posix board, type this: +or if you want to use native_sim board, type this: .. code-block:: console - west build -d build/client -b native_posix -t run \ + west build -d build/client -b native_sim -t run \ samples/net/sockets/echo_client -- \ -DCONFIG_NET_CONFIG_MY_IPV4_ADDR=\"203.0.113.1\" \ -DCONFIG_NET_CONFIG_PEER_IPV4_ADDR=\"198.51.100.1\" \ diff --git a/doc/connectivity/networking/overview.rst b/doc/connectivity/networking/overview.rst index f271bcd8a8c3089..c1de9a1ab674992 100644 --- a/doc/connectivity/networking/overview.rst +++ b/doc/connectivity/networking/overview.rst @@ -56,7 +56,7 @@ can be disabled if not needed. * **TCP** Transmission Control Protocol (`RFC 793 `_) is supported. Both server - and client roles can be used the the application. The amount of TCP sockets + and client roles can be used the application. The amount of TCP sockets that are available to applications can be configured at build time. * **BSD Sockets API** Support for a subset of a diff --git a/doc/connectivity/usb/device/usb_device.rst b/doc/connectivity/usb/device/usb_device.rst index 5e394a20457afab..134ec5972cddf74 100644 --- a/doc/connectivity/usb/device/usb_device.rst +++ b/doc/connectivity/usb/device/usb_device.rst @@ -82,6 +82,9 @@ But there are two important differences in behavior to a real UART controller: initialized and started, until then any data is discarded * If device is connected to the host, it still needs an application on the host side which requests the data +* The CDC ACM poll out implementation follows the API and blocks when the TX + ring buffer is full only if the hw-flow-control property is enabled and + called from a non-ISR context. The devicetree compatible property for CDC ACM UART is :dtcompatible:`zephyr,cdc-acm-uart`. @@ -172,6 +175,37 @@ CDC ACM UART as backend for a subsystem or application: for example see :zephyr_file:`samples/subsys/shell/shell_module` * ``zephyr,uart-mcumgr`` used by :zephyr:code-sample:`smp-svr` sample +POSIX default tty ECHO mitigation +--------------------------------- + +POSIX systems, like Linux, default to enabling ECHO on tty devices. Host side +application can disable ECHO by calling ``open()`` on the tty device and issuing +``ioctl()`` (preferably via ``tcsetattr()``) to disable echo if it is not desired. +Unfortunately, there is an inherent race between the ``open()`` and ``ioctl()`` +where the ECHO is enabled and any characters received (even if host application +does not call ``read()``) will be echoed back. This issue is especially visible +when the CDC ACM port is used without any real UART on the other side because +there is no arbitrary delay due to baud rate. + +To mitigate the issue, Zephyr CDC ACM implementation arms IN endpoint with ZLP +after device is configured. When the host reads the ZLP, which is pretty much +the best indication that host application has opened the tty device, Zephyr will +force :kconfig:option:`CONFIG_CDC_ACM_TX_DELAY_MS` millisecond delay before real +payload is sent. This should allow sufficient time for first, and only first, +application that opens the tty device to disable ECHO if ECHO is not desired. +If ECHO is not desired at all from CDC ACM device it is best to set up udev rule +to disable ECHO as soon as device is connected. + +ECHO is particurarly unwanted when CDC ACM instance is used for Zephyr shell, +because the control characters to set color sent back to shell are interpreted +as (invalid) command and user will see garbage as a result. While minicom does +disable ECHO by default, on exit with reset it will restore the termios settings +to whatever was set on entry. Therefore, if minicom is the first application to +open the tty device, the exit with reset will enable ECHO back and thus set up +a problem for the next application (which cannot be mitigated at Zephyr side). +To prevent the issue it is recommended either to leave minicom without reset or +to disable ECHO before minicom is started. + DFU === @@ -411,14 +445,14 @@ the vendor requests: The class driver waits for the :makevar:`USB_DC_CONFIGURED` device status code before transmitting any data. -.. _testing_USB_native_posix: +.. _testing_USB_native_sim: -Testing over USPIP in native_posix -*********************************** +Testing over USPIP in native_sim +******************************** A virtual USB controller implemented through USBIP might be used to test the USB device stack. Follow the general build procedure to build the USB sample for -the native_posix configuration. +the :ref:`native_sim ` configuration. Run built sample with: diff --git a/doc/contribute/bin_blobs.rst b/doc/contribute/bin_blobs.rst index 661007927a0d069..14c181e4058dc1f 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 f3bcecddfd93f90..4677da2e86e7a46 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 dfe6b5ff0e2ac65..cba1627a1b9be30 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 @@ -209,21 +206,47 @@ PR Technical Escalation In cases where a contributor objects to change requests from reviewers, Zephyr defines the following escalation process for resolving technical disagreements. +Before escalation of technical disagreements, follow the steps below: + - Resolve in the PR among assignee, maintainers and reviewer. - Assignee to act as moderator if applicable. -- Optionally resolve in the next `Zephyr Dev Meeting`_ or `Architecture Working - Group`_ meeting with more Maintainers and project stakeholders. +- Optionally resolve in the next `Zephyr Dev Meeting`_ meeting with more + Maintainers and project stakeholders. + + - The involved parties and the Assignee to be present when the issue is + discussed. + +- If no progress is made, the assignee (maintainer) has the right to dismiss + stale, unrelated or irrelevant change requests by reviewers giving the + reviewers a minimum of 1 business day to respond and revisit their initial + change requests or start the escalation process. - - The involved parties and the Assignee to be present when - the (escalated) issue is discussed. + The assignee has the responsibility to document the reasoning for dismissing + any reviews in the PR and should notify the reviewer about their review being + dismissed. -- TSC: Assignees can escalate to the TSC voting members and get a binding - resolution in the TSC by adding the `tsc`_ label on the PR. + To give the reviewers time to respond and escalate, the assignee is + expected to block the PR from being merged either by not + approving the PR or by setting the *DNM* label. -- Assignee to ensure the resolution of the escalation is reflected in the PR - review. +Escalation can be triggered by any party participating in the review +process (assignee, reviewers or the original author of the change) following +the steps below: + +- Escalate to the `Architecture Working Group`_ by adding the `Architecture + Review` label on the PR. Beside the weekly meeting where such escalations are + processed, the `Architecture Working Group`_ shall facilitate an offline + review of the escalation if requested, especially if any of the parties can't + attend the meeting. + +- If all avenues of resolution and escalation have failed, assignees can escalate + to the TSC and get a binding resolution in the TSC by adding the *TSC* label + on the PR. + +- The Assignee is expected to ensure the resolution of the escalation and the + outcome is documented in the related pull request or issues on Github. .. _#pr-help: https://discord.com/channels/720317445772017664/997527108844798012 @@ -235,19 +258,21 @@ defines the following escalation process for resolving technical disagreements. .. _Architecture Working Group: https://github.com/zephyrproject-rtos/zephyr/wiki/Architecture-Working-Group -.. _tsc: https://github.com/zephyrproject-rtos/zephyr/labels/tsc + +.. _reviewer-expectations: Reviewer Expectations -##################### +********************* - Be respectful when commenting on PRs. Refer to the Zephyr `Code of Conduct`_ for more details. - The Zephyr Project recognizes that reviewers and maintainers have limited - bandwidth. Prioritize review requests in the following order: + bandwidth. As a reviewer, prioritize review requests in the following order: - #. PRs related to items in the `Zephyr Release Plan`_. - #. PRs that the reviewer has requested blocking changes. + #. PRs related to items in the `Zephyr Release Plan`_ or those targeting + the next release during the stabilization period (after RC1). + #. PRs where the reviewer has requested blocking changes. #. PRs assigned to the reviewer as the area maintainer. #. All other PRs. @@ -275,6 +300,11 @@ Reviewer Expectations they address all non-blocking comments. PR authors should acknowledge every review comment in some way, even if it's just with an emoticon. +- Reviewers shall be *clear* and *concise* what changes they are requesting when the + "Request Changes" option is used. Requested changes shall be in the scope of + the PR in question and following the contribution and style guidelines of the + project. + .. _Code of Conduct: https://github.com/zephyrproject-rtos/zephyr/blob/main/CODE_OF_CONDUCT.md .. _Zephyr Release Plan: https://github.com/orgs/zephyrproject-rtos/projects/13 diff --git a/doc/contribute/documentation/generation.rst b/doc/contribute/documentation/generation.rst index 7c5466ee5ed05ba..87a00357c893864 100644 --- a/doc/contribute/documentation/generation.rst +++ b/doc/contribute/documentation/generation.rst @@ -278,6 +278,25 @@ or invoke make with the following target:: # To generate HTML output without detailed Kconfig make html-fast +Viewing generated documentation locally +*************************************** + +The generated HTML documentation can be hosted locally with python for viewing +with a web browser: + +.. code-block:: console + + $ python3 -m http.server -d _build/html + +.. note:: + + WSL2 users may need to explicitly bind the address to ``127.0.0.1`` in order + to be accessible from the host machine: + + .. code-block:: console + + $ python3 -m http.server -d _build/html --bind 127.0.0.1 + Linking external Doxygen projects against Zephyr ************************************************ diff --git a/doc/contribute/documentation/guidelines.rst b/doc/contribute/documentation/guidelines.rst index a98fa7519166552..55db8e2e5562e8d 100644 --- a/doc/contribute/documentation/guidelines.rst +++ b/doc/contribute/documentation/guidelines.rst @@ -3,6 +3,8 @@ Documentation Guidelines ######################## +.. highlight:: rst + .. note:: For instructions on building the documentation, see :ref:`zephyr_doc`. @@ -302,9 +304,7 @@ External Cross-Reference Linking With Sphinx's help, we can create link-references to any tagged text within the Zephyr Project documentation. -Target locations in a document are defined with a label directive: - - .. code-block:: rst +Target locations in a document are defined with a label directive:: .. _my label name: @@ -325,10 +325,7 @@ To enable easy cross-page linking within the site, each file should have a reference label before its title so it can be referenced from another file. These reference labels must be unique across the whole site, so generic names such as "samples" should be -avoided. For example the top of this document's .rst file is: - - -.. code-block:: rst +avoided. For example the top of this document's .rst file is:: .. _doc_guidelines: @@ -395,7 +392,7 @@ For example:: .. code-block:: c - struct z_object { + struct k_object { char *name; uint8_t perms[CONFIG_MAX_THREAD_BYTES]; uint8_t type; @@ -411,7 +408,7 @@ This would be rendered as: .. code-block:: c - struct z_object { + struct k_object { char *name; uint8_t perms[CONFIG_MAX_THREAD_BYTES]; uint8_t type; @@ -420,10 +417,93 @@ This would be rendered as: } __packed; -You can specify other languages for the ``code-block`` directive, -including ``c``, ``python``, and ``rst``, and also ``console``, -``bash``, or ``shell``. If you want no syntax highlighting, use the -language ``none``, for example:: +Other languages are of course supported (see `languages supported by Pygments`_), and in particular, +you are encouraged to make use of the following when appropriate: + +.. _`languages supported by Pygments`: http://pygments.org/languages/ + +* ``c`` for C code +* ``cpp`` for C++ code +* ``python`` for Python code +* ``console`` for console output, i.e. interactive shell sessions where commands are prefixed by a + prompt (ex. ``$`` for Linux, or ``uart:~$`` for Zephyr's shell), and where the output is also + shown. The commands will be highlighted, and the output will not. What's more, copying code block + using the "copy" button will automatically copy just the commands, excluding the prompt and the + outputs of the commands. +* ``shell`` or ``bash`` for shell commands. Both languages get highlighted the same but you may use + ``bash`` for conveying that the commands are bash-specific, and ``shell`` for generic shell + commands. + + .. note:: + + Do not use ``bash`` or ``shell`` if your code block includes a prompt, use ``console`` instead. + + Reciprocally, do not use ``console`` if your code block does not include a prompt and is not + showcasing an interactive session with command(s) and their output. + + .. list-table:: When to use ``bash``/``shell`` vs. ``console`` + :class: wrap-normal + :header-rows: 1 + :widths: 20,40,40 + + * - Use case + - ``code-block`` snippet + - Expected output + + * - One or several commands, no output + + - .. code-block:: rst + + .. code-block:: shell + + echo "Hello World!" + + - .. code-block:: shell + + echo "Hello World!" + + * - An interactive shell session with command(s) and their output + + - .. code-block:: rst + + .. code-block:: console + + $ echo "Hello World!" + Hello World! + + - .. code-block:: console + + $ echo "Hello World!" + Hello World! + + * - An interactive Zephyr shell session, with commands and their outputs + + - .. code-block:: rst + + .. code-block:: console + + uart:~$ version + Zephyr version 3.5.99 + uart:~$ kernel uptime + Uptime: 20970 ms + + - .. code-block:: console + + uart:~$ version + Zephyr version 3.5.99 + uart:~$ kernel uptime + Uptime: 20970 ms + +* ``bat`` for Windows batch files +* ``cfg`` for config files with "KEY=value" entries (ex. Kconfig ``.conf`` files) +* ``cmake`` for CMake +* ``devicetree`` for Devicetree +* ``kconfig`` for Kconfig +* ``yaml`` for YAML +* ``rst`` for reStructuredText + +When no language is specified, the language is set to ``none`` and the code block is not +highlighted. You may also use ``none`` explicitly to achieve the same result; for example:: .. code-block:: none @@ -437,11 +517,11 @@ Would display as: This would be a block of text styled with a background and box, but with no syntax highlighting. -There's a shorthand for writing code blocks too: end the introductory -paragraph with a double colon (``::``) and indent the code block content -by three spaces. On output, only one colon will be shown. The -highlighting package makes a best guess at the type of content in the -block and highlighting purposes. +There's a shorthand for writing code blocks too: end the introductory paragraph with a double colon +(``::``) and indent the code block content that follows it by three spaces. On output, only one +colon will be shown. The code block will have no highlighting (i.e. ``none``). You may however use +the ``.. highlight::`` directive to customize the default language used in your document (see for +example how this is done at the beginning of this very document). Images ****** diff --git a/doc/contribute/external.rst b/doc/contribute/external.rst index e602c94df09803b..c154bc3a698a81f 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 7f11d0784194a14..06a70f0845ddd8c 100644 --- a/doc/contribute/guidelines.rst +++ b/doc/contribute/guidelines.rst @@ -316,7 +316,7 @@ Pull Requests and Issues Before starting on a patch, first check in our issues `Zephyr Project Issues`_ system to see what's been reported on the issue you'd like to address. Have a -conversation on the `Zephyr devel mailing list`_ (or the the `Zephyr Discord +conversation on the `Zephyr devel mailing list`_ (or the `Zephyr Discord Server`_) to see what others think of your issue (and proposed solution). You may find others that have encountered the issue you're finding, or that have similar ideas for changes or additions. Send a message to the `Zephyr devel @@ -360,7 +360,7 @@ gitlint When you submit a pull request to the project, a series of checks are performed to verify your commit messages meet the requirements. The same step -done during the CI process can be performed locally using the the ``gitlint`` +done during the CI process can be performed locally using the ``gitlint`` command. Run ``gitlint`` locally in your tree and branch where your patches have been @@ -507,6 +507,7 @@ issues, you can add option --no-verify to the git push command. A more complete alternative to this is using check_compliance.py script from ci-tools repo. +.. _static_analysis: Static Code Analysis ******************** @@ -531,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 ======== @@ -650,8 +660,8 @@ workflow here: request for the ``main`` branch. The title and message from your commit message should appear as well. -#. GitHub will assign one or more suggested reviewers (based on the - CODEOWNERS file in the repo). If you are a project member, you can +#. A bot will assign one or more suggested reviewers (based on the + MAINTAINERS file in the repo). If you are a project member, you can select additional reviewers now too. #. Click on the submit button and your pull request is sent and awaits @@ -1025,3 +1035,18 @@ Some example past treewide changes are: Note that adding a new version of a widely used API while maintaining support for the old one is not a treewide change. Deprecation and removal of such APIs, however, are treewide changes. + +Specialized driver requirements +******************************* + +Drivers for standalone devices should use the Zephyr bus APIs (SPI, I2C...) +whenever possible so that the device can be used with any SoC from any vendor +implementing a compatible bus. + +If it is not technically possible to achieve full performance using the Zephyr +APIs due to specialized accelerators in a particular SoC family, one could +extend the support for an external device by providing a specialized path for +that SoC family. However, the driver must still provide a regular path (via +Zephyr APIs) for all other SoCs. Every exception must be approved by the +Architecture WG in order to be validated and potentially to be learned/improved +from. diff --git a/doc/develop/api/api_lifecycle.rst b/doc/develop/api/api_lifecycle.rst index 8f1f689c12c965a..b34832655c85078 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 9295ee57b5fafa0..20d03836c752722 100644 --- a/doc/develop/api/overview.rst +++ b/doc/develop/api/overview.rst @@ -61,6 +61,10 @@ between major releases are available in the :ref:`zephyr_release_notes`. - Stable - 1.14 + * - :ref:`can_transceiver_api` + - Experimental + - 3.1 + * - :ref:`charger_api` - Experimental - 3.5 @@ -137,6 +141,10 @@ between major releases are available in the :ref:`zephyr_release_notes`. - Stable - 1.11 + * - :ref:`gnss_api` + - Experimental + - 3.6 + * - :ref:`gpio_api` - Stable - 1.0 @@ -225,6 +233,10 @@ between major releases are available in the :ref:`zephyr_release_notes`. - Stable - 1.11 + * - :ref:`modem` + - Experimental + - 3.5 + * - :ref:`mqtt_socket_interface` - Unstable - 1.14 @@ -278,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 0dae0d288e01c52..4346e0116703d7d 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 @@ -521,6 +526,7 @@ Make sure to follow these steps in order. Structure your :file:`Kconfig` file like this: .. literalinclude:: application-kconfig.include + :language: kconfig .. note:: @@ -701,7 +707,7 @@ be useful for glue code to have access to Zephyr kernel header files. To make it easier to integrate third-party components, the Zephyr build system has defined CMake functions that give application build scripts access to the zephyr compiler options. The functions are -documented and defined in :zephyr_file:`cmake/extensions.cmake` +documented and defined in :zephyr_file:`cmake/modules/extensions.cmake` and follow the naming convention ``zephyr_get__``. The following variables will often need to be exported to the diff --git a/doc/develop/beyond-GSG.rst b/doc/develop/beyond-GSG.rst index 41269c1263446de..d9336af53817945 100644 --- a/doc/develop/beyond-GSG.rst +++ b/doc/develop/beyond-GSG.rst @@ -177,7 +177,8 @@ Build and Run an Application You can build, flash, and run Zephyr applications on real hardware using a supported host system. Depending on your operating system, -you can also run it in emulation with QEMU, or as a native POSIX application. +you can also run it in emulation with QEMU, or as a native application with +:ref:`native_sim `. Additional information about building applications can be found in the :ref:`build_an_application` section. @@ -214,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. @@ -291,22 +292,21 @@ To exit QEMU, type :kbd:`Ctrl-a`, then :kbd:`x`. Use ``qemu_cortex_m3`` to target an emulated Arm Cortex-M3 sample. -.. _gs_posix: +.. _gs_native: -Run a Sample Application natively (POSIX OS) -============================================ +Run a Sample Application natively (Linux) +========================================= -You can compile some samples to run as host processes -on a POSIX OS. This is currently only tested on Linux hosts. See -:ref:`native_posix` for more information. On 64-bit host operating systems, you -need to install a 32-bit C library; see :ref:`native_posix_deps` for details. +You can compile some samples to run as host programs +on Linux. See :ref:`native_sim` for more information. On 64-bit host operating systems, you +need to install a 32-bit C library, or build targeting :ref:`native_sim_64 `. -First, build Hello World for ``native_posix``. +First, build Hello World for ``native_sim``. .. zephyr-app-commands:: :zephyr-app: samples/hello_world :host-os: unix - :board: native_posix + :board: native_sim :goals: build Next, run the application. @@ -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/env_vars.rst b/doc/develop/env_vars.rst index 459c62b580ae75f..fba31b7735e22e2 100644 --- a/doc/develop/env_vars.rst +++ b/doc/develop/env_vars.rst @@ -72,7 +72,7 @@ Option 2: In all Terminals You can then run ``rapidee`` from your terminal to launch the program and set environment variables. Make sure to use the "User" environment variables area -- otherwise, you have to run RapidEE as administrator. Also make sure to save - your changes by clicking the Save button at top left before exiting.Settings + your changes by clicking the Save button at top left before exiting. Settings you make in RapidEE will be available whenever you open a new terminal window. .. _env_vars_zephyrrc: diff --git a/doc/develop/flash_debug/host-tools.rst b/doc/develop/flash_debug/host-tools.rst index 981c89ce686f662..dff685ba7dabae8 100644 --- a/doc/develop/flash_debug/host-tools.rst +++ b/doc/develop/flash_debug/host-tools.rst @@ -321,6 +321,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` @@ -377,6 +379,68 @@ Zephyr RTOS Awareness To enable Zephyr RTOS awareness follow the steps described in `Lauterbach TRACE32 Zephyr OS Awareness Manual`_. +.. _nxp-s32-debug-host-tools: + +NXP S32 Debug Probe Host Tools +****************************** + +:ref:`nxp-s32-debug-probe` is designed to work in conjunction with +`NXP S32 Design Studio for S32 Platform`_. + +Download (registration required) NXP S32 Design Studio for S32 Platform and +follow the `S32 Design Studio for S32 Platform Installation User Guide`_ to get +the necessary debug host tools and associated USB device drivers. + +Note that Zephyr RTOS-awareness support for the NXP S32 GDB server depends on +the target device. Consult the product release notes for more information. + +Supported west commands: + +1. debug +#. debugserver +#. attach + +Basic usage +----------- + +Before starting, add NXP S32 Design Studio installation directory to the system +:ref:`PATH environment variable `. Alternatively, it can be passed to +the runner on each invocation via ``--s32ds-path`` as shown below: + +.. tabs:: + + .. group-tab:: Linux + + .. code-block:: console + + west debug --s32ds-path=/opt/NXP/S32DS.3.5 + + .. group-tab:: Windows + + .. code-block:: console + + west debug --s32ds-path=C:\NXP\S32DS.3.5 + +If multiple S32 debug probes are connected to the host via USB, the runner will +ask the user to select one via command line prompt before continuing. The +connection string for the probe can be also specified when invoking the runner +via ``--dev-id=``. Consult NXP S32 debug probe user manual +for details on how to construct the connection string. For example, if using a +probe with serial ID ``00:04:9f:00:ca:fe``: + +.. code-block:: console + + west debug --dev-id='s32dbg:00:04:9f:00:ca:fe' + +It is possible to pass extra options to the debug host tools via ``--tool-opt``. +When executing ``debug`` or ``attach`` commands, the tool options will be passed +to the GDB client only. When executing ``debugserver``, the tool options will be +passed to the GDB server. For example, to load a Zephyr application to SRAM and +afterwards detach the debug session: + +.. code-block:: console + + west debug --tool-opt='--batch' .. _J-Link Software and Documentation Pack: https://www.segger.com/downloads/jlink/#J-LinkSoftwareAndDocumentationPack @@ -415,4 +479,10 @@ To enable Zephyr RTOS awareness follow the steps described in 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 + +.. _S32 Design Studio for S32 Platform Installation User Guide: + https://www.nxp.com/webapp/Download?colCode=S32DSIG diff --git a/doc/develop/flash_debug/probes.rst b/doc/develop/flash_debug/probes.rst index 83f355aadba714c..0e237a6fcf63f57 100644 --- a/doc/develop/flash_debug/probes.rst +++ b/doc/develop/flash_debug/probes.rst @@ -33,21 +33,23 @@ host tools, or with J-Link firmware to communicate with J-Link debug host tools. -+---------------------------------------+---------------------------------------------------------------+ -|| *Debug Probes & Host Tools* | Host Tools | -+| *Compatibility Chart* +--------------------+--------------------+---------------------+ -| | **J-Link Debug** | **OpenOCD** | **pyOCD** | -+----------------+----------------------+--------------------+--------------------+---------------------+ -| | **LPC-Link2 J-Link** | ✓ | | | -| +----------------------+--------------------+--------------------+---------------------+ -| | **OpenSDA DAPLink** | | ✓ | ✓ | -| +----------------------+--------------------+--------------------+---------------------+ -| Debug Probes | **OpenSDA J-Link** | ✓ | | | -| +----------------------+--------------------+--------------------+---------------------+ -| | **J-Link External** | ✓ | ✓ | | -| +----------------------+--------------------+--------------------+---------------------+ -| | **ST-LINK/V2-1** | ✓ | ✓ | *some STM32 boards* | -+----------------+----------------------+--------------------+--------------------+---------------------+ ++------------------------------------------+------------------------------------------------------------------------------------+ +|| *Debug Probes & Host Tools* | Host Tools | ++| *Compatibility Chart* +--------------------+--------------------+---------------------+--------------------+ +| | **J-Link Debug** | **OpenOCD** | **pyOCD** | **NXP S32DS** | ++----------------+-------------------------+--------------------+--------------------+---------------------+--------------------+ +| | **LPC-Link2 J-Link** | ✓ | | | | +| +-------------------------+--------------------+--------------------+---------------------+--------------------+ +| | **OpenSDA DAPLink** | | ✓ | ✓ | | +| +-------------------------+--------------------+--------------------+---------------------+--------------------+ +| Debug Probes | **OpenSDA J-Link** | ✓ | | | | +| +-------------------------+--------------------+--------------------+---------------------+--------------------+ +| | **J-Link External** | ✓ | ✓ | | | +| +-------------------------+--------------------+--------------------+---------------------+--------------------+ +| | **ST-LINK/V2-1** | ✓ | ✓ | *some STM32 boards* | | +| +-------------------------+--------------------+--------------------+---------------------+--------------------+ +| | **NXP S32 Debug Probe** | | | | ✓ | ++----------------+-------------------------+--------------------+--------------------+---------------------+--------------------+ Some supported boards in Zephyr do not include an onboard debug probe and @@ -373,6 +375,20 @@ Where board_uid can be obtained using twister's generate-hardware-map option. For more information about twister and available options, see :ref:`twister_script`. +.. _nxp-s32-debug-probe: + +NXP S32 Debug Probe +******************* + +`NXP S32 Debug Probe`_ enables NXP S32 target system debugging via a standard +debug port while connected to a developer's workstation via USB or remotely via +Ethernet. + +NXP S32 Debug Probe is designed to work in conjunction with NXP S32 Design Studio +(S32DS) and NXP Automotive microcontrollers and processors. Install the debug +host tools as in indicated in :ref:`nxp-s32-debug-host-tools` before you program +the firmware. + .. _LPCScrypt: https://www.nxp.com/lpcscrypt @@ -402,3 +418,6 @@ option. For more information about twister and available options, see .. _MCUXpresso Installer: https://www.nxp.com/lgfiles/updates/mcuxpresso/MCUXpressoInstaller.exe + +.. _NXP S32 Debug Probe: + https://www.nxp.com/design/software/automotive-software-and-tools/s32-debug-probe:S32-DP diff --git a/doc/develop/getting_started/index.rst b/doc/develop/getting_started/index.rst index 59f41a503d69c4f..d95651121bf878b 100644 --- a/doc/develop/getting_started/index.rst +++ b/doc/develop/getting_started/index.rst @@ -22,7 +22,7 @@ Click the operating system you are using. .. group-tab:: Ubuntu - This guide covers Ubuntu version 18.04 LTS and later. + This guide covers Ubuntu version 20.04 LTS and later. .. code-block:: bash @@ -94,7 +94,9 @@ The current minimum required version for the main dependencies are: python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \ make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1 - #. Verify the versions of the main dependencies installed on your system by entering:: + #. Verify the versions of the main dependencies installed on your system by entering: + + .. code-block:: bash cmake --version python3 --version @@ -114,11 +116,31 @@ The current minimum required version for the main dependencies are: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + #. After the Homebrew installation script completes, follow the on-screen + instructions to add the Homebrew installation to the path. + + * On macOS running on Apple Silicon, this is achieved with: + + .. code-block:: bash + + (echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> ~/.zprofile + source ~/.zprofile + + * On macOS running on Intel, use the command for Apple Silicon, but replace ``/opt/homebrew/`` with ``/usr/local/``. + #. Use ``brew`` to install the required dependencies: .. code-block:: bash - brew install cmake ninja gperf python3 ccache qemu dtc wget libmagic + brew install cmake ninja gperf python3 ccache qemu dtc libmagic + + #. Add the Homebrew Python folder to the path, in order to be able to + execute ``python`` and ``pip`` as well ``python3`` and ``pip3``. + + .. code-block:: bash + + (echo; echo 'export PATH="'$(brew --prefix)'/opt/python/libexec/bin:$PATH"') >> ~/.zprofile + source ~/.zprofile .. group-tab:: Windows @@ -132,8 +154,9 @@ The current minimum required version for the main dependencies are: Therefore, we don't recommend using WSL when getting started. - These instructions must be run in a ``cmd.exe`` command prompt. The - required commands differ on PowerShell. + These instructions must be run in a ``cmd.exe`` command prompt terminal window. + In modern version of Windows (10 and later) it is recommended to install the Windows Terminal + application from the Microsoft Store. The required commands differ on PowerShell. These instructions rely on `Chocolatey`_. If Chocolatey isn't an option, you can install dependencies from their respective websites and ensure @@ -146,25 +169,30 @@ The current minimum required version for the main dependencies are: #. `Install chocolatey`_. - #. Open a ``cmd.exe`` window as **Administrator**. To do so, press the Windows key, - type "cmd.exe", right-click the result, and choose :guilabel:`Run as - Administrator`. + #. Open a ``cmd.exe`` terminal window as **Administrator**. To do so, press the Windows key, + type ``cmd.exe``, right-click the :guilabel:`Command Prompt`` search result, and choose + :guilabel:`Run as Administrator`. #. Disable global confirmation to avoid having to confirm the installation of individual programs: - .. code-block:: console + .. code-block:: bat choco feature enable -n allowGlobalConfirmation #. Use ``choco`` to install the required dependencies: - .. code-block:: console + .. code-block:: bat choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System' - choco install ninja gperf python git dtc-msys2 wget 7zip + choco install ninja gperf python311 git dtc-msys2 wget 7zip + + .. warning:: + + As of November 2023, Python 3.12 is not recommended for Zephyr development on Windows, + as some required Python dependencies may be difficult to install. - #. Close the window and open a new ``cmd.exe`` window **as a regular user** to continue. + #. Close the terminal window. .. _Chocolatey: https://chocolatey.org/ .. _Install chocolatey: https://chocolatey.org/install @@ -246,7 +274,7 @@ additional Python dependencies. automatically load boilerplate code required for building Zephyr applications. - .. code-block:: console + .. code-block:: bash west zephyr-export @@ -280,7 +308,7 @@ additional Python dependencies. automatically load boilerplate code required for building Zephyr applications. - .. code-block:: console + .. code-block:: bash west zephyr-export @@ -336,7 +364,7 @@ additional Python dependencies. automatically load boilerplate code required for building Zephyr applications. - .. code-block:: console + .. code-block:: bash west zephyr-export @@ -367,7 +395,7 @@ additional Python dependencies. automatically load boilerplate code required for building Zephyr applications. - .. code-block:: console + .. code-block:: bash west zephyr-export @@ -384,6 +412,8 @@ additional Python dependencies. .. group-tab:: Install within virtual environment + #. Open a ``cmd.exe`` terminal window **as a regular user** + #. Create a new virtual environment: .. code-block:: bat @@ -395,10 +425,7 @@ additional Python dependencies. .. code-block:: bat - :: cmd.exe zephyrproject\.venv\Scripts\activate.bat - :: PowerShell - zephyrproject\.venv\Scripts\Activate.ps1 Once activated your shell will be prefixed with ``(.venv)``. The virtual environment can be deactivated at any time by running @@ -411,13 +438,13 @@ additional Python dependencies. #. Install west: - .. code-block:: bash + .. code-block:: bat pip install west #. Get the Zephyr source code: - .. code-block:: bash + .. code-block:: bat west init zephyrproject cd zephyrproject @@ -427,19 +454,21 @@ additional Python dependencies. automatically load boilerplate code required for building Zephyr applications. - .. code-block:: console + .. code-block:: bat west zephyr-export #. Zephyr's ``scripts\requirements.txt`` file declares additional Python dependencies. Install them with ``pip``. - .. code-block:: bash + .. code-block:: bat pip install -r %HOMEPATH%\zephyrproject\zephyr\scripts\requirements.txt .. group-tab:: Install globally + #. Open a ``cmd.exe`` terminal window **as a regular user** + #. Install west: .. code-block:: bat @@ -471,8 +500,8 @@ additional Python dependencies. pip3 install -r %HOMEPATH%\zephyrproject\zephyr\scripts\requirements.txt -Install Zephyr SDK -****************** +Install the Zephyr SDK +********************** The :ref:`Zephyr Software Development Kit (SDK) ` contains toolchains for each of Zephyr's supported architectures, which @@ -482,156 +511,9 @@ Zephyr applications. It also contains additional host tools, such as custom QEMU and OpenOCD builds that are used to emulate, flash and debug Zephyr applications. -.. tabs:: - - .. group-tab:: Ubuntu - - .. _ubuntu_zephyr_sdk: - - #. Download and verify the `Zephyr SDK bundle - `_: - - .. code-block:: bash - - 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 - - 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 - - tar xvf zephyr-sdk-0.16.3_linux-x86_64.tar.xz - - .. note:: - It is recommended to extract the Zephyr SDK bundle at one of the following locations: - - * ``$HOME`` - * ``$HOME/.local`` - * ``$HOME/.local/opt`` - * ``$HOME/bin`` - * ``/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``. - - #. Run the Zephyr SDK bundle setup script: - - .. code-block:: bash - - cd zephyr-sdk-0.16.3 - ./setup.sh - - .. note:: - You only need to run the setup script once after extracting the Zephyr SDK bundle. - - You must rerun the setup script if you relocate the Zephyr SDK bundle directory after - the initial setup. - - #. Install `udev `_ rules, which - allow you to flash most Zephyr boards as a regular user: - - .. code-block:: bash - - sudo cp ~/zephyr-sdk-0.16.3/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 - `_: - - .. code-block:: bash - - cd ~ - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_macos-x86_64.tar.xz - wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | 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 - - tar xvf zephyr-sdk-0.16.3_macos-x86_64.tar.xz - - .. note:: - It is recommended to extract the Zephyr SDK bundle at one of the following locations: - - * ``$HOME`` - * ``$HOME/.local`` - * ``$HOME/.local/opt`` - * ``$HOME/bin`` - * ``/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``. - - #. Run the Zephyr SDK bundle setup script: - - .. code-block:: bash - - cd zephyr-sdk-0.16.3 - ./setup.sh - - .. note:: - You only need to run the setup script once after extracting the Zephyr SDK bundle. - - You must rerun the setup script if you relocate the Zephyr SDK bundle directory after - the initial setup. - - .. group-tab:: Windows - - .. _windows_zephyr_sdk: - - #. Open a ``cmd.exe`` window by pressing the Windows key typing "cmd.exe". - - #. Download the `Zephyr SDK bundle - `_: - - .. code-block:: console - - cd %HOMEPATH% - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_windows-x86_64.7z - - #. Extract the Zephyr SDK bundle archive: - - .. code-block:: console - - 7z x zephyr-sdk-0.16.3_windows-x86_64.7z - - .. note:: - It is recommended to extract the Zephyr SDK bundle at one of the following locations: - - * ``%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``. - - #. Run the Zephyr SDK bundle setup script: - - .. code-block:: console - - cd zephyr-sdk-0.16.3 - setup.cmd - - .. note:: - You only need to run the setup script once after extracting the Zephyr SDK bundle. - - You must rerun the setup script if you relocate the Zephyr SDK bundle directory after - the initial setup. +.. include:: ../toolchains/zephyr_sdk.rst + :start-after: toolchain_zephyr_sdk_install_start + :end-before: toolchain_zephyr_sdk_install_end .. _getting_started_run_sample: @@ -686,7 +568,7 @@ If in doubt about what to do, check your board's page in :ref:`boards`. Then flash the sample using :ref:`west flash `: -.. code-block:: console +.. code-block:: shell west flash diff --git a/doc/develop/getting_started/installation_linux.rst b/doc/develop/getting_started/installation_linux.rst index d9598f4170d99ec..6ef50b6d45a703b 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 @@ -303,7 +301,7 @@ toolchains for all Zephyr target architectures, and does not require any extra flags when building applications or running tests. In addition to cross-compilers, the Zephyr SDK also provides prebuilt host tools. It is, however, possible to build without the SDK's toolchain by using another -toolchain as as described in the :ref:`toolchains` section. +toolchain as described in the :ref:`toolchains` section. As already noted above, the SDK also includes prebuilt host tools. To use the SDK's prebuilt host tools with a toolchain from another source, you must set the diff --git a/doc/develop/getting_started/installation_mac.rst b/doc/develop/getting_started/installation_mac.rst index de7b3f861b3e50b..a6043d37b4f592f 100644 --- a/doc/develop/getting_started/installation_mac.rst +++ b/doc/develop/getting_started/installation_mac.rst @@ -19,9 +19,9 @@ get around this issue you can take two different approaches: ``path/to/folder`` is the path to the enclosing folder where the executables you want to run are located. -* Open "System Preferences" -> "Security and Privacy" -> "Privacy" and then - scroll down to "Developer Tools". Then unlock the lock to be able to make - changes and check the checkbox corresponding to your terminal emulator of +* Open :menuselection:`System Preferences --> Security and Privacy --> Privacy` + and then scroll down to "Developer Tools". Then unlock the lock to be able to + make changes and check the checkbox corresponding to your terminal emulator of choice. This will apply to any executable being launched from such terminal program. diff --git a/doc/develop/languages/c/newlib.rst b/doc/develop/languages/c/newlib.rst index f79d00c01e26c0e..a0daba2b9712e32 100644 --- a/doc/develop/languages/c/newlib.rst +++ b/doc/develop/languages/c/newlib.rst @@ -31,7 +31,7 @@ The Newlib full variant (:file:`libc.a` and :file:`libm.a`) is the most capable variant of the Newlib available in the Zephyr SDK, and supports almost all standard C library features. It is optimized for performance (prefers performance over code size) and its footprint is significantly larger than the -the nano variant. +nano variant. This variant can be enabled by selecting the :kconfig:option:`CONFIG_NEWLIB_LIBC` and de-selecting the diff --git a/doc/develop/languages/cpp/index.rst b/doc/develop/languages/cpp/index.rst index 5ba5c7d7688adbd..492872d7e9ca473 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 000000000000000..258619d4be6f246 --- /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 000000000000000..49e262ab36e7f25 --- /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 2dba5d817dc9f70..a24c32de61cbb7c 100644 --- a/doc/develop/manifest/index.rst +++ b/doc/develop/manifest/index.rst @@ -30,7 +30,7 @@ Inactive and Optional Projects/Modules The projects below are optional and will not be downloaded when you -call `west update`. You can add any of the the projects or modules listed below +call `west update`. You can add any of the projects or modules listed below and use them to write application code and extend your workspace with the added functionality. @@ -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 45167585cd65864..875f6f62ff1d9fd 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}`` @@ -818,7 +819,7 @@ to the path containing the CMake file. To include a module's Kconfig file, set the variable ``ZEPHYR__KCONFIG`` to the path to the Kconfig file. -The following is an example on how to add support the the ``FOO`` module. +The following is an example on how to add support the ``FOO`` module. Create the following structure diff --git a/doc/develop/optimizations/tools.rst b/doc/develop/optimizations/tools.rst index 762891cf8d80c83..c253d47092ee587 100644 --- a/doc/develop/optimizations/tools.rst +++ b/doc/develop/optimizations/tools.rst @@ -33,37 +33,48 @@ Use the ``ram_report`` target with your board: which will generate something similar to the output below:: - Path Size % - ============================================================================================================== - ... - ... - SystemCoreClock 4 0.08% - _kernel 48 0.99% - _sw_isr_table 384 7.94% - cli.10544 16 0.33% - gpio_initialized.9765 1 0.02% - on.10543 4 0.08% - poll_out_lock.9764 4 0.08% - z_idle_threads 128 2.65% - z_interrupt_stacks 2048 42.36% - z_main_thread 128 2.65% - arch 1 0.02% - arm 1 0.02% - core 1 0.02% - aarch32 1 0.02% - cortex_m 1 0.02% - mpu 1 0.02% - arm_mpu.c 1 0.02% - static_regions_num 1 0.02% - drivers 536 11.09% - clock_control 100 2.07% - nrf_power_clock.c 100 2.07% - __device_clock_nrf 16 0.33% - data 80 1.65% - hfclk_users 4 0.08% - ... - ... - + Path Size % + ======================================================================================== + Root 4637 100.00% + ├── (hidden) 4 0.09% + ├── (no paths) 2748 59.26% + │ ├── _cpus_active 4 0.09% + │ ├── _kernel 32 0.69% + │ ├── _sw_isr_table 384 8.28% + │ ├── cli.1 16 0.35% + │ ├── on.2 4 0.09% + │ ├── poll_out_lock.0 4 0.09% + │ ├── z_idle_threads 128 2.76% + │ ├── z_interrupt_stacks 2048 44.17% + │ └── z_main_thread 128 2.76% + ├── WORKSPACE 184 3.97% + │ └── modules 184 3.97% + │ └── hal 184 3.97% + │ └── nordic 184 3.97% + │ └── nrfx 184 3.97% + │ └── drivers 184 3.97% + │ └── src 184 3.97% + │ ├── nrfx_clock.c 8 0.17% + │ │ └── m_clock_cb 8 0.17% + │ ├── nrfx_gpiote.c 132 2.85% + │ │ └── m_cb 132 2.85% + │ ├── nrfx_ppi.c 4 0.09% + │ │ └── m_channels_allocated 4 0.09% + │ └── nrfx_twim.c 40 0.86% + │ └── m_cb 40 0.86% + └── ZEPHYR_BASE 1701 36.68% + ├── arch 5 0.11% + │ └── arm 5 0.11% + │ └── core 5 0.11% + │ ├── mpu 1 0.02% + │ │ └── arm_mpu.c 1 0.02% + │ │ └── static_regions_num 1 0.02% + │ └── tls.c 4 0.09% + │ └── z_arm_tls_ptr 4 0.09% + ├── drivers 258 5.56% + │ ├── ... ... ...% + ======================================================================================== + 4637 Build Target: rom_report ======================== @@ -82,47 +93,40 @@ Use the ``rom_report`` to get the ROM report: which will generate something similar to the output below:: - Path Size % - ============================================================================================================== - ... - ... - CSWTCH.5 4 0.02% - SystemCoreClock 4 0.02% - __aeabi_idiv0 2 0.01% - __udivmoddi4 702 3.37% - _sw_isr_table 384 1.85% - delay_machine_code.9114 6 0.03% - levels.8826 20 0.10% - mpu_config 8 0.04% - transitions.10558 12 0.06% - arch 1194 5.74% - arm 1194 5.74% - core 1194 5.74% - aarch32 1194 5.74% - cortex_m 852 4.09% - fault.c 400 1.92% - bus_fault.isra.0 60 0.29% - mem_manage_fault.isra.0 56 0.27% - usage_fault.isra.0 36 0.17% - z_arm_fault 232 1.11% - z_arm_fault_init 16 0.08% - irq_init.c 24 0.12% - z_arm_interrupt_init 24 0.12% - mpu 352 1.69% - arm_core_mpu.c 56 0.27% - z_arm_configure_static_mpu_regions 56 0.27% - arm_mpu.c 296 1.42% - __init_sys_init_arm_mpu_init0 8 0.04% - arm_core_mpu_configure_static_mpu_regions 20 0.10% - arm_core_mpu_disable 16 0.08% - arm_core_mpu_enable 20 0.10% - arm_mpu_init 92 0.44% - mpu_configure_regions 140 0.67% - thread_abort.c 76 0.37% - z_impl_k_thread_abort - 76 0.37% - ... - ... + Path Size % + ======================================================================================== + Root 21652 100.00% + ├── ... ... ...% + └── ZEPHYR_BASE 13378 61.79% + ├── arch 1718 7.93% + │ └── arm 1718 7.93% + │ └── core 1718 7.93% + │ ├── cortex_m 1020 4.71% + │ │ ├── fault.c 620 2.86% + │ │ │ ├── bus_fault.constprop.0 108 0.50% + │ │ │ ├── mem_manage_fault.constprop.0 120 0.55% + │ │ │ ├── usage_fault.constprop.0 84 0.39% + │ │ │ ├── z_arm_fault 292 1.35% + │ │ │ └── z_arm_fault_init 16 0.07% + │ │ ├── ... ... ...% + ├── boards 32 0.15% + │ └── arm 32 0.15% + │ └── reel_board 32 0.15% + │ └── board.c 32 0.15% + │ ├── __init_board_reel_board_init 8 0.04% + │ └── board_reel_board_init 24 0.11% + ├── build 194 0.90% + │ └── zephyr 194 0.90% + │ ├── isr_tables.c 192 0.89% + │ │ └── _irq_vector_table 192 0.89% + │ └── misc 2 0.01% + │ └── generated 2 0.01% + │ └── configs.c 2 0.01% + │ └── _ConfigAbsSyms 2 0.01% + ├── drivers 6162 28.46% + │ ├── ... ... ...% + ======================================================================================== + 21652 Build Target: puncover ====================== diff --git a/doc/develop/sca/gcc.rst b/doc/develop/sca/gcc.rst new file mode 100644 index 000000000000000..4ae852c81ad85eb --- /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 08b9d96a0ccc609..44a9ee426156d10 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,4 @@ The following is a list of SCA tools natively supported by Zephyr build system. codechecker sparse + gcc diff --git a/doc/develop/test/bsim.rst b/doc/develop/test/bsim.rst index be06fad434fa281..c785f88c1ee84c9 100644 --- a/doc/develop/test/bsim.rst +++ b/doc/develop/test/bsim.rst @@ -12,7 +12,7 @@ including the BLE stack, 802.15.4, and some of the networking stack. BabbleSim_ is a physical layer simulator, which in combination with the Zephyr :ref:`bsim boards` can be used to simulate a network of BLE and 15.4 devices. -When we build Zephyr targeting an :ref:`nrf52_bsim` board we produce a Linux +When we build Zephyr targeting a :ref:`bsim board` we produce a Linux executable, which includes the application, Zephyr OS, and models of the HW. When there is radio activity, this Linux executable will connect to the BabbleSim Phy simulation @@ -21,8 +21,9 @@ to simulate the radio channel. In the BabbleSim documentation you can find more information on how to `get `_ and `build `_ the simulator. -In the :ref:`nrf52_bsim` board documentation you can find more information about how -to build Zephyr targeting that particular board, and a few examples. +In the :ref:`nrf52_bsim` and :ref:`nrf5340bsim` boards documentation +you can find more information about how to build Zephyr targeting thesee particular boards, +and a few examples. Types of tests ************** @@ -31,8 +32,8 @@ Tests without radio activity: bsim tests with twister ----------------------------------------------------- The :ref:`bsim boards` can be used without radio activity, and in that case, it is not -necessary to connect them to a phyisical layer simulation. Thanks to this, this target boards can -be used just like :ref:`native_posix` with :ref:`twister `, +necessary to connect them to a physical layer simulation. Thanks to this, these target boards can +be used just like :ref:`native_sim` with :ref:`twister `, to run all standard Zephyr twister tests, but with models of a real SOC HW, and their drivers. Tests with radio activity @@ -62,8 +63,8 @@ found in the :ref:`bsim boards tests section`. Test coverage and BabbleSim *************************** -As the :ref:`nrf52_bsim` is based on the POSIX architecture, you can easily collect test -coverage information. +As the :ref:`nrf52_bsim` and :ref:`nrf5340bsim` boards are based on the +POSIX architecture, you can easily collect test coverage information. You can use the script :code:`tests/bsim/generate_coverage_report.sh` to generate an html coverage report from tests. diff --git a/doc/develop/test/coverage.rst b/doc/develop/test/coverage.rst index f911c74287cf90c..60faffa1a90ff65 100644 --- a/doc/develop/test/coverage.rst +++ b/doc/develop/test/coverage.rst @@ -109,7 +109,7 @@ You may postprocess these with your preferred tools. For example: :zephyr-app: samples/hello_world :gen-args: -DCONFIG_COVERAGE=y :host-os: unix - :board: native_posix + :board: native_sim :goals: build :compact: @@ -140,9 +140,13 @@ For example, you may invoke:: or:: - $ twister --coverage -p native_posix -T tests/bluetooth + $ 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 d0fad4d6be61d8f..ac3980105d9b023 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,29 +46,72 @@ 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’]``. +`discovery rules `_. + +Passing extra arguments +======================= + +There are two ways for passing extra arguments to the called pytest subprocess: -Helpers & fixtures -================== +#. 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 + + $ ./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' + + +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 (more info +:ref:`here `). -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 posix, qemu, hardware, etc.). All types of devices share the same API. -This allows for writing tests which are device-type-agnostic. .. code-block:: python @@ -78,11 +121,14 @@ This allows for writing tests which are device-type-agnostic. 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. +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 @@ -92,16 +138,16 @@ Note that it uses `dut` fixture, so `dut` can be skipped when `shell` is used. 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 @@ -120,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 445fc020b9beca0..be24732e1ba38c0 100644 --- a/doc/develop/test/twister.rst +++ b/doc/develop/test/twister.rst @@ -19,7 +19,7 @@ tests for different boards and different configurations to help keep the complete code tree buildable. When using (at least) one ``-v`` option, twister's console output -shows for every test how the test is run (qemu, native_posix, etc.) or +shows for every test how the test is run (qemu, native_sim, etc.) or whether the binary was just built. There are a few reasons why twister only builds a test and doesn't run it: @@ -136,7 +136,9 @@ required for best test coverage for this specific board: identifier: A string that matches how the board is defined in the build system. This same string is used when building, for example when calling ``west build`` or - ``cmake``:: + ``cmake``: + + .. code-block:: console # with west west build -b reel_board @@ -153,7 +155,7 @@ arch: Architecture of the board toolchain: The list of supported toolchains that can build this board. This should match - one of the values used for 'ZEPHYR_TOOLCHAIN_VARIANT' when building on the command line + one of the values used for :envvar:`ZEPHYR_TOOLCHAIN_VARIANT` when building on the command line ram: Available RAM on the board (specified in KB). This is used to match testcase requirements. If not specified we default to 128KB. @@ -164,7 +166,7 @@ supported: A list of features this board supports. This can be specified as a single word feature or as a variant of a feature class. For example: - :: + .. code-block:: yaml supported: - pci @@ -172,7 +174,7 @@ supported: This indicates the board does support PCI. You can make a testcase build or run only on such boards, or: - :: + .. code-block:: yaml supported: - netif:eth @@ -206,7 +208,7 @@ testing: Test Cases ********** -Test cases are detected by the presence of a 'testcase.yaml' or a 'sample.yaml' +Test cases are detected by the presence of a ``testcase.yaml`` or a ``sample.yaml`` files in the application's project directory. This file may contain one or more entries in the test section each identifying a test scenario. @@ -244,7 +246,7 @@ samples. The following is an example test with a few options that are explained in this document. -:: + .. code-block:: yaml tests: bluetooth.gatt: @@ -263,7 +265,7 @@ explained in this document. A sample with tests will have the same structure with additional information related to the sample and what is being demonstrated: -:: + .. code-block:: yaml sample: name: hello world @@ -280,11 +282,7 @@ related to the sample and what is being demonstrated: tags: tests min_ram: 16 -The full canonical name for each test case is: - -:: - - / +The full canonical name for each test case is:``/`` Each test block in the testcase meta data can define the following key/value pairs: @@ -298,7 +296,7 @@ skip: (default False) skip testcase unconditionally. This can be used for broken tests. slow: (default False) - Don't run this test case unless --enable-slow or --enable-slow-only was + Don't run this test case unless ``--enable-slow`` or ``--enable-slow-only`` was passed in on the command line. Intended for time-consuming test cases that are only run under certain circumstances, like daily builds. These test cases are still compiled. @@ -309,7 +307,9 @@ extra_args: extra_configs: Extra configuration options to be merged with a master prj.conf - when building or running the test case. For example:: + when building or running the test case. For example: + + .. code-block:: yaml common: tags: drivers adc @@ -321,7 +321,9 @@ extra_configs: - CONFIG_ADC_ASYNC=y Using namespacing, it is possible to apply a configuration only to some - hardware. Currently both architectures and platforms are supported:: + hardware. Currently both architectures and platforms are supported: + + .. code-block:: yaml common: tags: drivers adc @@ -345,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 @@ -355,7 +357,7 @@ depends_on: A board or platform can announce what features it supports, this option will enable the test only those platforms that provide this feature. -levels: Test levels this test should be part of. If a level is present, this test will be selectable using the command line option ``--level `` @@ -387,7 +389,7 @@ platform_allow: integration_platforms: This option limits the scope to the listed platforms when twister is - invoked with the --integration option. Use this instead of + invoked with the ``--integration`` option. Use this instead of platform_allow if the goal is to limit scope due to timing or resource constraints. @@ -403,7 +405,7 @@ sysbuild: (default False) Build the project using sysbuild infrastructure. Only the main project's generated devicetree and Kconfig will be used for filtering tests. on device testing must use the hardware map, or west flash to load - the images onto the target. The --erase option of west flash is + the images onto the target. The ``--erase`` option of west flash is not supported with this option. Usage of unsupported options will result in tests requiring sysbuild support being skipped. @@ -417,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: @@ -443,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. @@ -452,7 +462,9 @@ platform_key: that. For example to key on (arch, simulation) to ensure a test is run once - per arch and simulation (as would be most common):: + per arch and simulation (as would be most common): + + .. code-block:: yaml platform_key: - arch @@ -461,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 @@ -474,16 +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 @@ -491,32 +496,79 @@ 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 specific test setup and board selection logic to pick the particular board(s) out of multiple boards that fulfill the dependency in an - automation setup based on "fixture" keyword. Some sample fixture names + automation setup based on ``fixture`` keyword. Some sample fixture names are i2c_hts221, i2c_bme280, i2c_FRAM, ble_fw and gpio_loop. 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. + If the scope is set to ``function``, DUT is launched for every test case + in python script. For ``session`` scope, DUT is launched only once. 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 sample: name: HTS221 Temperature and Humidity Monitor @@ -539,7 +591,7 @@ harness_config: default pytest_root name "pytest" will be used if pytest_root not specified. please refer the examples in samples/subsys/testsuite/pytest/. - :: + .. code-block:: yaml common: harness: pytest @@ -558,7 +610,7 @@ harness_config: The following is an example yaml file with robot harness_config options. - :: + .. code-block:: yaml tests: robot.example: @@ -570,7 +622,7 @@ filter: Filter whether the testcase should be run by evaluating an expression against an environment containing the following values: - :: + .. code-block:: none { ARCH : , PLATFORM : , @@ -586,51 +638,57 @@ filter: The grammar for the expression language is as follows: - expression ::= expression "and" expression - | expression "or" expression - | "not" expression - | "(" expression ")" - | symbol "==" constant - | symbol "!=" constant - | symbol "<" number - | symbol ">" number - | symbol ">=" number - | symbol "<=" number - | symbol "in" list - | symbol ":" string - | symbol + .. code-block:: antlr - list ::= "[" list_contents "]" + expression : expression 'and' expression + | expression 'or' expression + | 'not' expression + | '(' expression ')' + | symbol '==' constant + | symbol '!=' constant + | symbol '<' NUMBER + | symbol '>' NUMBER + | symbol '>=' NUMBER + | symbol '<=' NUMBER + | symbol 'in' list + | symbol ':' STRING + | symbol + ; - list_contents ::= constant - | list_contents "," constant + list : '[' list_contents ']'; - constant ::= number - | string + list_contents : constant (',' constant)*; + constant : NUMBER | STRING; - For the case where expression ::= symbol, it evaluates to true + For the case where ``expression ::= symbol``, it evaluates to ``true`` if the symbol is defined to a non-empty string. Operator precedence, starting from lowest to highest: - or (left associative) - and (left associative) - not (right associative) - all comparison operators (non-associative) + * or (left associative) + * and (left associative) + * not (right associative) + * all comparison operators (non-associative) - arch_allow, arch_exclude, platform_allow, platform_exclude - are all syntactic sugar for these expressions. For instance + ``arch_allow``, ``arch_exclude``, ``platform_allow``, ``platform_exclude`` + are all syntactic sugar for these expressions. For instance: + + .. code-block:: none arch_exclude = x86 arc Is the same as: + .. code-block:: none + filter = not ARCH in ["x86", "arc"] - The ':' operator compiles the string argument as a regular expression, + The ``:`` operator compiles the string argument as a regular expression, and then returns a true value only if the symbol's value in the environment - matches. For example, if CONFIG_SOC="stm32f107xc" then + matches. For example, if ``CONFIG_SOC="stm32f107xc"`` then + + .. code-block:: none filter = CONFIG_SOC : "stm.*" @@ -646,7 +704,7 @@ required_snippets: The following is an example yaml file with 2 required snippets. - :: + .. code-block:: yaml tests: snippet.example: @@ -656,16 +714,16 @@ required_snippets: The set of test cases that actually run depends on directives in the testcase filed and options passed in on the command line. If there is any confusion, -running with -v or examining the discard report +running with ``-v`` or examining the discard report (:file:`twister_discard.csv`) can help show why particular test cases were skipped. Metrics (such as pass/fail state and binary size) for the last code -release are stored in scripts/release/twister_last_release.csv. -To update this, pass the --all --release options. +release are stored in ``scripts/release/twister_last_release.csv``. +To update this, pass the ``--all --release`` options. -To load arguments from a file, write '+' before the file name, e.g., -+file_name. File content must be one or more valid arguments separated by +To load arguments from a file, add ``+`` before the file name, e.g., +``+file_name``. File content must be one or more valid arguments separated by line break instead of white spaces. Most everyday users will run with no arguments. @@ -691,7 +749,7 @@ Running in Integration Mode This mode is used in continuous integration (CI) and other automated environments used to give developers fast feedback on changes. The mode can -be activated using the --integration option of twister and narrows down +be activated using the ``--integration`` option of twister and narrows down the scope of builds and tests if applicable to platforms defined under the integration keyword in the testcase definition file (testcase.yaml and sample.yaml). @@ -705,7 +763,7 @@ supports running any out-of-tree custom emulator defined in the board's :file:`b To use this type of simulation, add the following properties to :file:`custom_board/custom_board.yaml`: -:: +.. code-block:: yaml simulation: custom simulation_exec: @@ -715,14 +773,14 @@ make sure this binary exists in the PATH. Then, in :file:`custom_board/board.cmake`, set the supported emulation platforms to ``custom``: -:: +.. code-block:: cmake set(SUPPORTED_EMU_PLATFORMS custom) Finally, implement the ``run_custom`` target in :file:`custom_board/board.cmake`. It should look something like this: -:: +.. code-block:: cmake add_custom_target(run_custom COMMAND @@ -829,40 +887,40 @@ devices, for example: .. group-tab:: Linux - :: - - - connected: true - id: OSHW000032254e4500128002ab98002784d1000097969900 - platform: unknown - product: DAPLink CMSIS-DAP - runner: pyocd - serial: /dev/cu.usbmodem146114202 - - connected: true - id: 000683759358 - platform: unknown - product: J-Link - runner: unknown - serial: /dev/cu.usbmodem0006837593581 + .. code-block:: yaml + + - connected: true + id: OSHW000032254e4500128002ab98002784d1000097969900 + platform: unknown + product: DAPLink CMSIS-DAP + runner: pyocd + serial: /dev/cu.usbmodem146114202 + - connected: true + id: 000683759358 + platform: unknown + product: J-Link + runner: unknown + serial: /dev/cu.usbmodem0006837593581 .. group-tab:: Windows - :: + .. code-block:: yaml - - connected: true - id: OSHW000032254e4500128002ab98002784d1000097969900 - platform: unknown - product: unknown - runner: unknown - serial: COM1 - - connected: true - id: 000683759358 - platform: unknown - product: unknown - runner: unknown - serial: COM2 + - connected: true + id: OSHW000032254e4500128002ab98002784d1000097969900 + platform: unknown + product: unknown + runner: unknown + serial: COM1 + - connected: true + id: 000683759358 + platform: unknown + product: unknown + runner: unknown + serial: COM2 -Any options marked as 'unknown' need to be changed and set with the correct +Any options marked as ``unknown`` need to be changed and set with the correct values, in the above example the platform names, the products and the runners need to be replaced with the correct values corresponding to the connected hardware. In this example we are using a reel_board and an nrf52840dk_nrf52840: @@ -871,41 +929,41 @@ In this example we are using a reel_board and an nrf52840dk_nrf52840: .. group-tab:: Linux - :: - - - connected: true - id: OSHW000032254e4500128002ab98002784d1000097969900 - platform: reel_board - product: DAPLink CMSIS-DAP - runner: pyocd - serial: /dev/cu.usbmodem146114202 - baud: 9600 - - connected: true - id: 000683759358 - platform: nrf52840dk_nrf52840 - product: J-Link - runner: nrfjprog - serial: /dev/cu.usbmodem0006837593581 - baud: 9600 + .. code-block:: yaml + + - connected: true + id: OSHW000032254e4500128002ab98002784d1000097969900 + platform: reel_board + product: DAPLink CMSIS-DAP + runner: pyocd + serial: /dev/cu.usbmodem146114202 + baud: 9600 + - connected: true + id: 000683759358 + platform: nrf52840dk_nrf52840 + product: J-Link + runner: nrfjprog + serial: /dev/cu.usbmodem0006837593581 + baud: 9600 .. group-tab:: Windows - :: - - - connected: true - id: OSHW000032254e4500128002ab98002784d1000097969900 - platform: reel_board - product: DAPLink CMSIS-DAP - runner: pyocd - serial: COM1 - baud: 9600 - - connected: true - id: 000683759358 - platform: nrf52840dk_nrf52840 - product: J-Link - runner: nrfjprog - serial: COM2 - baud: 9600 + .. code-block:: yaml + + - connected: true + id: OSHW000032254e4500128002ab98002784d1000097969900 + platform: reel_board + product: DAPLink CMSIS-DAP + runner: pyocd + serial: COM1 + baud: 9600 + - connected: true + id: 000683759358 + platform: nrf52840dk_nrf52840 + product: J-Link + runner: nrfjprog + serial: COM2 + baud: 9600 The baud entry is only needed if not running at 115200. @@ -944,17 +1002,19 @@ command line options as ``flash-timeout`` and ``flash-with-test`` fields respect These hardware map values override command line options for the particular platform. Serial PTY support using ``--device-serial-pty`` can also be used in the -hardware map:: +hardware map: - - connected: true - id: None - platform: intel_adsp_cavs25 - product: None - runner: intel_adsp - serial_pty: path/to/script.py - runner_params: - - --remote-host=remote_host_ip_addr - - --key=/path/to/key.pem +.. code-block:: yaml + + - connected: true + id: None + platform: intel_adsp_cavs25 + product: None + runner: intel_adsp + serial_pty: path/to/script.py + runner_params: + - --remote-host=remote_host_ip_addr + - --key=/path/to/key.pem The runner_params field indicates the parameters you want to pass to the @@ -994,7 +1054,9 @@ specify the fixture it needs which can then be matched with hardware capability of a board and the fixtures it supports via the command line or using the hardware map file. -Fixtures are defined in the hardware map file as a list:: +Fixtures are defined in the hardware map file as a list: + +.. code-block:: yaml - connected: true fixtures: @@ -1021,8 +1083,10 @@ Notes +++++ It may be useful to annotate board descriptions in the hardware map file -with additional information. Use the "notes" keyword to do this. For -example:: +with additional information. Use the ``notes`` keyword to do this. For +example: + +.. code-block:: yaml - connected: false fixtures: @@ -1030,7 +1094,7 @@ example:: id: 000683290670 notes: An nrf5340dk_nrf5340 is detected as an nrf52840dk_nrf52840 with no serial port, and three serial ports with an unknown platform. The board id of the serial - ports is not the same as the board id of the the development kit. If you regenerate + ports is not the same as the board id of the development kit. If you regenerate this file you will need to update serial to reference the third port, and platform to nrf5340dk_nrf5340_cpuapp or another supported board target. platform: nrf52840dk_nrf52840 @@ -1041,11 +1105,13 @@ example:: Overriding Board Identifier +++++++++++++++++++++++++++ -When (re-)generated the hardware map file will contain an "id" keyword +When (re-)generated the hardware map file will contain an ``id`` keyword that serves as the argument to ``--board-id`` when flashing. In some cases the detected ID is not the correct one to use, for example when -using an external J-Link probe. The "probe_id" keyword overrides the -"id" keyword for this purpose. For example:: +using an external J-Link probe. The ``probe_id`` keyword overrides the +``id`` keyword for this purpose. For example: + +.. code-block:: yaml - connected: false id: 0229000005d9ebc600000000000000000000000097969905 @@ -1058,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 @@ -1072,8 +1138,8 @@ The current status of tests on the quarantine list can also be verified by addin which are not on the given list. A quarantine yaml has to be a sequence of dictionaries. Each dictionary has to have -"scenarios" and "platforms" entries listing combinations of scenarios and platforms -to put under quarantine. In addition, an optional entry "comment" can be used, where +``scenarios`` and ``platforms`` entries listing combinations of scenarios and platforms +to put under quarantine. In addition, an optional entry ``comment`` can be used, where some more details can be given (e.g. link to a reported issue). These comments will also be added to the output reports. @@ -1082,7 +1148,9 @@ when dealing with multiple issues within a subsystem, it is possible to use regular expressions, for example, **kernel.*** would quarantine all kernel tests. -An example of entries in a quarantine yaml:: +An example of entries in a quarantine yaml: + +.. code-block:: yaml - scenarios: - sample.basic.helloworld @@ -1094,9 +1162,11 @@ An example of entries in a quarantine yaml:: - kernel.common.nano64 platforms: - .*_cortex_.* - - native_posix + - native_sim -To exclude a platform, use the following syntax:: +To exclude a platform, use the following syntax: + +.. code-block:: yaml - platforms: - qemu_x86 @@ -1107,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. @@ -1117,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. @@ -1134,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 @@ -1157,7 +1227,9 @@ The following options control platform filtering in twister: can either be used to replace the existing default platforms or can extend it depending on the value of `override_default_platforms`. -And example platforms configuration:: +And example platforms configuration: + +.. code-block:: yaml platforms: override_default_platforms: true @@ -1177,7 +1249,9 @@ In the configuration file you can include complete components using regular expressions and you can specify which test level to import from the same file, making management of levels simple. -And example test level configuration:: +And example test level configuration: + +.. code-block:: yaml levels: - name: my-test-level @@ -1195,7 +1269,9 @@ 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 platforms: override_default_platforms: true @@ -1222,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:: @@ -1240,7 +1316,7 @@ Running in Tests in Random Order ******************************** Enable ZTEST framework's :kconfig:option:`CONFIG_ZTEST_SHUFFLE` config option to run your tests in random order. This can be beneficial for identifying -dependencies between test cases. For native_posix platforms, you can provide +dependencies between test cases. For native_sim platforms, you can provide the seed to the random number generator by providing ``-seed=value`` as an argument to twister. See :ref:`Shuffling Test Sequence ` for more details. diff --git a/doc/develop/test/ztest.rst b/doc/develop/test/ztest.rst index 1eff49906bf4f00..124fd415c2306f8 100644 --- a/doc/develop/test/ztest.rst +++ b/doc/develop/test/ztest.rst @@ -10,10 +10,6 @@ test structure. The framework can be used in two ways, either as a generic framework for integration testing, or for unit testing specific modules. -To enable support for the latest Ztest API, set -:kconfig:option:`CONFIG_ZTEST_NEW_API` to ``y``. There is also a legacy API -that is deprecated and will eventually be removed. - Creating a test suite ********************* @@ -201,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(); @@ -344,6 +340,8 @@ it needs to report either a pass or fail. For example: ZTEST_SUITE(common, NULL, NULL, NULL, NULL, NULL); +.. _ztest_unit_testing: + Quick start - Unit testing ************************** @@ -555,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. @@ -581,7 +576,7 @@ Shuffling Test Sequence By default the tests are sorted and ran in alphanumerical order. Test cases may be dependent on this sequence. Enable :kconfig:option:`CONFIG_ZTEST_SHUFFLE` to randomize the order. The output from the test will display the seed for failed -tests. For native posix builds you can provide the seed as an argument to +tests. For native simulator builds you can provide the seed as an argument to twister with `--seed` Static configuration of ZTEST_SHUFFLE contains: @@ -592,7 +587,7 @@ Static configuration of ZTEST_SHUFFLE contains: Test Selection ************** -For POSIX enabled builds with ZTEST_NEW_API use command line arguments to list +For tests built for native simulator, use command line arguments to list or select tests to run. The test argument expects a comma separated list of ``suite::test`` . You can substitute the test name with an ``*`` to run all tests within a suite. diff --git a/doc/develop/toolchains/cadence_xcc.rst b/doc/develop/toolchains/cadence_xcc.rst index 5778c542068db3a..f1de7ed1e534845 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 adfd41cef9e539f..900601c97d3df99 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 c128708f50876ca..14cf70f61417dab 100644 --- a/doc/develop/toolchains/zephyr_sdk.rst +++ b/doc/develop/toolchains/zephyr_sdk.rst @@ -67,153 +67,169 @@ the recommended version for the corresponding Zephyr version. For the full list of compatible Zephyr and Zephyr SDK versions, refer to the `Zephyr SDK Version Compatibility Matrix`_. -.. _toolchain_zephyr_sdk_install_linux: +.. _toolchain_zephyr_sdk_install: -Install Zephyr SDK on Linux -*************************** +Zephyr SDK installation +*********************** + +.. toolchain_zephyr_sdk_install_start + +.. 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. + +.. note:: If you want to uninstall the SDK, you may simply remove the directory + where you installed it. + +.. tabs:: -#. Download and verify the `Zephyr SDK bundle`_: + .. group-tab:: Ubuntu - .. code-block:: bash + .. _ubuntu_zephyr_sdk: - 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 + #. Download and verify the `Zephyr SDK bundle`_: - You can change ``0.16.3`` to another version if needed; the `Zephyr SDK - Releases`_ page contains all available SDK releases. + .. parsed-literal:: - 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. + cd ~ + wget |sdk-url-linux| + wget -O - |sdk-url-linux-sha| | shasum --check --ignore-missing -#. Extract the Zephyr SDK bundle archive: + 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. - .. code-block:: bash + #. Extract the Zephyr SDK bundle archive: - cd - tar xvf zephyr-sdk-0.16.3_linux-x86_64.tar.xz + .. parsed-literal:: -#. Run the Zephyr SDK bundle setup script: + tar xvf zephyr-sdk- |sdk-version-trim| _linux-x86_64.tar.xz - .. code-block:: bash + .. note:: + It is recommended to extract the Zephyr SDK bundle at one of the following locations: - cd zephyr-sdk-0.16.3 - ./setup.sh + * ``$HOME`` + * ``$HOME/.local`` + * ``$HOME/.local/opt`` + * ``$HOME/bin`` + * ``/opt`` + * ``/usr/local`` - If this fails, make sure Zephyr's dependencies were installed as described - in :ref:`Install Requirements and Dependencies `. + 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 want to uninstall the SDK, remove the directory where you installed it. -If you relocate the SDK directory, you need to re-run the setup script. + #. Run the Zephyr SDK bundle setup script: -.. note:: - It is recommended to extract the Zephyr SDK bundle at one of the following - default locations: + .. parsed-literal:: - * ``$HOME`` - * ``$HOME/.local`` - * ``$HOME/.local/opt`` - * ``$HOME/bin`` - * ``/opt`` - * ``/usr/local`` + cd zephyr-sdk- |sdk-version-ltrim| + ./setup.sh - 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``. + .. note:: + You only need to run the setup script once after extracting the Zephyr SDK bundle. -.. _toolchain_zephyr_sdk_install_macos: + You must rerun the setup script if you relocate the Zephyr SDK bundle directory after + the initial setup. -Install Zephyr SDK on macOS -*************************** + #. Install `udev `_ rules, which + allow you to flash most Zephyr boards as a regular user: -#. Download and verify the `Zephyr SDK bundle`_: + .. parsed-literal:: - .. code-block:: bash + 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 - cd ~ - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_macos-x86_64.tar.xz - wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing + .. group-tab:: macOS - 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. + .. _macos_zephyr_sdk: -#. Extract the Zephyr SDK bundle archive: + #. Download and verify the `Zephyr SDK bundle`_: - .. code-block:: bash + .. parsed-literal:: - tar xvf zephyr-sdk-0.16.3_macos-x86_64.tar.xz + cd ~ + curl -L -O |sdk-url-macos| + curl -L |sdk-url-macos-sha| | shasum --check --ignore-missing - .. note:: - It is recommended to extract the Zephyr SDK bundle at one of the following - default locations: + 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. - * ``$HOME`` - * ``$HOME/.local`` - * ``$HOME/.local/opt`` - * ``$HOME/bin`` - * ``/opt`` - * ``/usr/local`` + #. Extract the Zephyr SDK bundle archive: - 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``. + .. parsed-literal:: -#. Run the Zephyr SDK bundle setup script: + tar xvf zephyr-sdk- |sdk-version-trim| _macos-x86_64.tar.xz - .. code-block:: bash + .. note:: + It is recommended to extract the Zephyr SDK bundle at one of the following locations: - cd zephyr-sdk-0.16.3 - ./setup.sh + * ``$HOME`` + * ``$HOME/.local`` + * ``$HOME/.local/opt`` + * ``$HOME/bin`` + * ``/opt`` + * ``/usr/local`` - .. note:: - You only need to run the setup script once after extracting the Zephyr SDK bundle. + The Zephyr SDK bundle archive contains the ``zephyr-sdk-`` + directory and, when extracted under ``$HOME``, the resulting + installation path will be ``$HOME/zephyr-sdk-``. - You must rerun the setup script if you relocate the Zephyr SDK bundle directory after - the initial setup. + #. Run the Zephyr SDK bundle setup script: -.. _toolchain_zephyr_sdk_install_windows: + .. parsed-literal:: -Install Zephyr SDK on Windows -***************************** + cd zephyr-sdk- |sdk-version-ltrim| + ./setup.sh -#. Open a ``cmd.exe`` window by pressing the Windows key typing "cmd.exe". + .. note:: + You only need to run the setup script once after extracting the Zephyr SDK bundle. -#. Download the `Zephyr SDK bundle`_: + You must rerun the setup script if you relocate the Zephyr SDK bundle directory after + the initial setup. - .. code-block:: console + .. group-tab:: Windows - cd %HOMEPATH% - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_windows-x86_64.7z + .. _windows_zephyr_sdk: -#. Extract the Zephyr SDK bundle archive: + #. Open a ``cmd.exe`` terminal window **as a regular user** - .. code-block:: console + #. Download the `Zephyr SDK bundle`_: - 7z x zephyr-sdk-0.16.3_windows-x86_64.7z + .. parsed-literal:: - .. note:: - It is recommended to extract the Zephyr SDK bundle at one of the following - default locations: + cd %HOMEPATH% + wget |sdk-url-windows| - * ``%HOMEPATH%`` - * ``%PROGRAMFILES%`` + #. Extract the Zephyr SDK bundle archive: - 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``. + .. parsed-literal:: -#. Run the Zephyr SDK bundle setup script: + 7z x zephyr-sdk- |sdk-version-trim| _windows-x86_64.7z - .. code-block:: console + .. note:: + It is recommended to extract the Zephyr SDK bundle at one of the following locations: - cd zephyr-sdk-0.16.3 - setup.cmd + * ``%HOMEPATH%`` + * ``%PROGRAMFILES%`` - .. note:: - You only need to run the setup script once after extracting the Zephyr SDK bundle. + The Zephyr SDK bundle archive contains the ``zephyr-sdk-`` + directory and, when extracted under ``%HOMEPATH%``, the resulting + installation path will be ``%HOMEPATH%\zephyr-sdk-``. - You must rerun the setup script if you relocate the Zephyr SDK bundle directory after - the initial setup. + #. Run the Zephyr SDK bundle setup script: + + .. parsed-literal:: + + cd zephyr-sdk- |sdk-version-ltrim| + setup.cmd + + .. note:: + You only need to run the setup script once after extracting the Zephyr SDK bundle. + + 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 + +.. toolchain_zephyr_sdk_install_end diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index 0f9f15ef9d7ffd8..8356d95cade643b 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/built-in.rst b/doc/develop/west/built-in.rst index 085a37fdc647c5c..b54dbaad54fc0de 100644 --- a/doc/develop/west/built-in.rst +++ b/doc/develop/west/built-in.rst @@ -245,13 +245,14 @@ West has a few more commands for managing the projects in the workspace, which are summarized here. Run ``west -h`` for detailed help. +- ``west compare``: compare the state of the workspace against the manifest +- ``west diff``: run ``git diff`` in local project repositories +- ``west forall``: run an arbitrary command in local project repositories +- ``west grep``: search for patterns in local project repositories - ``west list``: print a line of information about each project in the manifest, according to a format string - ``west manifest``: manage the manifest file. See :ref:`west-manifest-cmd`. -- ``west diff``: run ``git diff`` in local project repositories - ``west status``: run ``git status`` in local project repositories -- ``west forall``: run an arbitrary command in local project repositories -- ``west compare``: compare the state of the workspace against the manifest Other built-in commands *********************** diff --git a/doc/develop/west/config.rst b/doc/develop/west/config.rst index 594b54cbbe70302..eae6c7e4b9ecb5a 100644 --- a/doc/develop/west/config.rst +++ b/doc/develop/west/config.rst @@ -135,6 +135,24 @@ commands are documented in the pages for those commands. stdout is a terminal. * - ``commands.allow_extensions`` - Boolean, default ``true``, disables :ref:`west-extensions` if ``false`` + * - ``grep.color`` + - String, default empty. Set this to ``never`` to disable ``west grep`` + color output. If set, ``west grep`` passes the value to the grep tool's + ``--color`` option. + * - ``grep.tool`` + - String, one of ``"git-grep"`` (default), ``"ripgrep"``, or ``"grep"``. + The grep tool that ``west grep`` should use. + * - ``grep.-args`` + - String, default empty. The ```` part is a pattern that can be any + ``grep.tool`` value, so ``grep.ripgrep-args`` is an example + configuration option. If set, arguments that ``west grep`` should pass + to the corresponding grep tool. Run ``west help grep`` for details. + * - ``grep.-path`` + - String, default empty. The ```` part is a pattern that can be any + ``grep.tool`` value, so ``grep.ripgrep-path`` is an example + configuration option. The path to the corresponding tool that ``west + grep`` should use instead of searching for the command. Run ``west help + grep`` for details. * - ``manifest.file`` - String, default ``west.yml``. Relative path from the manifest repository root directory to the manifest file used by ``west init`` and other diff --git a/doc/develop/west/index.rst b/doc/develop/west/index.rst index 627267fb250d9c7..7b5fd6b2cce86f2 100644 --- a/doc/develop/west/index.rst +++ b/doc/develop/west/index.rst @@ -26,9 +26,6 @@ You can run ``west --help`` (or ``west -h`` for short) to get top-level help for available west commands, and ``west -h`` for detailed help on each command. -The following pages document west's ``v1.0.y`` releases, and provide additional -context about the tool. - .. toctree:: :maxdepth: 1 diff --git a/doc/develop/west/manifest.rst b/doc/develop/west/manifest.rst index 3f2fa74e306ce7c..f989cdcae1e2ba6 100644 --- a/doc/develop/west/manifest.rst +++ b/doc/develop/west/manifest.rst @@ -174,9 +174,13 @@ Here is an example. We'll assume the ``remotes`` given above. # [... same remotes as above...] projects: - name: proj1 + description: the first example project remote: remote1 path: extra/project-1 - name: proj2 + description: | + A multi-line description of the second example + project. repo-path: my-path remote: remote2 revision: v1.3 @@ -229,6 +233,10 @@ next. reserved values "west" or "manifest". The name must be unique in the manifest file. + * - ``description`` + - Optional, an informational description of the project. Added in + west v1.2.0. + * - ``remote``, ``url`` - Mandatory (one of the two, but not both). @@ -240,7 +248,7 @@ next. remote Git repository. If the project has neither, the ``defaults`` section must specify a - ``remote``, which will be used as the the project's remote. Otherwise, + ``remote``, which will be used as the project's remote. Otherwise, the manifest is invalid. * - ``repo-path`` @@ -331,9 +339,13 @@ so far using ``defaults`` is: projects: - name: proj1 + description: the first example project path: extra/project-1 revision: master - name: proj2 + description: | + A multi-line description of the second example + project. repo-path: my-path remote: remote2 - name: proj3 @@ -487,6 +499,10 @@ about the manifest file features that were introduced in that version. - Identical to ``"0.13"``, but available for use by users that do not wish to use a ``"0.x"`` version field. + * - ``"1.2"`` + - Support for ``description:`` in ``projects:`` + (:ref:`west-manifests-projects`) + .. note:: Versions of west without any new features in the manifest file format do not @@ -1108,7 +1124,7 @@ recursively update the project's Git submodules whenever it updates the project itself. If it's ``false`` or missing, it has no effect. For example, let's say you have a source code repository ``foo``, which has -some submodules, and you want ``west update`` to keep all of them them in sync, +some submodules, and you want ``west update`` to keep all of them in sync, along with another project named ``bar`` in the same workspace. You can do that with this manifest file: @@ -2033,8 +2049,8 @@ The ultimate outcomes of resolving manifest imports are: - a ``projects`` list, which is produced by combining the ``projects`` defined in the top-level file with those defined in imported files -- a set of extension commands, which are drawn from the the ``west-commands`` - keys in in the top-level file and any imported files +- a set of extension commands, which are drawn from the ``west-commands`` + keys in the top-level file and any imported files - a ``group-filter`` list, which is produced by combining the top-level and any imported filters diff --git a/doc/develop/west/release-notes.rst b/doc/develop/west/release-notes.rst index 98d67da96d939f9..951cc4c3e374589 100644 --- a/doc/develop/west/release-notes.rst +++ b/doc/develop/west/release-notes.rst @@ -3,6 +3,81 @@ West Release Notes ################## +v1.2.0 +****** + +Major changes: + +- New ``west grep`` command for running a "grep tool" in your west workspace's + repositories. Currently, ``git grep``, `ripgrep`_, and standard ``grep`` are + supported grep tools. + + To run this command to get ``git grep foo`` results from all cloned, + active repositories, run: + + .. code-block:: console + + west grep foo + + Here are some other examples for running different grep commands + with ``west grep``: + + .. list-table:: + + * - ``git grep --untracked`` + - ``west grep --untracked foo`` + * - ``ripgrep`` + - ``west grep --tool ripgrep foo`` + * - ``grep --recursive`` + - ``west grep --tool grep foo`` + + To switch the default grep tool in your workspace, run the appropriate + command in this table: + + .. list-table:: + + * - ``ripgrep`` + - ``west config grep.tool ripgrep`` + * - ``grep`` + - ``west config grep.tool grep`` + + For more details, run ``west help grep``. + +Other changes: + +- The manifest file format now supports a ``description`` field in each + ``projects:`` element. See :ref:`west-manifests-projects` for examples. + +- ``west list --format`` now accepts ``{description}`` in the format + string, which prints the project's ``description:`` value. + +- ``west compare`` now always prints information about + :ref:`west-manifest-rev`. + +Bug fixes: + +- ``west init`` aborts if the destination directory already exists. + +API changes: + +- ``west.commands.WestCommand`` methods ``check_call()`` and + ``check_output()`` now take any kwargs that can be passed on + to the underlying subprocess function. + +- ``west.commands.WestCommand.run_subprocess()``: new wrapper + around ``subprocess.run()``. This could not be named ``run()`` + because ``WestCommand`` already had a method by this name. + +- ``west.commands.WestCommand`` methods ``dbg()``, ``inf()``, + ``wrn()``, and ``err()`` now all take an ``end`` kwarg, which + is passed on to the call to ``print()``. + +- ``west.manifest.Project`` now has a ``description`` attribute, + which contains the parsed value of the ``description:`` field + in the manifest data. + +.. _ripgrep: https://github.com/BurntSushi/ripgrep#readme + v1.1.0 ****** @@ -594,7 +669,7 @@ The developer-visible changes to the :ref:`west-apis` are: West now requires Python 3.6 or later. Additionally, some features may rely on Python dictionaries being insertion-ordered; this is only an implementation -detail in CPython 3.6, but is is part of the language specification as of +detail in CPython 3.6, but it is part of the language specification as of Python 3.7. v0.6.3 diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index 44193d4611f3231..8cc55ffeea4e80b 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -40,7 +40,7 @@ Notes on the above commands: - ``YOUR_BOARD`` should be changed to match your board - The ``CONFIG_MCUBOOT_SIGNATURE_KEY_FILE`` value is the insecure default - provided and used by by MCUboot for development and testing + provided and used by MCUboot for development and testing - You can change the ``hello_world`` application directory to any other application that can be loaded by MCUboot, such as the :zephyr:code-sample:`smp-svr` sample. diff --git a/doc/develop/west/west-apis.rst b/doc/develop/west/west-apis.rst index ec60bc6fe56aa49..306cef813e8b672 100644 --- a/doc/develop/west/west-apis.rst +++ b/doc/develop/west/west-apis.rst @@ -137,14 +137,39 @@ WestCommand .. automethod:: add_pre_run_hook .. versionadded:: 1.0.0 - .. automethod:: check_call + .. NOTE: the following 'method' (not 'automethod') directives were added for + expediency during the west v1.2 release time frame to work around a build + failure in this zephyr documentation that could not be fixed without + cutting a west point release. (The docstrings in west had some RST syntax + errors). + These should be reverted back to automethod calls at the next release. + + .. method:: check_call(args, **kwargs) + + Runs ``subprocess.check_call(args, **kwargs)`` after + logging the call at Verbosity.DBG_MORE`` level. + + .. versionchanged:: 1.2.0 + The *cwd* keyword argument was replaced with a catch-all ``**kwargs``. .. versionchanged:: 0.11.0 - .. automethod:: check_output + .. method:: check_output(args, **kwargs) + + Runs ``subprocess.check_output(args, **kwargs)`` after + logging the call at Verbosity.DBG_MORE level. + .. versionchanged:: 1.2.0 + The *cwd* keyword argument was replaced with a catch-all ``**kwargs``. .. versionchanged:: 0.11.0 + .. method:: run_subprocess(args, **kwargs) + + Runs ``subprocess.run(args, **kwargs)`` after logging + the call at Verbosity.DBG_MORE level. + + .. versionadded:: 1.2.0 + All subclasses must provide the following abstract methods, which are used to implement the above: @@ -158,15 +183,23 @@ WestCommand "quiet" mode for west commands in a future release: .. automethod:: dbg + .. versionchanged:: 1.2.0 + The *end* argument. .. versionadded:: 1.0.0 .. automethod:: inf + .. versionchanged:: 1.2.0 + The *end* argument. .. versionadded:: 1.0.0 .. automethod:: wrn + .. versionchanged:: 1.2.0 + The *end* argument. .. versionadded:: 1.0.0 .. automethod:: err + .. versionchanged:: 1.2.0 + The *end* argument. .. versionadded:: 1.0.0 .. automethod:: die @@ -396,10 +429,6 @@ Manifest and sub-objects .. (note: attributes are part of the class docstring) - .. versionchanged:: 0.8.0 - The *west_commands* attribute is now always a list. In previous - releases, it could be a string or ``None``. - .. versionchanged:: 0.7.0 The *remote* attribute was removed. Its semantics could no longer be preserved when support for manifest ``import`` keys was added. @@ -407,12 +436,19 @@ Manifest and sub-objects .. versionadded:: 0.7.0 The *remote_name* and *name_and_path* attributes. + .. versionchanged:: 0.8.0 + The *west_commands* attribute is now always a list. In previous + releases, it could be a string or ``None``. + .. versionadded:: 0.9.0 The *group_filter* and *submodules* attributes. .. versionadded:: 0.12.0 The *userdata* attribute. + .. versionadded:: 1.2.0 + The *description* attribute. + Constructor: .. automethod:: __init__ diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 056d22e48ebde2f..f6b2322e6a4922a 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/glossary.rst b/doc/glossary.rst index 95781c665f67911..8571f4b6d491eb0 100644 --- a/doc/glossary.rst +++ b/doc/glossary.rst @@ -51,7 +51,7 @@ Glossary of Terms device runtime power management Device Runtime Power Management (PM) refers the capability of devices to - save energy independently of the the system power state. Devices will keep + save energy independently of the system power state. Devices will keep reference of their usage and will automatically be suspended or resumed. This feature is enabled via the :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME` Kconfig option. @@ -89,7 +89,7 @@ Glossary of Terms system power state System power states describe the power consumption of the system as a - whole. System power states are are represented by :c:enum:`pm_state`. + whole. System power states are represented by :c:enum:`pm_state`. west A multi-repo meta-tool developed for the Zephyr project. See :ref:`west`. diff --git a/doc/hardware/arch/arm_cortex_m.rst b/doc/hardware/arch/arm_cortex_m.rst index b037896776faccc..1c074618567fc3d 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 000000000000000..3568b0abbdc0506 --- /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 25173530ca205e7..000000000000000 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 eac62bf9da65553..000000000000000 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 000000000000000..6aa5e703a7006b9 --- /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 ad64956fe6859de..000000000000000 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 000000000000000..a8615ff02a848dd --- /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 23ed94a192aecef..0369876783ad0ff 100644 --- a/doc/hardware/emulator/index.rst +++ b/doc/hardware/emulator/index.rst @@ -1,188 +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_posix 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_posix. 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_posix 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_posix. 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_posix`` 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_posix`` 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_posix - :goals: build - -#. Simple test of the EEPROM emulator: - - .. zephyr-app-commands:: - :app: tests/drivers/eeprom - :board: native_posix - :goals: build - -#. The same test has a second EEPROM which is an Atmel AT24 EEPROM driver - connected via I2C an emulator: - - .. zephyr-app-commands:: - :app: tests/drivers/eeprom - :board: native_posix - :goals: build - -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 c9ba1c92f8ae3ea..72e9cc5fd0561ad 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/auxdisplay.rst b/doc/hardware/peripherals/auxdisplay.rst index b3cb6cbae5babeb..913b43f2779c87e 100644 --- a/doc/hardware/peripherals/auxdisplay.rst +++ b/doc/hardware/peripherals/auxdisplay.rst @@ -9,7 +9,7 @@ Overview Auxiliary Displays are text-based displays that have simple interfaces for displaying textual, numeric or alphanumeric data, as opposed to the :ref:`display_api`, auxiliary displays do not support custom -graphical output to displays (and and most often monochrome), the most +graphical output to displays (and most often monochrome), the most advanced custom feature supported is generation of custom characters. These inexpensive displays are commonly found with various configurations and sizes, a common display size is 16 characters by 2 lines. diff --git a/doc/hardware/peripherals/bc12.rst b/doc/hardware/peripherals/bc12.rst index 00c9bcdb677b017..a612a403dbbd96c 100644 --- a/doc/hardware/peripherals/bc12.rst +++ b/doc/hardware/peripherals/bc12.rst @@ -74,7 +74,7 @@ Charging port mode is used by the application when the USB port is configured as a downstream facing port, i.e. a USB host port. For charging port mode, the BC1.2 driver powers up the detection chip and configures the charger type specified by a devicetree property. If the driver supports detection of plug and -and unplug events, the BC1.2 driver notifies the callback registered with +unplug events, the BC1.2 driver notifies the callback registered with ``bc12_set_result_cb()`` to indicate the current connection state of the portable device partner. diff --git a/doc/hardware/peripherals/canbus/controller.rst b/doc/hardware/peripherals/can/controller.rst similarity index 89% rename from doc/hardware/peripherals/canbus/controller.rst rename to doc/hardware/peripherals/can/controller.rst index 8724b96515a6f69..e87102013498b60 100644 --- a/doc/hardware/peripherals/canbus/controller.rst +++ b/doc/hardware/peripherals/can/controller.rst @@ -16,22 +16,6 @@ ISO 11898-1:2003 standard. CAN is mostly known for its application in the automotive domain. However, it is also used in home and industrial automation and other products. -A CAN transceiver is an external device that converts the logic level signals -from the CAN controller to the bus-levels. The bus lines are called -CAN High (CAN H) and CAN Low (CAN L). -The transmit wire from the controller to the transceiver is called CAN TX, -and the receive wire is called CAN RX. -These wires use the logic levels whereas the bus-level is interpreted -differentially between CAN H and CAN L. -The bus can be either in the recessive (logical one) or dominant (logical zero) -state. The recessive state is when both lines, CAN H and CAN L, at roughly at -the same voltage level. This state is also the idle state. -To write a dominant bit to the bus, open-drain transistors tie CAN H to Vdd -and CAN L to ground. -The first and last node use a 120-ohm resistor between CAN H and CAN L to -terminate the bus. The dominant state always overrides the recessive state. -This structure is called a wired-AND. - .. warning:: CAN controllers can only initialize when the bus is in the idle (recessive) @@ -39,12 +23,6 @@ This structure is called a wired-AND. CAN RX is high, at least for a short time. This is also necessary for loopback mode. -.. image:: transceiver.svg - :width: 70% - :align: center - :alt: CAN Transceiver - - The bit-timing as defined in ISO 11898-1:2003 looks as following: .. image:: timing.svg @@ -225,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 }; @@ -248,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 }; @@ -314,7 +292,7 @@ The following example sets the bitrate to 250k baud with the sampling point at LOG_ERR("Failed to start CAN controller"); } -A similar API exists for calculating and setting the timing for the data phase for CAN-FD capable +A similar API exists for calculating and setting the timing for the data phase for CAN FD capable controllers. See :c:func:`can_set_timing_data` and :c:func:`can_calc_timing_data`. SocketCAN @@ -340,9 +318,3 @@ CAN Controller API Reference **************************** .. doxygengroup:: can_interface - - -CAN Transceiver API Reference -***************************** - -.. doxygengroup:: can_transceiver diff --git a/doc/hardware/peripherals/can/index.rst b/doc/hardware/peripherals/can/index.rst new file mode 100644 index 000000000000000..c605bdd03010fcc --- /dev/null +++ b/doc/hardware/peripherals/can/index.rst @@ -0,0 +1,11 @@ +.. _can: + +Controller Area Network (CAN) +############################# + +.. toctree:: + :maxdepth: 2 + + 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 000000000000000..5b161fde5d6f2bb --- /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/canbus/timing.svg b/doc/hardware/peripherals/can/timing.svg similarity index 100% rename from doc/hardware/peripherals/canbus/timing.svg rename to doc/hardware/peripherals/can/timing.svg diff --git a/doc/hardware/peripherals/can/transceiver.rst b/doc/hardware/peripherals/can/transceiver.rst new file mode 100644 index 000000000000000..26db7856818e863 --- /dev/null +++ b/doc/hardware/peripherals/can/transceiver.rst @@ -0,0 +1,37 @@ +.. _can_transceiver_api: + +CAN Transceiver +############### + +.. contents:: + :local: + :depth: 2 + +Overview +******** + +A CAN transceiver is an external device that converts the logic level signals +from the CAN controller to the bus-levels. The bus lines are called +CAN High (CAN H) and CAN Low (CAN L). +The transmit wire from the controller to the transceiver is called CAN TX, +and the receive wire is called CAN RX. +These wires use the logic levels whereas the bus-level is interpreted +differentially between CAN H and CAN L. +The bus can be either in the recessive (logical one) or dominant (logical zero) +state. The recessive state is when both lines, CAN H and CAN L, are roughly at +the same voltage level. This state is also the idle state. +To write a dominant bit to the bus, open-drain transistors tie CAN H to Vdd +and CAN L to ground. +The first and last node use a 120-ohm resistor between CAN H and CAN L to +terminate the bus. The dominant state always overrides the recessive state. +This structure is called a wired-AND. + +.. image:: transceiver.svg + :width: 70% + :align: center + :alt: CAN Transceiver + +CAN Transceiver API Reference +***************************** + +.. doxygengroup:: can_transceiver diff --git a/doc/hardware/peripherals/canbus/transceiver.svg b/doc/hardware/peripherals/can/transceiver.svg similarity index 100% rename from doc/hardware/peripherals/canbus/transceiver.svg rename to doc/hardware/peripherals/can/transceiver.svg diff --git a/doc/hardware/peripherals/canbus/index.rst b/doc/hardware/peripherals/canbus/index.rst deleted file mode 100644 index 844ab945ff9a949..000000000000000 --- a/doc/hardware/peripherals/canbus/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -.. _canbus: - -Controller Area Network (CAN) -############################# - -.. toctree:: - :maxdepth: 2 - - controller.rst - isotp.rst diff --git a/doc/hardware/peripherals/charger.rst b/doc/hardware/peripherals/charger.rst index a3e2c177e3eeee1..0198fe11f656775 100644 --- a/doc/hardware/peripherals/charger.rst +++ b/doc/hardware/peripherals/charger.rst @@ -3,12 +3,16 @@ Chargers ######## -The charger subsystem exposes an API to uniformly access battery charger devices. Currently, -only reading data is supported. +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 ========== @@ -18,8 +22,8 @@ measure. Chargers typically support multiple properties, such as temperature readings of the battery-pack or present-time current/voltage. -Properties are fetched using a client allocated array of :c:struct:`charger_get_property`. This -array is then populated by values as according to its `property_type` field. +Properties are fetched by the client one at a time using :c:func:`charger_get_prop`. +Properties are set by the client one at a time using :c:func:`charger_set_prop`. .. _charger_api_reference: diff --git a/doc/hardware/peripherals/dma.rst b/doc/hardware/peripherals/dma.rst index 198590905d369cc..53fd18a1aa70d80 100644 --- a/doc/hardware/peripherals/dma.rst +++ b/doc/hardware/peripherals/dma.rst @@ -6,6 +6,72 @@ Direct Memory Access (DMA) Overview ******** +Direct Memory Access (Controller) is a commonly provided type of co-processor that can typically +offload transferring data to and from peripherals and memory. + +The DMA API is not a portable API and really cannot be as each DMA has unique memory requirements, +peripheral interactions, and features. The API in effect provides a union of all useful DMA +functionality drivers have needed in the tree. It can still be a good abstraction, with care, for +peripheral devices for vendors where the DMA IP might be very similar but have slight variances. + +Driver Implementation Expectations +********************************** + +Synchronization and Ownership ++++++++++++++++++++++++++++++ + +From an API point of view, a DMA channel is a single-owner object, meaning the drivers should not +attempt to wrap a channel with kernel synchronization primitives such as mutexes or semaphores. If +DMA channels require mutating shared registers, those register updates should be wrapped in a spin +lock. + +This enables the entire API to be low-cost and callable from any call context, including ISRs where +it may be very useful to start/stop/suspend/resume/reload a channel transfer. + +Transfer Descriptor Memory Management ++++++++++++++++++++++++++++++++++++++ + +Drivers should not attempt to use heap allocations of any kind. If object pools are needed for +transfer descriptors then those should be setup in a way that does not break the promise of +ISR-allowable calls. Many drivers choose to create a simple static descriptor array per channel with +the size of the descriptor array adjustable using Kconfig. + +Channel State Machine Expectations +++++++++++++++++++++++++++++++++++ + +DMA channels should be viewed as state machines that the DMA API provides transition events for in +the form of API calls. Every driver is expected to maintain its own channel state tracking. The busy +state of the channel should be inspectable at any time with :c:func:`dma_get_status()`. + +A diagram showing those expectated possible state transitions and their API calls is provided here +for reference. + +.. graphviz:: + :caption: DMA state finite state machine + + digraph { + node [style=rounded]; + edge [fontname=Courier]; + init [shape=point]; + + CONFIGURED [label=Configured,shape=box]; + RUNNING [label=Running,shape=box]; + SUSPENDED [label=Suspended,shape=box]; + + init -> CONFIGURED [label=dma_config]; + + CONFIGURED -> RUNNING [label=dma_start]; + CONFIGURED -> CONFIGURED [label=dma_stop]; + + RUNNING -> CONFIGURED [label=dma_stop]; + RUNNING -> RUNNING [label=dma_start]; + RUNNING -> RUNNING [label=dma_resume, headport=w]; + RUNNING -> SUSPENDED [label=dma_suspend]; + + SUSPENDED -> SUSPENDED [label=dma_suspend]; + SUSPENDED -> RUNNING [label=dma_resume]; + SUSPENDED -> CONFIGURED [label=dma_stop]; + } API Reference ************* diff --git a/doc/hardware/peripherals/gnss.rst b/doc/hardware/peripherals/gnss.rst new file mode 100644 index 000000000000000..bcc40e540ab7ed2 --- /dev/null +++ b/doc/hardware/peripherals/gnss.rst @@ -0,0 +1,50 @@ +.. _gnss_api: + +GNSS (Global Navigation Satellite System) +######################################### + +Overview +******** + +GNSS is a general term which covers satellite systems used for +navigation, like GPS (Global Positioning System). GNSS services +are usually accessed through GNSS modems which receive and +process GNSS signals to determine their position, or more +specifically, their antennas position. They usually +additionally provide a precise time synchronization mechanism, +commonly named PPS (Pulse-Per-Second). + +Subsystem support +***************** + +The GNSS subsystem is based on the :ref:`modem`. The GNSS +subsystem covers everything from sending and receiving commands +to and from the modem, to parsing, creating and processing +NMEA0183 messages. + +Adding support for additional NMEA0183 based GNSS modems +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 +buses than the usual NMEA0183 over UART is possible, but will +require a bit more work from the driver developer. + +Configuration Options +********************* + +Related configuration options: + +* :kconfig:option:`CONFIG_GNSS` +* :kconfig:option:`CONFIG_GNSS_SATELLITES` +* :kconfig:option:`CONFIG_GNSS_DUMP_TO_LOG` + +Navigation Reference +******************** + +.. doxygengroup:: navigation + +GNSS API Reference +****************** + +.. doxygengroup:: gnss_interface diff --git a/doc/hardware/peripherals/i3c.rst b/doc/hardware/peripherals/i3c.rst index 4ffb6dd45e441e8..347d8944ef171dd 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 ff80c0e9eb5d59c..19461b6c9f4c1ad 100644 --- a/doc/hardware/peripherals/index.rst +++ b/doc/hardware/peripherals/index.rst @@ -16,7 +16,7 @@ Peripherals bbram.rst bc12.rst clock_control.rst - canbus/index.rst + can/index.rst charger.rst coredump.rst counter.rst @@ -29,6 +29,7 @@ Peripherals edac/index.rst flash.rst fuel_gauge.rst + gnss.rst gpio.rst hwinfo.rst i2c_eeprom_target.rst diff --git a/doc/hardware/peripherals/rtc.rst b/doc/hardware/peripherals/rtc.rst index c279c7c79131335..ae69df0b4464eea 100644 --- a/doc/hardware/peripherals/rtc.rst +++ b/doc/hardware/peripherals/rtc.rst @@ -84,9 +84,9 @@ and clock calibration, these must be enabled by selecting :kconfig:option:`CONFIG_RTC_ALARM`, :kconfig:option:`CONFIG_RTC_UPDATE` and :kconfig:option:`CONFIG_RTC_CALIBRATION`. -The following examples build the test suite for the ``native_posix`` +The following examples build the test suite for the ``native_sim`` board. To build the test suite for a different board, replace the -``native_posix`` board with your board. +``native_sim`` board with your board. To build the test application with the default configuration, testing only the mandatory features, the following command can be used for @@ -95,7 +95,7 @@ reference: .. zephyr-app-commands:: :tool: west :host-os: unix - :board: native_posix + :board: native_sim :zephyr-app: tests/drivers/rtc/rtc_api :goals: build @@ -106,7 +106,7 @@ following command can be used for reference: .. zephyr-app-commands:: :tool: west :host-os: unix - :board: native_posix + :board: native_sim :zephyr-app: tests/drivers/rtc/rtc_api :goals: menuconfig @@ -115,7 +115,7 @@ Then build the test application using the following command: .. zephyr-app-commands:: :tool: west :host-os: unix - :board: native_posix + :board: native_sim :zephyr-app: tests/drivers/rtc/rtc_api :maybe-skip-config: :goals: build @@ -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 42906bca6fab028..177a54dbbfef756 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 c67f46a0cb1a1bf..98edfeacf586142 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 a4e1e753cffff7c..62b79cdb0323342 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 ******************* @@ -59,11 +69,11 @@ Common steps for all architectures: * Setup an initial stack. * If running an :abbr:`XIP (eXecute-In-Place)` kernel, copy initialized data -* from ROM to RAM. + 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 @@ -535,24 +545,23 @@ The region specified by ``thread.stack_info.start`` and the initial stack pointer from the very end of the stack object, taking into account storage for TLS and ASLR random offsets. -:: - - +---------------------+ <- 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 +.. 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 At present, Zephyr does not support stacks that grow upward. @@ -624,7 +633,7 @@ simply leave an non-present virtual page below every stack when it is mapped into the address space. The stack object will still need to be properly aligned and sized to page granularity. -:: +.. code-block:: none +-----------------------------+ <- thread.stack_obj | Guard reserved memory | } K_KERNEL_STACK_RESERVED @@ -683,7 +692,7 @@ On systems without power-of-two region requirements, the reserved memory area for threads stacks defined by :c:macro:`K_THREAD_STACK_RESERVED` may be used to contain the privilege mode stack. The layout could be something like: -:: +.. code-block:: none +------------------------------+ <- thread.stack_obj | Other platform data | @@ -742,7 +751,7 @@ of the privilege stacks can be looked up quickly at runtime based on the thread stack address using :c:func:`z_priv_stack_find()`. These stacks are laid out the same way as other kernel-only stacks. -:: +.. code-block:: none +-----------------------------+ <- z_priv_stack_find(thread.stack_obj) | Reserved memory | } K_KERNEL_STACK_RESERVED diff --git a/doc/hardware/porting/board_porting.rst b/doc/hardware/porting/board_porting.rst index 5b21cbf2b681a34..5be561aecb25176 100644 --- a/doc/hardware/porting/board_porting.rst +++ b/doc/hardware/porting/board_porting.rst @@ -327,7 +327,7 @@ named ``plank``: This should at least contain a definition for a ``BOARD_PLANK`` option, which looks something like this: - .. code-block:: none + .. code-block:: kconfig config BOARD_PLANK bool "Plank board" @@ -340,7 +340,7 @@ named ``plank``: The entire file should be inside an ``if BOARD_PLANK`` / ``endif`` pair of lines, like this: - .. code-block:: none + .. code-block:: kconfig if BOARD_PLANK @@ -369,10 +369,10 @@ named ``plank``: your system clock, console, etc. The results are architecture-specific, but typically look something like this: - .. code-block:: none + .. code-block:: cfg - CONFIG_SOC_${VENDOR_XYZ3000}=y /* select your SoC */ - CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=120000000 /* set up your clock, etc */ + CONFIG_SOC_${VENDOR_XYZ3000}=y # select your SoC + CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=120000000 # set up your clock, etc CONFIG_SERIAL=y :file:`plank_x_y_z.conf` diff --git a/doc/hardware/porting/shields.rst b/doc/hardware/porting/shields.rst index 0f6c1a9a7a4dfb3..9eca06177b4fa16 100644 --- a/doc/hardware/porting/shields.rst +++ b/doc/hardware/porting/shields.rst @@ -101,7 +101,7 @@ CMake command Alternatively, it could be set by default in a project's CMakeLists.txt: -.. code-block:: none +.. code-block:: cmake set(SHIELD x_nucleo_iks01a1) @@ -153,7 +153,7 @@ node`_ that looks like the following into the board devicetree file: .. _nexus node: https://github.com/devicetree-org/devicetree-specification/blob/4b1dac80eaca45b4babf5299452a951008a5d864/source/devicetree-basics.rst#nexus-nodes-and-specifier-mapping -.. code-block:: none +.. code-block:: devicetree arduino_header: connector { compatible = "arduino-header-r3"; @@ -193,7 +193,7 @@ bits of the flags correspond to features that can be configured in devicetree. In some cases it's necessary to use a non-zero flag value to tell the driver how a particular pin behaves, as with: -.. code-block:: none +.. code-block:: devicetree drdy-gpios = <&arduino_header 11 GPIO_ACTIVE_LOW>; diff --git a/doc/index-tex.rst b/doc/index-tex.rst index 09ef9e9459e64ea..9c0527ae73a0efa 100644 --- a/doc/index-tex.rst +++ b/doc/index-tex.rst @@ -24,3 +24,4 @@ Zephyr Project Documentation project/index.rst security/index.rst safety/index.rst + glossary.rst diff --git a/doc/introduction/index.rst b/doc/introduction/index.rst index 918801fc7d43ec3..f8b841ae300222c 100644 --- a/doc/introduction/index.rst +++ b/doc/introduction/index.rst @@ -9,6 +9,7 @@ sensors and LED wearables to sophisticated embedded controllers, smart watches, and IoT wireless applications. The Zephyr kernel supports multiple architectures, including: + - ARCv2 (EM and HS) and ARCv3 (HS6X) - ARMv6-M, ARMv7-M, and ARMv8-M (Cortex-M) - ARMv7-A and ARMv8-A (Cortex-A, 32- and 64-bit) @@ -79,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. @@ -122,7 +125,7 @@ Zephyr offers a large and ever growing number of features including: **Bluetooth Low Energy 5.0 support** Bluetooth 5.0 compliant (ESR10) and Bluetooth Low Energy Controller support - (LE Link Layer). Includes Bluetooth mesh and a Bluetooth qualification-ready + (LE Link Layer). Includes Bluetooth Mesh and a Bluetooth qualification-ready Bluetooth controller. * Generic Access Profile (GAP) with all possible LE roles @@ -143,13 +146,12 @@ Zephyr offers a large and ever growing number of features including: **Native Linux, macOS, and Windows Development** A command-line CMake build environment runs on popular developer OS - systems. A native POSIX port lets you build and run Zephyr as a native - application on Linux and other OSes, aiding development and testing. + systems. A native port (:ref:`native_sim `) lets you build and run Zephyr as a native + application on Linux, aiding development and testing. -**Virtual File System Interface with LittleFS and FATFS Support** - LittleFS and FATFS Support, - FCB (Flash Circular Buffer) for memory constrained applications, and - file system enhancements for logging and configuration. +**Virtual File System Interface with ext2, FatFs, and LittleFS Support** + ext2, LittleFS and FatFS support; FCB (Flash Circular Buffer) for memory constrained + applications. **Powerful multi-backend logging Framework** Support for log filtering, object dumping, panic mode, multiple backends @@ -170,9 +172,9 @@ Zephyr offers a large and ever growing number of features including: NVS allows storage of binary blobs, strings, integers, longs, and any combination of these. -**Native POSIX port** - Supports running Zephyr as a Linux application with support for various - subsystems and networking. +**Native port** + :ref:`Native sim ` allows running Zephyr as a Linux application with support + for various subsystems and networking. .. include:: ../../README.rst diff --git a/doc/kernel/code-relocation.rst b/doc/kernel/code-relocation.rst index a9da18e98cd4a3b..599cdedccbd7459 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/data_structures/mpsc_pbuf.rst b/doc/kernel/data_structures/mpsc_pbuf.rst index 4ecef5b62e476fe..73780d6a42671ac 100644 --- a/doc/kernel/data_structures/mpsc_pbuf.rst +++ b/doc/kernel/data_structures/mpsc_pbuf.rst @@ -54,7 +54,7 @@ Header state: +-------+------+----------------------+ Packet buffer space contains free space, valid user packets and internal skip -packets. Internal skip packets indicates padding, e.g. at the of the buffer. +packets. Internal skip packets indicates padding, e.g. at the end of the buffer. Allocation ^^^^^^^^^^ diff --git a/doc/kernel/data_structures/rbtree.rst b/doc/kernel/data_structures/rbtree.rst index 135960200f8fe41..aac446cbad6e313 100644 --- a/doc/kernel/data_structures/rbtree.rst +++ b/doc/kernel/data_structures/rbtree.rst @@ -27,7 +27,7 @@ the algorithm to work correctly. As with the slist and dlist containers, nodes within an rbtree are represented as a :c:struct:`rbnode` structure which exists in -user-managed memory, typically embedded within the the data structure +user-managed memory, typically embedded within the data structure being tracked in the tree. Unlike the list code, the data within an rbnode is entirely opaque. It is not possible for the user to extract the binary tree topology and "manually" traverse the tree as it is for diff --git a/doc/kernel/data_structures/slist.rst b/doc/kernel/data_structures/slist.rst index add76e869a61164..c1eb062ff83dfdf 100644 --- a/doc/kernel/data_structures/slist.rst +++ b/doc/kernel/data_structures/slist.rst @@ -108,7 +108,7 @@ ways identically to the slist API. It adds the ability to associate exactly two bits of user defined "flags" with each list node. These can be accessed and modified with -:c:func:`sys_sfnode_flags_get` and :c:func:`sys_sfnode_flags_get`. +:c:func:`sys_sfnode_flags_get` and :c:func:`sys_sfnode_flags_set`. Internally, the flags are stored unioned with the bottom bits of the next pointer and incur no SRAM storage overhead when compared with the simpler slist code. diff --git a/doc/kernel/drivers/device_driver_model.svg b/doc/kernel/drivers/device_driver_model.svg index 9ace8badffcf78b..fe779232eec92c9 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/drivers/index.rst b/doc/kernel/drivers/index.rst index 33e1027c07eea15..51b31de006f72c8 100644 --- a/doc/kernel/drivers/index.rst +++ b/doc/kernel/drivers/index.rst @@ -235,11 +235,11 @@ implementation of both the subsystem API and the specific APIs: #ifdef CONFIG_USERSPACE - #include + #include int z_vrfy_specific_from_user(const struct device *dev, int bar) { - Z_OOPS(Z_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_GENERIC, &api)); + K_OOPS(K_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_GENERIC, &api)); return z_impl_specific_do_that(dev, bar) } @@ -343,13 +343,6 @@ allow the user to specify at what time during the boot sequence the init function will be executed. Any driver will specify one of four initialization levels: -``EARLY`` - Used very early in the boot process, right after entering the C domain - (``z_cstart()``). This can be used in architectures and SoCs that extend - or implement architecture code and use drivers or system services that - have to be initialized before the Kernel calls any architecture specific - initialization code. - ``PRE_KERNEL_1`` Used for devices that have no dependencies, such as those that rely solely on hardware present in the processor/SOC. These devices cannot @@ -368,12 +361,6 @@ initialization levels: Used for devices that require kernel services during configuration. Init functions at this level run in context of the kernel main task. -``APPLICATION`` - Used for application components (i.e. non-kernel components) that need - automatic configuration. These devices can use all services provided by - the kernel during configuration. Init functions at this level run on - the kernel main task. - Within each initialization level you may specify a priority level, relative to other devices in the same initialization level. The priority level is specified as an integer value in the range 0 to 99; lower values indicate earlier @@ -394,6 +381,18 @@ In some cases you may just need to run a function at boot. For such cases, the data structures and there isn't a way to later get a device pointer by name. The same device policies for initialization level and priority apply. +Inspecting the initialization sequence +************************************** + +Device drivers declared with :c:macro:`DEVICE_DEFINE` (or any variations of it) +and :c:macro:`SYS_INIT` are processed at boot time and the corresponding +initialization functions are called sequentially according to their specified +level and priority. + +Sometimes it's useful to inspect the final sequence of initialization function +call as produced by the linker. To do that, use the ``initlevels`` CMake +target, for example ``west build -t initlevels``. + Error handling ************** diff --git a/doc/kernel/memory_management/heap.rst b/doc/kernel/memory_management/heap.rst index 70d719c7396d375..a52c5ff77c6925a 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 7fbb03f6574e76d..0bbf2f7a428c276 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/slabs.rst b/doc/kernel/memory_management/slabs.rst index ae57a789b19b84a..7f6945ee38694ff 100644 --- a/doc/kernel/memory_management/slabs.rst +++ b/doc/kernel/memory_management/slabs.rst @@ -109,7 +109,7 @@ A warning is printed if a suitable block is not obtained. char *block_ptr; - if (k_mem_slab_alloc(&my_slab, &block_ptr, 100) == 0) { + if (k_mem_slab_alloc(&my_slab, (void **)&block_ptr, K_MSEC(100)) == 0) { memset(block_ptr, 0, 400); ... } else { @@ -128,9 +128,9 @@ then releases it once it is no longer needed. char *block_ptr; - k_mem_slab_alloc(&my_slab, &block_ptr, K_FOREVER); + k_mem_slab_alloc(&my_slab, (void **)&block_ptr, K_FOREVER); ... /* use memory block pointed at by block_ptr */ - k_mem_slab_free(&my_slab, block_ptr); + k_mem_slab_free(&my_slab, (void *)block_ptr); Suggested Uses ************** diff --git a/doc/kernel/memory_management/sys_mem_blocks.rst b/doc/kernel/memory_management/sys_mem_blocks.rst index abc1edd1a8039fd..da84f7c151caa24 100644 --- a/doc/kernel/memory_management/sys_mem_blocks.rst +++ b/doc/kernel/memory_management/sys_mem_blocks.rst @@ -112,7 +112,7 @@ to a 4-byte boundary: SYS_MEM_BLOCKS_DEFINE(allocator, 64, 4, 4); -Similarly, you can define a memory slab in private scope: +Similarly, you can define a memory blocks allocator in private scope: .. code-block:: c diff --git a/doc/kernel/memory_management/virtual_memory.rst b/doc/kernel/memory_management/virtual_memory.rst new file mode 100644 index 000000000000000..dbc95fb7b5279e6 --- /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/data_passing/pipes.rst b/doc/kernel/services/data_passing/pipes.rst index 62c4f8f0223b7f7..bdeec48f0117ba5 100644 --- a/doc/kernel/services/data_passing/pipes.rst +++ b/doc/kernel/services/data_passing/pipes.rst @@ -150,12 +150,12 @@ process data items generated by one or more producing threads. while (1) { rc = k_pipe_get(&my_pipe, buffer, sizeof(buffer), &bytes_read, - sizeof(header), K_MSEC(100)); + sizeof(*header), K_MSEC(100)); - if ((rc < 0) || (bytes_read < sizeof (header))) { + if ((rc < 0) || (bytes_read < sizeof (*header))) { /* Incomplete message header received */ ... - } else if (header->num_data_bytes + sizeof(header) > bytes_read) { + } else if (header->num_data_bytes + sizeof(*header) > bytes_read) { /* Only some data was received */ ... } else { diff --git a/doc/kernel/services/interrupts.rst b/doc/kernel/services/interrupts.rst index b940540e600fcec..b1f7421ed01d209 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. @@ -233,7 +233,7 @@ become shared, meaning the two ISR/argument pairs (previous one and the one that has just been registered) will be invoked each time the interrupt is triggered. The entities that make use of an interrupt line in the shared interrupt context are known as clients. The maximum number of allowed clients for an interrupt is -controlled by :kconfig:option:`SHARED_IRQ_MAX_NUM_CLIENTS`. +controlled by :kconfig:option:`CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS`. Interrupt sharing is transparent to the user. As such, the user may register interrupts using :c:macro:`IRQ_CONNECT` and :c:func:`irq_connect_dynamic` as @@ -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. @@ -554,7 +554,7 @@ This is an array of struct z_shared_isr_table_entry: }; 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. @@ -608,7 +608,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 +616,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 6d739209ae63f72..3e589a4cad39b7b 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/smp/smp.rst b/doc/kernel/services/smp/smp.rst index 0f1e29c9f1201a4..0a94ed022b0dabe 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/synchronization/events.rst b/doc/kernel/services/synchronization/events.rst index 7182803883a75f0..cbb86894723c3dc 100644 --- a/doc/kernel/services/synchronization/events.rst +++ b/doc/kernel/services/synchronization/events.rst @@ -33,10 +33,10 @@ conditions of multiple threads waiting on the event object. All threads whose match conditions have been met are made active at the same time. Threads may wait on one or more events. They may either wait for all of the -the requested events, or for any of them. Furthermore, threads making a wait -request have the option of resetting the current set of events tracked by the -event object prior to waiting. Care must be taken with this option when -multiple threads wait on the same event object. +requested events, or for any of them. Furthermore, threads making a wait request +have the option of resetting the current set of events tracked by the event +object prior to waiting. Care must be taken with this option when multiple +threads wait on the same event object. .. note:: The kernel does allow an ISR to query an event object, however the ISR must diff --git a/doc/kernel/services/synchronization/mutexes.rst b/doc/kernel/services/synchronization/mutexes.rst index b813fec2d685ca3..8fa7d1504229429 100644 --- a/doc/kernel/services/synchronization/mutexes.rst +++ b/doc/kernel/services/synchronization/mutexes.rst @@ -20,7 +20,7 @@ is referenced by its memory address. A mutex has the following key properties: -* A **lock count** that indicates the number of times the mutex has be locked +* A **lock count** that indicates the number of times the mutex has been locked by the thread that has locked it. A count of zero indicates that the mutex is unlocked. diff --git a/doc/kernel/services/timing/timers.rst b/doc/kernel/services/timing/timers.rst index c5f6beca358b2fa..9b1e424921de4a8 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/timeutil.rst b/doc/kernel/timeutil.rst index d41c5b48b896530..203d52ea9afdd1c 100644 --- a/doc/kernel/timeutil.rst +++ b/doc/kernel/timeutil.rst @@ -223,7 +223,7 @@ include: - GPS time: epoch of 1980-01-06T00:00:00Z, continuous following TAI with an offset of TAI-GPS=19 s. -- Bluetooth mesh time: epoch of 2000-01-01T00:00:00Z, continuous following TAI +- Bluetooth Mesh time: epoch of 2000-01-01T00:00:00Z, continuous following TAI with an offset of -32. - UNIX Leap Time: epoch of 1970-01-01T00:00:00Z, continuous following TAI with an offset of -8. diff --git a/doc/kernel/timing_functions/index.rst b/doc/kernel/timing_functions/index.rst index 5f21204c4e60686..711ce319fcc27ea 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/kernel/usermode/kernelobjects.rst b/doc/kernel/usermode/kernelobjects.rst index 1ac62ab8a969b84..a5a20b6500e7e71 100644 --- a/doc/kernel/usermode/kernelobjects.rst +++ b/doc/kernel/usermode/kernelobjects.rst @@ -210,7 +210,7 @@ Some objects will be implicitly initialized at boot: is run by the kernel early in the boot process. If a kernel object is initialized with a private static initializer, the object -must have :c:func:`z_object_init` called on it at some point by a supervisor +must have :c:func:`k_object_init` called on it at some point by a supervisor thread, otherwise the kernel will consider the object uninitialized if accessed by a user thread. This is very uncommon, typically only for kernel objects that are embedded within some larger struct and initialized statically. @@ -228,7 +228,7 @@ are embedded within some larger struct and initialized statically. }; ... - z_object_init(&my_foo.sem); + k_object_init(&my_foo.sem); ... diff --git a/doc/kernel/usermode/syscalls.rst b/doc/kernel/usermode/syscalls.rst index af16fbd2e4f5aec..f751697d9a30700 100644 --- a/doc/kernel/usermode/syscalls.rst +++ b/doc/kernel/usermode/syscalls.rst @@ -271,7 +271,7 @@ passed in. This includes: * Any other arguments that have a limited range of valid values. Verification functions involve a great deal of boilerplate code which has been -made simpler by some macros in :zephyr_file:`include/zephyr/syscall_handler.h`. +made simpler by some macros in :zephyr_file:`include/zephyr/internal/syscall_handler.h`. Verification functions should be declared using these macros. Argument Validation @@ -279,50 +279,50 @@ Argument Validation Several macros exist to validate arguments: -* :c:macro:`Z_SYSCALL_OBJ()` Checks a memory address to assert that it is +* :c:macro:`K_SYSCALL_OBJ()` Checks a memory address to assert that it is a valid kernel object of the expected type, that the calling thread has permissions on it, and that the object is initialized. -* :c:macro:`Z_SYSCALL_OBJ_INIT()` is the same as - :c:macro:`Z_SYSCALL_OBJ()`, except that the provided object may be +* :c:macro:`K_SYSCALL_OBJ_INIT()` is the same as + :c:macro:`K_SYSCALL_OBJ()`, except that the provided object may be uninitialized. This is useful for verifiers of object init functions. -* :c:macro:`Z_SYSCALL_OBJ_NEVER_INIT()` is the same as - :c:macro:`Z_SYSCALL_OBJ()`, except that the provided object must be +* :c:macro:`K_SYSCALL_OBJ_NEVER_INIT()` is the same as + :c:macro:`K_SYSCALL_OBJ()`, except that the provided object must be uninitialized. This is not used very often, currently only for :c:func:`k_thread_create()`. -* :c:macro:`Z_SYSCALL_MEMORY_READ()` validates a memory buffer of a particular +* :c:macro:`K_SYSCALL_MEMORY_READ()` validates a memory buffer of a particular size. The calling thread must have read permissions on the entire buffer. -* :c:macro:`Z_SYSCALL_MEMORY_WRITE()` is the same as - :c:macro:`Z_SYSCALL_MEMORY_READ()` but the calling thread must additionally +* :c:macro:`K_SYSCALL_MEMORY_WRITE()` is the same as + :c:macro:`K_SYSCALL_MEMORY_READ()` but the calling thread must additionally have write permissions. -* :c:macro:`Z_SYSCALL_MEMORY_ARRAY_READ()` validates an array whose total size +* :c:macro:`K_SYSCALL_MEMORY_ARRAY_READ()` validates an array whose total size is expressed as separate arguments for the number of elements and the element size. This macro correctly accounts for multiplication overflow when computing the total size. The calling thread must have read permissions on the total size. -* :c:macro:`Z_SYSCALL_MEMORY_ARRAY_WRITE()` is the same as - :c:macro:`Z_SYSCALL_MEMORY_ARRAY_READ()` but the calling thread must +* :c:macro:`K_SYSCALL_MEMORY_ARRAY_WRITE()` is the same as + :c:macro:`K_SYSCALL_MEMORY_ARRAY_READ()` but the calling thread must additionally have write permissions. -* :c:macro:`Z_SYSCALL_VERIFY_MSG()` does a runtime check of some boolean +* :c:macro:`K_SYSCALL_VERIFY_MSG()` does a runtime check of some boolean expression which must evaluate to true otherwise the check will fail. - A variant :c:macro:`Z_SYSCALL_VERIFY` exists which does not take + A variant :c:macro:`K_SYSCALL_VERIFY` exists which does not take a message parameter, instead printing the expression tested if it fails. The latter should only be used for the most obvious of tests. -* :c:macro:`Z_SYSCALL_DRIVER_OP()` checks at runtime if a driver +* :c:macro:`K_SYSCALL_DRIVER_OP()` checks at runtime if a driver instance is capable of performing a particular operation. While this macro can be used by itself, it's mostly a building block for macros that are automatically generated for every driver subsystem. For instance, to validate the GPIO driver, one could use the - :c:macro:`Z_SYSCALL_DRIVER_GPIO()` macro. + :c:macro:`K_SYSCALL_DRIVER_GPIO()` macro. -* :c:macro:`Z_SYSCALL_SPECIFIC_DRIVER()` is a runtime check to verify that +* :c:macro:`K_SYSCALL_SPECIFIC_DRIVER()` is a runtime check to verify that a provided pointer is a valid instance of a specific device driver, that the calling thread has permissions on it, and that the driver has been initialized. It does this by checking the API structure pointer that @@ -331,7 +331,7 @@ Several macros exist to validate arguments: API structure. If any check fails, the macros will return a nonzero value. The macro -:c:macro:`Z_OOPS()` can be used to induce a kernel oops which will kill the +:c:macro:`K_OOPS()` can be used to induce a kernel oops which will kill the calling thread. This is done instead of returning some error condition to keep the APIs the same when calling from supervisor mode. @@ -357,7 +357,7 @@ For example: static int z_vrfy_k_sem_take(struct k_sem *sem, int32_t timeout) { - Z_OOPS(Z_SYSCALL_OBJ(sem, K_OBJ_SEM)); + K_OOPS(K_SYSCALL_OBJ(sem, K_OBJ_SEM)); return z_impl_k_sem_take(sem, timeout); } #include @@ -377,7 +377,7 @@ The proper procedure to mitigate these attacks is to make a copies in the verification function, and only perform parameter checks on the copies, which user threads will never have access to. The implementation functions get passed the copy and not the original data sent by the user. The -:c:func:`z_user_to_copy()` and :c:func:`z_user_from_copy()` APIs exist for +:c:func:`k_usermode_to_copy()` and :c:func:`k_usermode_from_copy()` APIs exist for this purpose. There is one exception in place, with respect to large data buffers which are @@ -397,12 +397,12 @@ for some integral value: int ret; ret = z_impl_some_syscall(&local_out_param); - Z_OOPS(z_user_to_copy(out_param, &local_out_param, sizeof(*out_param))); + K_OOPS(k_usermode_to_copy(out_param, &local_out_param, sizeof(*out_param))); return ret; } Here we have allocated ``local_out_param`` on the stack, passed its address to -the implementation function, and then used :c:func:`z_user_to_copy()` to fill +the implementation function, and then used :c:func:`k_usermode_to_copy()` to fill in the memory passed in by the caller. It might be tempting to do something more concise: @@ -411,7 +411,7 @@ It might be tempting to do something more concise: int z_vrfy_some_syscall(int *out_param) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(out_param, sizeof(*out_param))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(out_param, sizeof(*out_param))); return z_impl_some_syscall(out_param); } @@ -433,9 +433,9 @@ bytes processed. This too should use a stack copy: size_t size; int ret; - Z_OOPS(z_user_from_copy(&size, size_ptr, sizeof(size)); + K_OOPS(k_usermode_from_copy(&size, size_ptr, sizeof(size)); ret = z_impl_in_out_syscall(&size); - Z_OOPS(z_user_to_copy(size_ptr, &size, sizeof(size))); + K_OOPS(k_usermode_to_copy(size_ptr, &size, sizeof(size))); return ret; } @@ -461,11 +461,11 @@ be copied. Typically this is done by allocating copies on the stack: struct bar bar_right_copy; struct bar bar_left_copy; - Z_OOPS(z_user_from_copy(&foo_copy, foo, sizeof(*foo))); - Z_OOPS(z_user_from_copy(&bar_right_copy, foo_copy.bar_right, + K_OOPS(k_usermode_from_copy(&foo_copy, foo, sizeof(*foo))); + K_OOPS(k_usermode_from_copy(&bar_right_copy, foo_copy.bar_right, sizeof(struct bar))); foo_copy.bar_right = &bar_right_copy; - Z_OOPS(z_user_from_copy(&bar_left_copy, foo_copy.bar_left, + K_OOPS(k_usermode_from_copy(&bar_left_copy, foo_copy.bar_left, sizeof(struct bar))); foo_copy.bar_left = &bar_left_copy; @@ -478,7 +478,7 @@ memory from the caller's resource pool via :c:func:`z_thread_malloc()`. This should always be considered last resort. Functional safety programming guidelines heavily discourage usage of heap and the fact that a resource pool is used must be clearly documented. Any issues with allocation must be -reported, to a caller, with returning the ``-ENOMEM`` . The ``Z_OOPS()`` +reported, to a caller, with returning the ``-ENOMEM`` . The ``K_OOPS()`` should never be used to verify if resource allocation has been successful. .. code-block:: c @@ -500,7 +500,7 @@ should never be used to verify if resource allocation has been successful. size_t bar_list_bytes; /* Safely copy foo into foo_copy */ - Z_OOPS(z_user_from_copy(&foo_copy, foo, sizeof(*foo))); + K_OOPS(k_usermode_from_copy(&foo_copy, foo, sizeof(*foo))); /* Bounds check the count member, in the copy we made */ if (foo_copy.count > 32) { @@ -514,7 +514,7 @@ should never be used to verify if resource allocation has been successful. if (bar_list_copy == NULL) { return -ENOMEM; } - Z_OOPS(z_user_from_copy(bar_list_copy, foo_copy.bar_list, + K_OOPS(k_usermode_from_copy(bar_list_copy, foo_copy.bar_list, bar_list_bytes)); foo_copy.bar_list = bar_list_copy; @@ -528,7 +528,7 @@ should never be used to verify if resource allocation has been successful. Finally, we must consider large data buffers. These represent areas of user memory which either have data copied out of, or copied into. It is permitted to pass these pointers to the implementation function directly. The caller's -access to the buffer still must be validated with ``Z_SYSCALL_MEMORY`` APIs. +access to the buffer still must be validated with ``K_SYSCALL_MEMORY`` APIs. The following constraints need to be met: * If the buffer is used by the implementation function to write data, such @@ -549,7 +549,7 @@ The following constraints need to be met: int z_vrfy_get_data_from_kernel(void *buf, size_t size) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(buf, size)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(buf, size)); return z_impl_get_data_from_kernel(buf, size); } @@ -558,25 +558,25 @@ Verification Return Value Policies When verifying system calls, it's important to note which kinds of verification failures should propagate a return value to the caller, and which should -simply invoke :c:macro:`Z_OOPS()` which kills the calling thread. The current +simply invoke :c:macro:`K_OOPS()` which kills the calling thread. The current conventions are as follows: #. For system calls that are defined but not compiled, invocations of these missing system calls are routed to :c:func:`handler_no_syscall()` which - invokes :c:macro:`Z_OOPS()`. + invokes :c:macro:`K_OOPS()`. -#. Any invalid access to memory found by the set of ``Z_SYSCALL_MEMORY`` APIs, - :c:func:`z_user_from_copy()`, :c:func:`z_user_to_copy()` - should trigger a :c:macro:`Z_OOPS`. This happens when the caller doesn't have +#. Any invalid access to memory found by the set of ``K_SYSCALL_MEMORY`` APIs, + :c:func:`k_usermode_from_copy()`, :c:func:`k_usermode_to_copy()` + should trigger a :c:macro:`K_OOPS`. This happens when the caller doesn't have appropriate permissions on the memory buffer or some size calculation overflowed. #. Most system calls take kernel object pointers as an argument, checked either - with one of the ``Z_SYSCALL_OBJ`` functions, ``Z_SYSCALL_DRIVER_nnnnn``, or - manually using :c:func:`z_object_validate()`. These can fail for a variety + with one of the ``K_SYSCALL_OBJ`` functions, ``K_SYSCALL_DRIVER_nnnnn``, or + manually using :c:func:`k_object_validate()`. These can fail for a variety of reasons: missing driver API, bad kernel object pointer, wrong kernel object type, or improper initialization state. These issues should always - invoke :c:macro:`Z_OOPS()`. + invoke :c:macro:`K_OOPS()`. #. Any error resulting from a failed memory heap allocation, often from invoking :c:func:`z_thread_malloc()`, should propagate ``-ENOMEM`` to the @@ -594,7 +594,7 @@ conventions are as follows: be registered from user mode. APIs which simply install callbacks shall not be exposed as system calls. Some driver subsystem APIs may take optional function callback pointers. User mode verification functions for these APIs - must enforce that these are NULL and should invoke :c:macro:`Z_OOPS()` if + must enforce that these are NULL and should invoke :c:macro:`K_OOPS()` if not. #. Some parameter checks are enforced only from user mode. These should be @@ -608,14 +608,14 @@ There are some known exceptions to these policies currently in Zephyr: initialization bit pulls double-duty to indicate whether a thread is running, cleared upon exit. See #23030. -* :c:func:`k_thread_create()` invokes :c:macro:`Z_OOPS()` for parameter +* :c:func:`k_thread_create()` invokes :c:macro:`K_OOPS()` for parameter checks, due to a great deal of existing code ignoring the return value. This will also be addressed by #23030. -* :c:func:`k_thread_abort()` invokes :c:macro:`Z_OOPS()` if an essential +* :c:func:`k_thread_abort()` invokes :c:macro:`K_OOPS()` if an essential thread is aborted, as the function has no return value. -* Various system calls related to logging invoke :c:macro:`Z_OOPS()` +* Various system calls related to logging invoke :c:macro:`K_OOPS()` when bad parameters are passed in as they do not propagate errors. Configuration Options @@ -630,18 +630,18 @@ APIs **** Helper macros for creating system call verification functions are provided in -:zephyr_file:`include/zephyr/syscall_handler.h`: - -* :c:macro:`Z_SYSCALL_OBJ()` -* :c:macro:`Z_SYSCALL_OBJ_INIT()` -* :c:macro:`Z_SYSCALL_OBJ_NEVER_INIT()` -* :c:macro:`Z_OOPS()` -* :c:macro:`Z_SYSCALL_MEMORY_READ()` -* :c:macro:`Z_SYSCALL_MEMORY_WRITE()` -* :c:macro:`Z_SYSCALL_MEMORY_ARRAY_READ()` -* :c:macro:`Z_SYSCALL_MEMORY_ARRAY_WRITE()` -* :c:macro:`Z_SYSCALL_VERIFY_MSG()` -* :c:macro:`Z_SYSCALL_VERIFY` +:zephyr_file:`include/zephyr/internal/syscall_handler.h`: + +* :c:macro:`K_SYSCALL_OBJ()` +* :c:macro:`K_SYSCALL_OBJ_INIT()` +* :c:macro:`K_SYSCALL_OBJ_NEVER_INIT()` +* :c:macro:`K_OOPS()` +* :c:macro:`K_SYSCALL_MEMORY_READ()` +* :c:macro:`K_SYSCALL_MEMORY_WRITE()` +* :c:macro:`K_SYSCALL_MEMORY_ARRAY_READ()` +* :c:macro:`K_SYSCALL_MEMORY_ARRAY_WRITE()` +* :c:macro:`K_SYSCALL_VERIFY_MSG()` +* :c:macro:`K_SYSCALL_VERIFY` Functions for invoking system calls are defined in :zephyr_file:`include/zephyr/syscall.h`: diff --git a/doc/project/dev_env_and_tools.rst b/doc/project/dev_env_and_tools.rst index 37356ec3232cbe8..1678a455f174b10 100644 --- a/doc/project/dev_env_and_tools.rst +++ b/doc/project/dev_env_and_tools.rst @@ -20,10 +20,11 @@ and linked to any relevant :ref:`bug or feature tracking issues` The Zephyr project uses GitHub for code reviews and Git tree management. When submitting a change or an enhancement to any Zephyr component, a developer -should use GitHub. GitHub automatically assigns a responsible reviewer on a -component basis, as defined in the :zephyr_file:`CODEOWNERS` file stored with the code -tree in the Zephyr project repository. A limited set of release managers are -allowed to merge a pull request into the main branch once reviews are complete. +should use GitHub. GitHub Actions automatically assigns a responsible reviewer +on a component basis, as defined in the :zephyr_file:`MAINTAINERS.yml` file +stored with the code tree in the Zephyr project repository. A limited set of +release managers are allowed to merge a pull request into the main branch once +reviews are complete. .. _review_time: @@ -110,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. @@ -322,7 +323,7 @@ Fix for an issue blocking development. * *Maintainer* -Maintainer review reqiured. +Maintainer review required. * *Security Review* @@ -382,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 c2b970c77f789fb..a57a7b46def4b69 100644 --- a/doc/project/project_roles.rst +++ b/doc/project/project_roles.rst @@ -67,9 +67,9 @@ template ` and the guidelines +of the project or in cases of disagreement, it is the responsibility of the +assignee to advance the review process and resolve any disagreements. + +Collaborator approval of pull requests are counted toward the minimum required +approvals needed to merge a PR. Other criteria for merging may apply. Maintainer ++++++++++ @@ -116,12 +123,15 @@ 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 :ref:`maintainers_file` in the Zephyr repository. -Maintainer votes on pull requests can block or approve the pull request. +Maintainer approval of pull requests are counted toward the minimum +required approvals needed to merge a PR. Other criteria for merging may apply. Role Retirement ############### @@ -149,15 +159,37 @@ Assignees are set either automatically based on the code being changed or set by the other Maintainers, the Release Engineering team can set an assignee when the latter is not possible. -* Right to dismiss stale reviews and seek reviews from additional maintainers, - developers and contributors -* Right to block pull requests from being merged +* Right to dismiss stale and unrelated reviews or reviews not following + :ref:`expectations ` from reviewers and seek reviews + from additional maintainers, developers and contributors +* Right to block pull requests from being merged until issues or changes + requested are addressed * Responsibility to re-assign a pull request if they are the original submitter of the code * Responsibility to drive the pull request to a mergeable state * 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 e1e07c417c83841..7523cb951a378ab 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/eol_releases.rst b/doc/releases/eol_releases.rst new file mode 100644 index 000000000000000..22900a55e44fc29 --- /dev/null +++ b/doc/releases/eol_releases.rst @@ -0,0 +1,14 @@ +End-of-life releases +==================== + +Release notes for end-of-life releases of Zephyr RTOS are kept here for historical purposes. + +.. toctree:: + :maxdepth: 1 + :glob: + :reversed: + + release-notes-1.? + release-notes-1.* + release-notes-2.[0-6] + release-notes-3.[0-2] diff --git a/doc/releases/index.rst b/doc/releases/index.rst index 48855b65faecf02..7a3540d227ddb0c 100644 --- a/doc/releases/index.rst +++ b/doc/releases/index.rst @@ -3,11 +3,17 @@ Releases ######## -Zephyr project is provided as source code and build scripts for different -target architectures and configurations, and not as a binary image. Updated -versions of the Zephyr project are released approximately every four months. +Zephyr project is provided as source code and build scripts for different target +architectures and configurations, and not as a binary image. Updated versions of +the Zephyr project are released approximately every four months. -All Zephyr project source code is maintained in a `GitHub repository`_. +All Zephyr project source code is maintained in a `GitHub repository`_. In order +to use a released version of the Zephyr project, it is recommended that you use +:ref:`west` to :ref:`get_the_code` of the release you are interested in. + +The technical documentation for current and past releases is available at +https://docs.zephyrproject.org/ (use the version selector to select your release +of interest). Release Life Cycle and Maintenance ********************************** @@ -52,9 +58,9 @@ Supported Releases +=================+================+===============+ | `Zephyr 2.7.5`_ | 2023-06-01 | 2024-08-31 | +-----------------+----------------+---------------+ -| `Zephyr 3.4.0`_ | 2023-06-16 | 2024-02-29 | +| `Zephyr 3.5.0`_ | 2023-10-20 | 2024-07-26 | +-----------------+----------------+---------------+ -| `Zephyr 3.3.0`_ | 2023-02-19 | 2023-10-31 | +| `Zephyr 3.4.0`_ | 2023-06-16 | 2024-02-29 | +-----------------+----------------+---------------+ As of 2022-01-01, LTS1 (1.14.x) is not supported and has reached end of life (EOL). @@ -62,32 +68,14 @@ As of 2022-01-01, LTS1 (1.14.x) is not supported and has reached end of life (EO Release Notes ************* -For Zephyr versions up to 1.13, you can either download source as a tar.gz file -(see the bottom of the `GitHub tagged releases`_ page corresponding to each -release), or clone the GitHub repository. - -With the introduction of the :ref:`west` tool after the release of Zephyr 1.13, -it is no longer recommended to download or clone the source code manually. -Instead we recommend you follow the instructions in :ref:`get_the_code` to do -so with the help of west. - -The project's technical documentation is also tagged to correspond with a -specific release and can be found at https://docs.zephyrproject.org/. - -.. comment We need to split the globbing of release notes to get the - single-digit and double-digit subversions sorted correctly. Specify - names in normal order and use the :reversed: option to reverse it. - This will get us through 10 subversions (0-9) before we need to - update this list for two-digit subversions again. - .. toctree:: :maxdepth: 1 :glob: :reversed: - release-notes-1.? - release-notes-1.* - release-notes-* + eol_releases + release-notes-2.7 + release-notes-3.[3-6] Migration Guides **************** @@ -105,5 +93,5 @@ users transition from the previous release. .. _`GitHub repository`: https://github.com/zephyrproject-rtos/zephyr .. _`GitHub tagged releases`: https://github.com/zephyrproject-rtos/zephyr/tags .. _`Zephyr 2.7.5`: https://docs.zephyrproject.org/2.7.5/ -.. _`Zephyr 3.3.0`: https://docs.zephyrproject.org/3.3.0/ .. _`Zephyr 3.4.0`: https://docs.zephyrproject.org/3.4.0/ +.. _`Zephyr 3.5.0`: https://docs.zephyrproject.org/3.5.0/ diff --git a/doc/releases/migration-guide-3.5.rst b/doc/releases/migration-guide-3.5.rst index 57b408676602adf..86d0fa51fcb4909 100644 --- a/doc/releases/migration-guide-3.5.rst +++ b/doc/releases/migration-guide-3.5.rst @@ -2,15 +2,21 @@ .. _migration_3.5: -Migration guide to Zephyr v3.5.0 (Working Draft) -################################################ +Migration guide to Zephyr v3.5.0 +################################ This document describes the changes required or recommended when migrating your application from Zephyr v3.4.0 to Zephyr v3.5.0. +Any other changes (not directly related to migrating applications) can be found in +the :ref:`release notes`. + Required changes **************** +Kernel +====== + * The kernel :c:func:`k_mem_slab_free` function has changed its signature, now taking a ``void *mem`` pointer instead of a ``void **mem`` double-pointer. The new signature will not immediately trigger a compiler error or warning, @@ -19,56 +25,14 @@ Required changes detect if you pass the function memory not belonging to the memory blocks in the slab. -* The :kconfig:option:`CONFIG_BOOTLOADER_SRAM_SIZE` default value is now ``0`` (was - ``16``). Bootloaders that use a part of the SRAM should set this value to an - appropriate size. :github:`60371` - -* The Kconfig option ``CONFIG_GPIO_NCT38XX_INTERRUPT`` has been renamed to - :kconfig:option:`CONFIG_GPIO_NCT38XX_ALERT`. - -* MCUmgr SMP version 2 error codes entry has changed due to a collision with an - existing response in shell_mgmt. Previously, these errors had the entry ``ret`` - but now have the entry ``err``. ``smp_add_cmd_ret()`` is now deprecated and - :c:func:`smp_add_cmd_err` should be used instead, ``MGMT_CB_ERROR_RET`` is - now deprecated and :c:enumerator:`MGMT_CB_ERROR_ERR` should be used instead. - SMP version 2 error code defines for in-tree modules have been updated to - replace the ``*_RET_RC_*`` parts with ``*_ERR_*``. - -* MCUmgr SMP version 2 error translation (to legacy MCUmgr error code) is now - handled in function handlers by setting the ``mg_translate_error`` function - pointer of :c:struct:`mgmt_group` when registering a group. See - :c:type:`smp_translate_error_fn` for function details. Any SMP version 2 - handlers made for Zephyr 3.4 need to be updated to include these translation - functions when the groups are registered. - -* ``zephyr,memory-region-mpu`` was renamed ``zephyr,memory-attr`` and its type - moved from 'enum' to 'int'. To have a seamless conversion this is the - required change in the DT: - - .. code-block:: none - - - "RAM" -> <( DT_MEM_ARM(ATTR_MPU_RAM) )> - - "RAM_NOCACHE" -> <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )> - - "FLASH" -> <( DT_MEM_ARM(ATTR_MPU_FLASH) )> - - "PPB" -> <( DT_MEM_ARM(ATTR_MPU_PPB) )> - - "IO" -> <( DT_MEM_ARM(ATTR_MPU_IO) )> - - "EXTMEM" -> <( DT_MEM_ARM(ATTR_MPU_EXTMEM) )> +* :c:macro:`CONTAINER_OF` now performs type checking, this was very commonly + misused to obtain user structure from :c:struct:`k_work` pointers without + passing from :c:struct:`k_work_delayable`. This would now result in a build + error and have to be done correctly using + :c:func:`k_work_delayable_from_work`. -* A new networking Kconfig option :kconfig:option:`CONFIG_NET_INTERFACE_NAME` - defaults to ``y``. The option allows user to set a name to a network interface. - During system startup a default name is assigned to the network interface like - ``eth0`` to the first Ethernet network interface. The option affects the behavior - of ``SO_BINDTODEVICE`` BSD socket option. If the Kconfig option is set to ``n``, - which is how the system worked earlier, then the name of the device assigned - to the network interface is used by the ``SO_BINDTODEVICE`` socket option. - If the Kconfig option is set to ``y`` (current default), then the network - interface name is used by the ``SO_BINDTODEVICE`` socket option. - -* On all STM32 ADC, it is no longer possible to read sensor channels (Vref, - Vbat or temperature) using the ADC driver. The dedicated sensor driver should - be used instead. This change is due to a limitation on STM32F4 where the - channels for temperature and Vbat are identical, and the impossibility of - determining what we want to measure using solely the ADC API. +C Library +========= * The default C library used on most targets has changed from the built-in minimal C library to Picolibc. While both provide standard C library @@ -106,6 +70,16 @@ Required changes compiler will now warn about declarations of `main` which don't conform to the Zephyr required type -- ``int main(void)``. + * 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 + 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 + positional arguments. Building the library as a module allows finer + control over the feature set provided at each level. + * Picolibc's default floating point input/output code is larger than the minimal C library version (this is necessary to conform with the C language "round trip" requirements for these operations). If you use @@ -115,52 +89,51 @@ Required changes to a smaller, but inexact conversion algorithm. This requires building Picolibc as a module. -* The CAN controller timing API functions :c:func:`can_set_timing` and :c:func:`can_set_timing_data` - no longer fallback to the (Re-)Synchronization Jump Width (SJW) value set in the devicetree - properties for the given CAN controller upon encountering an SJW value corresponding to - ``CAN_SJW_NO_CHANGE`` (which is no longer available). The caller will therefore need to fill in - the ``sjw`` field in :c:struct:`can_timing`. To aid in this, the :c:func:`can_calc_timing` and - :c:func:`can_calc_timing_data` functions now automatically calculate a suitable SJW. The - calculated SJW can be overwritten by the caller if needed. The CAN controller API functions - :c:func:`can_set_bitrate` and :c:func:`can_set_bitrate_data` now also automatically calculate a - suitable SJW, but their SJW cannot be overwritten by the caller. +Optional Modules +================ -* The CAN ISO-TP message configuration in :c:struct:`isotp_msg_id` is changed to use the following - flags instead of bit fields: +The following modules have been made optional and are not downloaded with `west update` by default anymore: - * :c:macro:`ISOTP_MSG_EXT_ADDR` to enable ISO-TP extended addressing - * :c:macro:`ISOTP_MSG_FIXED_ADDR` to enable ISO-TP fixed addressing - * :c:macro:`ISOTP_MSG_IDE` to use extended (29-bit) CAN IDs +* ``chre`` +* ``lz4`` +* ``nanopb`` +* ``psa-arch-tests`` +* ``sof`` +* ``tf-m-tests`` +* ``tflite-micro`` +* ``thrift`` +* ``zscilib`` - The two new flags :c:macro:`ISOTP_MSG_FDF` and :c:macro:`ISOTP_MSG_BRS` were added for CAN FD - mode. +To enable them again use the ``west config manifest.project-filter -- +`` command, or ``west config manifest.group-filter -- +optional`` to +enable all optional modules, and then run ``west update`` again. -* Ethernet PHY devicetree bindings were updated to use the standard ``reg`` - property for the PHY address instead of a custom ``address`` property. As a - result, MDIO controller nodes now require ``#address-cells`` and - ``#size-cells`` properties. Similarly, Ethernet PHY devicetree nodes and - corresponding driver were updated to consistently use the node name - ``ethernet-phy`` instead of ``phy``. Devicetrees and overlays must be updated - accordingly: +Device Drivers and Device Tree +============================== - .. code-block:: devicetree +* ``zephyr,memory-region-mpu`` was renamed ``zephyr,memory-attr`` and its type + moved from 'enum' to 'int'. To have a seamless conversion this is the + required change in the DT: - mdio { - compatible = "mdio-controller"; - #address-cells = <1>; - #size-cells = <0>; + .. code-block:: none - ethernet-phy@0 { - compatible = "ethernet-phy"; - reg = <0>; - }; - }; + - "RAM" -> <( DT_MEM_ARM(ATTR_MPU_RAM) )> + - "RAM_NOCACHE" -> <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )> + - "FLASH" -> <( DT_MEM_ARM(ATTR_MPU_FLASH) )> + - "PPB" -> <( DT_MEM_ARM(ATTR_MPU_PPB) )> + - "IO" -> <( DT_MEM_ARM(ATTR_MPU_IO) )> + - "EXTMEM" -> <( DT_MEM_ARM(ATTR_MPU_EXTMEM) )> -* The ``accept()`` callback's signature in :c:struct:`bt_l2cap_server` has - changed to ``int (*accept)(struct bt_conn *conn, struct bt_l2cap_server - *server, struct bt_l2cap_chan **chan)``, - adding a new ``server`` parameter pointing to the :c:struct:`bt_l2cap_server` - structure instance the callback relates to. :github:`60536` +* Device dependencies (incorrectly referred as "device handles" in some areas) + are now an optional feature enabled by :kconfig:option:`CONFIG_DEVICE_DEPS`. + This means that an extra linker stage is no longer necessary if this option is + not enabled. + +* On all STM32 ADC, it is no longer possible to read sensor channels (Vref, + Vbat or temperature) using the ADC driver. The dedicated sensor driver should + be used instead. This change is due to a limitation on STM32F4 where the + channels for temperature and Vbat are identical, and the impossibility of + determining what we want to measure using solely the ADC API. * The RAM disk driver has been changed to support multiple instances and instantiation using devicetree. As a result, Kconfig option :kconfig:option:`CONFIG_DISK_RAM_VOLUME_SIZE` @@ -188,12 +161,6 @@ Required changes :dtcompatible:`gpio-keys` and the callback definition has been renamed from ``INPUT_LISTENER_CB_DEFINE`` to :c:macro:`INPUT_CALLBACK_DEFINE`. -* :c:macro:`CONTAINER_OF` now performs type checking, this was very commonly - misused to obtain user structure from :c:struct:`k_work` pointers without - passing from :c:struct:`k_work_delayable`. This would now result in a build - error and have to be done correctly using - :c:func:`k_work_delayable_from_work`. - * The :dtcompatible:`ti,bq274xx` driver was using incorrect units for capacity and power channels, these have been fixed and scaled by x1000 factor from the previous implementation, any application using them has to be changed @@ -216,35 +183,11 @@ Required changes * ``CONFIG_SSD1306_REVERSE_MODE`` is now set using the ``inversion-on`` property of the devicetree node. - * GPIO drivers not implementing IRQ related operations must now provide ``NULL`` to the relevant operations: ``pin_interrupt_configure``, ``manage_callback``, ``get_pending_int``. The public API will return ``-ENOSYS`` when these are not available, instead of ``-ENOTSUP``. -* Platforms that implement power management hooks must explicitly select - :kconfig:option:`CONFIG_HAS_PM` in Kconfig. This is now a dependency of - :kconfig:option:`CONFIG_PM`. Before this change all platforms could enable - :kconfig:option:`CONFIG_PM` because empty weak stubs were provided, however, - this is no longer supported. As a result of this change, power management - hooks are no longer defined as weaks. - -* Multiple platforms no longer support powering the system off using - :c:func:`pm_state_force`. The new :c:func:`sys_poweroff` API must be used. - Migrated platforms include Nordic nRF, STM32, ESP32 and TI CC13XX/26XX. The - new API is independent from :kconfig:option:`CONFIG_PM`. It requires - :kconfig:option:`CONFIG_POWEROFF` to be enabled, which depends on - :kconfig:option:`CONFIG_HAS_POWEROFF`, an option selected by platforms - implementing the required new hooks. - -* ARM SoC initialization routines no longer need to call `NMI_INIT()`. The - macro call has been removed as it was not doing anything useful. - -* Device dependencies (incorrectly referred as "device handles" in some areas) - are now an optional feature enabled by :kconfig:option:`CONFIG_DEVICE_DEPS`. - This means that an extra linker stage is no longer necessary if this option is - not enabled. - * STM32 Ethernet driver was misusing :c:func:`hwinfo_get_device_id` to generate last 3 bytes of mac address, resulting in a high risk of collision when using SoCs from the same lot. This is now fixed to use the whole range of entropy @@ -267,9 +210,122 @@ Required changes <&rcc STM32_SRC_HSI ADC_SEL(2)>; }; +* On NXP boards with LPC DMA, the DMA controller node used to have its ``dma-channels`` property + set in the board DTS as a way to configure the amount of structures the driver will allocate. + This did not match the zephyr dma-controller binding, so this property is now fixed and set + in the SOC devicetree definition. Downstream boards should not override this property and + instead use the new driver Kconfig + :kconfig:option:`CONFIG_DMA_MCUX_LPC_NUMBER_OF_CHANNELS_ALLOCATED`. + +* The LPC55XXX series SOC (except LPC55S06) default main clock has been + updated to PLL1 source from XTAL32K running at 144MHZ. If the new + kconfig option :kconfig:option:`CONFIG_INIT_PLL1` + is disabled then the main clock is muxed to FRO_HR as before. -* The :kconfig:option:`CONFIG_RISCV_MTVEC_VECTORED_MODE` Kconfig option was renamed to - :kconfig:option:`CONFIG_RISCV_VECTORED_MODE`. +* The Kconfig option ``CONFIG_GPIO_NCT38XX_INTERRUPT`` has been renamed to + :kconfig:option:`CONFIG_GPIO_NCT38XX_ALERT`. + +* The CAN controller timing API functions :c:func:`can_set_timing` and :c:func:`can_set_timing_data` + no longer fallback to the (Re-)Synchronization Jump Width (SJW) value set in the devicetree + properties for the given CAN controller upon encountering an SJW value corresponding to + ``CAN_SJW_NO_CHANGE`` (which is no longer available). The caller will therefore need to fill in + the ``sjw`` field in :c:struct:`can_timing`. To aid in this, the :c:func:`can_calc_timing` and + :c:func:`can_calc_timing_data` functions now automatically calculate a suitable SJW. The + calculated SJW can be overwritten by the caller if needed. The CAN controller API functions + :c:func:`can_set_bitrate` and :c:func:`can_set_bitrate_data` now also automatically calculate a + suitable SJW, but their SJW cannot be overwritten by the caller. + +* The CAN ISO-TP message configuration in :c:struct:`isotp_msg_id` is changed to use the following + flags instead of bit fields: + + * :c:macro:`ISOTP_MSG_EXT_ADDR` to enable ISO-TP extended addressing + * :c:macro:`ISOTP_MSG_FIXED_ADDR` to enable ISO-TP fixed addressing + * :c:macro:`ISOTP_MSG_IDE` to use extended (29-bit) CAN IDs + + The two new flags :c:macro:`ISOTP_MSG_FDF` and :c:macro:`ISOTP_MSG_BRS` were added for CAN FD + mode. + +* NXP i.MX RT based boards should now enable + :kconfig:option:`CONFIG_DEVICE_CONFIGURATION_DATA` at the board level when + using a DCD with the RT bootrom, and enable + :kconfig:option:`CONFIG_NXP_IMX_EXTERNAL_SDRAM` when using external SDRAM + via the SEMC + +* NXP i.MX RT11xx series SNVS pin control name identifiers have been updated to + match with the source data for these SOCs. The pin names have had the + suffix ``dig`` added. For example, ``iomuxc_snvs_wakeup_gpio13_io00`` has + been renamed to ``iomuxc_snvs_wakeup_dig_gpio13_io00`` + +Power Management +================ + +* Platforms that implement power management hooks must explicitly select + :kconfig:option:`CONFIG_HAS_PM` in Kconfig. This is now a dependency of + :kconfig:option:`CONFIG_PM`. Before this change all platforms could enable + :kconfig:option:`CONFIG_PM` because empty weak stubs were provided, however, + this is no longer supported. As a result of this change, power management + hooks are no longer defined as weaks. + +* Multiple platforms no longer support powering the system off using + :c:func:`pm_state_force`. The new :c:func:`sys_poweroff` API must be used. + Migrated platforms include Nordic nRF, STM32, ESP32 and TI CC13XX/26XX. The + new API is independent from :kconfig:option:`CONFIG_PM`. It requires + :kconfig:option:`CONFIG_POWEROFF` to be enabled, which depends on + :kconfig:option:`CONFIG_HAS_POWEROFF`, an option selected by platforms + implementing the required new hooks. + +Bootloader +========== + +* The :kconfig:option:`CONFIG_BOOTLOADER_SRAM_SIZE` default value is now ``0`` (was + ``16``). Bootloaders that use a part of the SRAM should set this value to an + appropriate size. :github:`60371` + +Bluetooth +========= + +* The ``accept()`` callback's signature in :c:struct:`bt_l2cap_server` has + changed to ``int (*accept)(struct bt_conn *conn, struct bt_l2cap_server + *server, struct bt_l2cap_chan **chan)``, + adding a new ``server`` parameter pointing to the :c:struct:`bt_l2cap_server` + structure instance the callback relates to. :github:`60536` + +Networking +========== + +* A new networking Kconfig option :kconfig:option:`CONFIG_NET_INTERFACE_NAME` + defaults to ``y``. The option allows user to set a name to a network interface. + During system startup a default name is assigned to the network interface like + ``eth0`` to the first Ethernet network interface. The option affects the behavior + of ``SO_BINDTODEVICE`` BSD socket option. If the Kconfig option is set to ``n``, + which is how the system worked earlier, then the name of the device assigned + to the network interface is used by the ``SO_BINDTODEVICE`` socket option. + If the Kconfig option is set to ``y`` (current default), then the network + interface name is used by the ``SO_BINDTODEVICE`` socket option. + +* Ethernet PHY devicetree bindings were updated to use the standard ``reg`` + property for the PHY address instead of a custom ``address`` property. As a + result, MDIO controller nodes now require ``#address-cells`` and + ``#size-cells`` properties. Similarly, Ethernet PHY devicetree nodes and + corresponding driver were updated to consistently use the node name + ``ethernet-phy`` instead of ``phy``. Devicetrees and overlays must be updated + accordingly: + + .. code-block:: devicetree + + mdio { + compatible = "mdio-controller"; + #address-cells = <1>; + #size-cells = <0>; + + ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0>; + }; + }; + +Other Subsystems +================ * ZBus runtime observers implementation now relies on the HEAP memory instead of a memory slab. Thus, zbus' configuration (kconfig) related to runtime observers has changed. To keep your runtime @@ -282,12 +338,32 @@ Required changes * The zbus VDED delivery sequence has changed. Check the :ref:`documentation` to verify if it will affect your code. -* On NXP boards with LPC DMA, the DMA controller node used to have its ``dma-channels`` property - set in the board DTS as a way to configure the amount of structures the driver will allocate. - This did not match the zephyr dma-controller binding, so this property is now fixed and set - in the SOC devicetree definition. Downstream boards should not override this property and - instead use the new driver Kconfig - :kconfig:option:`CONFIG_DMA_MCUX_LPC_NUMBER_OF_CHANNELS_ALLOCATED`. +* MCUmgr SMP version 2 error codes entry has changed due to a collision with an + existing response in shell_mgmt. Previously, these errors had the entry ``ret`` + but now have the entry ``err``. ``smp_add_cmd_ret()`` is now deprecated and + :c:func:`smp_add_cmd_err` should be used instead, ``MGMT_CB_ERROR_RET`` is + now deprecated and :c:enumerator:`MGMT_CB_ERROR_ERR` should be used instead. + SMP version 2 error code defines for in-tree modules have been updated to + replace the ``*_RET_RC_*`` parts with ``*_ERR_*``. + +* MCUmgr SMP version 2 error translation (to legacy MCUmgr error code) is now + handled in function handlers by setting the ``mg_translate_error`` function + pointer of :c:struct:`mgmt_group` when registering a group. See + :c:type:`smp_translate_error_fn` for function details. Any SMP version 2 + handlers made for Zephyr 3.4 need to be updated to include these translation + functions when the groups are registered. + +ARM +=== + +* ARM SoC initialization routines no longer need to call `NMI_INIT()`. The + macro call has been removed as it was not doing anything useful. + +RISC V +====== + +* The :kconfig:option:`CONFIG_RISCV_MTVEC_VECTORED_MODE` Kconfig option was renamed to + :kconfig:option:`CONFIG_RISCV_VECTORED_MODE`. Recommended Changes ******************* @@ -324,7 +400,7 @@ Recommended Changes Instead the new :kconfig:option:`CONFIG_MODEM_CELLULAR` driver should be used. As part of this :kconfig:option:`CONFIG_GSM_MUX` and :kconfig:option:`CONFIG_UART_MUX` are being marked as deprecated as well. The new modem subsystem :kconfig:option:`CONFIG_MODEM_CMUX` - and :kconfig:option:`CONFIG_MODEM_PPP`` should be used instead. + and :kconfig:option:`CONFIG_MODEM_PPP` should be used instead. * Device drivers should now be restricted to ``PRE_KERNEL_1``, ``PRE_KERNEL_2`` and ``POST_KERNEL`` initialization levels. Other device initialization levels, @@ -350,3 +426,7 @@ Recommended Changes ```` are now deprecated in favor of including ```` instead. The new header is part of the CMSIS glue code in the ``modules`` directory. + +* Random API header ```` is deprecated in favor of + ````. The old header will be removed in future releases + and its usage should be avoided. diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst new file mode 100644 index 000000000000000..e44293b570d3799 --- /dev/null +++ b/doc/releases/migration-guide-3.6.rst @@ -0,0 +1,517 @@ +:orphan: + +.. _migration_3.6: + +Migration guide to Zephyr v3.6.0 (Working Draft) +################################################ + +This document describes the changes required or recommended when migrating your +application from Zephyr v3.5.0 to Zephyr v3.6.0. + +Any other changes (not directly related to migrating applications) can be found in +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. + +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 +========= + +Optional Modules +================ + +The following modules have been made optional and are not downloaded with `west update` by default +anymore: + +* ``canopennode`` (:github:`64139`) + +To enable them again use the ``west config manifest.project-filter -- +`` command, or ``west config manifest.group-filter -- +optional`` to +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``. + These attributes must be configured in the Device Tree similarly to the following + example: + + .. code-block:: devicetree + + / { + lsm6dsv16x@0 { + compatible = "st,lsm6dsv16x"; + + int1-gpios = <&gpioa 4 GPIO_ACTIVE_HIGH>; + int2-gpios = <&gpiod 11 GPIO_ACTIVE_HIGH>; + drdy-pin = <2>; + }; + }; +* 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 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. + +* 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` + +Power Management +================ + +Shell +===== + +* The following subsystem and driver shell modules are now disabled by default. Each required shell + module must now be explicitly enabled via Kconfig (:github:`65307`): + + * :kconfig:option:`CONFIG_ACPI_SHELL` + * :kconfig:option:`CONFIG_ADC_SHELL` + * :kconfig:option:`CONFIG_AUDIO_CODEC_SHELL` + * :kconfig:option:`CONFIG_CAN_SHELL` + * :kconfig:option:`CONFIG_CLOCK_CONTROL_NRF_SHELL` + * :kconfig:option:`CONFIG_DAC_SHELL` + * :kconfig:option:`CONFIG_DEBUG_COREDUMP_SHELL` + * :kconfig:option:`CONFIG_EDAC_SHELL` + * :kconfig:option:`CONFIG_EEPROM_SHELL` + * :kconfig:option:`CONFIG_FLASH_SHELL` + * :kconfig:option:`CONFIG_HWINFO_SHELL` + * :kconfig:option:`CONFIG_I2C_SHELL` + * :kconfig:option:`CONFIG_LOG_CMDS` + * :kconfig:option:`CONFIG_LORA_SHELL` + * :kconfig:option:`CONFIG_MCUBOOT_SHELL` + * :kconfig:option:`CONFIG_MDIO_SHELL` + * :kconfig:option:`CONFIG_OPENTHREAD_SHELL` + * :kconfig:option:`CONFIG_PCIE_SHELL` + * :kconfig:option:`CONFIG_PSCI_SHELL` + * :kconfig:option:`CONFIG_PWM_SHELL` + * :kconfig:option:`CONFIG_REGULATOR_SHELL` + * :kconfig:option:`CONFIG_SENSOR_SHELL` + * :kconfig:option:`CONFIG_SMBUS_SHELL` + * :kconfig:option:`CONFIG_STATS_SHELL` + * :kconfig:option:`CONFIG_USBD_SHELL` + * :kconfig:option:`CONFIG_USBH_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 +========== + +* MCUboot's deprecated ``CONFIG_ZEPHYR_TRY_MASS_ERASE`` Kconfig option has been removed. If an + erase is needed when flashing MCUboot, this should now be provided directly to the ``west`` + command e.g. ``west flash --erase``. (:github:`64703`) + +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`` + Devicetree chosen is now ``zephyr,bt-hci-ipc``. The existing sample has also + been renamed, from ``samples/bluetooth/hci_rpmsg`` to + ``samples/bluetooth/hci_ipc``. (:github:`64391`) +* The BT GATT callback list, appended to by :c:func:`bt_gatt_cb_register`, is no longer + cleared on :c:func:`bt_enable`. Callbacks can now be registered before the initial + call to :c:func:`bt_enable`, and should no longer be re-registered after a :c:func:`bt_disable` + :c:func:`bt_enable` cycle. (:github:`63693`) +* The Bluetooth UUID has been modified to rodata in ``BT_UUID_DECLARE_16``, ``BT_UUID_DECLARE_32` + and ``BT_UUID_DECLARE_128`` as the return value has been changed to `const`. + 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 + + * The Bluetooth Mesh ``model`` declaration has been changed to add prefix ``const``. + The ``model->user_data``, ``model->elem_idx`` and ``model->mod_idx`` field has been changed to + the new runtime structure, replaced by ``model->rt->user_data``, ``model->rt->elem_idx`` and + ``model->rt->mod_idx`` separately. (:github:`65152`) + * The Bluetooth Mesh ``element`` declaration has been changed to add prefix ``const``. + The ``elem->addr`` field has been changed to the new runtime structure, replaced by + ``elem->rt->addr``. (:github:`65388`) + * 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 +======= + +* The API to register a callback to provide battery level information to the LoRaWAN stack has been + renamed from ``lorawan_set_battery_level_callback`` to + :c:func:`lorawan_register_battery_level_callback` and the return type is now ``void``. This + is more consistent with similar functions for downlink and data rate changed callbacks. + (:github:`65103`) + +Networking +========== + +* The CoAP public API has some minor changes to take into account. The + :c:func:`coap_remove_observer` now returns a result if the observer was removed. This + change is used by the newly introduced :ref:`coap_server_interface` subsystem. Also, the + ``request`` argument for :c:func:`coap_well_known_core_get` is made ``const``. + (:github:`64265`) + +* CoAP observer events have moved from a callback function in a CoAP resource to the Network Events + subsystem. The ``CONFIG_COAP_OBSERVER_EVENTS`` configuration option has been removed. + (:github:`65936`) + +* The CoAP public API function :c:func:`coap_pending_init` has changed. The parameter + ``retries`` is replaced with a pointer to :c:struct:`coap_transmission_parameters`. This allows to + specify retransmission parameters of the confirmable message. It is safe to pass a NULL pointer to + use default values. + (:github:`66482`) + +* The CoAP public API functions :c:func:`coap_service_send` and :c:func:`coap_resource_send` have + changed. An additional parameter pointer to :c:struct:`coap_transmission_parameters` has been + added. It is safe to pass a NULL pointer to use default values. (:github:`66540`) + +* The IGMP multicast library now supports IGMPv3. This results in a minor change to the existing + api. The :c:func:`net_ipv4_igmp_join` now takes an additional argument of the type + ``const struct igmp_param *param``. This allows IGMPv3 to exclude/include certain groups of + addresses. If this functionality is not used or available (when using IGMPv2), you can safely pass + a NULL pointer. IGMPv3 can be enabled using the Kconfig ``CONFIG_NET_IPV4_IGMPV3``. + (:github:`65293`) + +* The network stack now uses a separate IPv4 TTL (time-to-live) value for multicast packets. + Before, the same TTL value was used for unicast and multicast packets. + 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 +================ + +* MCUmgr applications that make use of serial transports (shell or UART) must now select + :kconfig:option:`CONFIG_CRC`, this was previously erroneously selected if MCUmgr was enabled, + when for non-serial transports it was not needed. (:github:`64078`) + +* Touchscreen drivers :dtcompatible:`focaltech,ft5336` and + :dtcompatible:`goodix,gt911` were using the incorrect polarity for the + 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 097d06749990d91..3a9922f4f00029b 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 b2b22f8fae09d3c..ca5f82561f69455 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 af2f414d7bbf9f8..5f4e7feaa11f92e 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 c4ad995f2811631..53864fa2508b386 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 c7e80d3d83f6d40..91f6393197a0037 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 422806137499800..a03beb7d0d51e25 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 517ef1c6e3cc131..fe631d3c7667d74 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 e9e4bd647db2194..11e923b0f8e6151 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. @@ -335,7 +335,7 @@ Bluetooth payload updates with the Resolvable Private Address (RPA) rotations when the :kconfig:option:`CONFIG_BT_PRIVACY` is enabled. * Added a new :c:func:`bt_le_set_rpa_timeout()` API call to dynamically change - the the Resolvable Private Address (RPA) timeout when the + the Resolvable Private Address (RPA) timeout when the :kconfig:option:`CONFIG_BT_RPA_TIMEOUT_DYNAMIC` is enabled. * Added :c:func:`bt_conn_auth_cb_overlay` to overlay authentication callbacks for a Bluetooth LE connection. @@ -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 93be4649b1e05ab..b1590a5ee1d8bfc 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 @@ -811,7 +811,7 @@ Drivers and Sensors * Added new API :c:func:`pcie_scan` to scan for devices. - * This iterates through the the buses and devices which are expected to + * This iterates through the buses and devices which are expected to exist. The old method was to try all possible combination of buses and devices to determine if there is a device there. :c:func:`pci_init` and :c:func:`pcie_bdf_lookup` have been updated to diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 092fa251c6f7494..3b96c3e8bb8c08d 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 7616242a3dcfc6a..0ae90dd5c3eb18c 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -2,14 +2,29 @@ .. _zephyr_3.5: -Zephyr 3.5.0 (Working Draft) -############################ +Zephyr 3.5.0 +############ We are pleased to announce the release of Zephyr version 3.5.0. Major enhancements with this release include: -* Added native_sim (successor to native_posix) +* Added support for linkable loadable extensions (llext) +* Added native_sim simulator target (successor to native_posix) +* Added new battery charger driver API +* Added new hardware spinlock driver API +* Added new modem subsystem +* Added support for 45+ new boards +* Networking: improvements to CoAP, Connection Manager, DHCP, Ethernet, gPTP, ICMP, + IPv6 and LwM2M +* Bluetooth: improvements to the Controller, Audio, Mesh, as well as the host stack in + general +* Improved LVGL graphics library integration +* Integrated support with the CodeChecker static analyzer +* Picolibc is now the default C standard library + +An overview of the changes required or recommended when migrating your application from Zephyr +v3.4.0 to Zephyr v3.5.0 can be found in the separate :ref:`migration guide`. The following sections provide detailed lists of changes by component. @@ -53,6 +68,9 @@ https://docs.zephyrproject.org/latest/security/vulnerabilities.html * CVE-2023-5563 `Zephyr project bug tracker GHSA-98mc-rj7w-7rpv `_ +* CVE-2023-5753 `Zephyr project bug tracker GHSA-hmpr-px56-rvww + `_ + Kernel ****** @@ -66,6 +84,15 @@ Architectures * ARC + * Introduced the scalar port for ARC VPX processors + * Introduced support for ARCv3 HS (both 32 and 64 bit) SMP platforms with up to 12 CPU cores + * Reworked GNU helper tools usage for ARC MWDT toolchain. Now helper tools can be used from + Zephyr SDK (if SDK is installed) + * Fixed dynamic thread stack allocation + * Fixed STR assembly macro offset calculation issue which may cause build error for ARCv3 64bit + * Cleaned-up and made more user friendly handling of the ARC MWDT toolchain path + (ARCMWDT_TOOLCHAIN_PATH) + * ARM * Architectural support for Arm Cortex-M has been separated from Arm @@ -91,6 +118,11 @@ Architectures * Added basic MMU v2 Support. +* x86 + + * Added support for Intel Alder Lake boards + * Added support for Intel Sensor Hub (ISH) + * POSIX * Has been reworked to use the native simulator. @@ -106,15 +138,149 @@ Bluetooth * Audio + Improved memory usage of codec configurations and codec capabilities. Fixed several bugs in BAP + and the BAP-related services (ASCS, PACS, BASS), as well as missing features such as proper + notification handling. + + * Added BAP ``bt_bap_stream_get_tx_sync`` + * Added CAP stream send and tx sync + * Added ``bt_audio_codec_cap_get`` helper functions + * Added support for long read/write in CAP + * Fixed ASCS Source ASE link loss state transition + * Fixed ASCS possible ASE leak + * Fixed ASCS to drop ISO PDUs if ASE is not in streaming state + * Fixed BAP ``bt_bap_scan_delegator_find_state`` implementation + * Fixed BAP issue with PA sync and ID in ``broadcast_sink_create`` + * Fixed TMAS characteristic permissions + * Fixed ``tbs_client`` missing discovery complete event + * Fixed audio stack to accept empty CCID list in audio metadata + * Fixed bad size of metadata_backup in ASCS + * Fixed possible ASCS ASE stuck in releasing state + * Refactored ``bt_audio_codec_cap`` to flat arrays + * Refactored ``bt_audio_codec_cfg`` to flat arrays + * Removed ``CONFIG_BT_PACS_{SNK,SRC}_CONTEXT`` + * Removed scanning and PA sync from broadcast sink + * Renamed ``bt_codec`` to ``bt_audio_codec_{cap, conf, data}`` + * Renamed codec qos framing + * Replaced ``BT_AUDIO_CODEC_LC3_ID`` -> ``BT_HCI_CODING_FORMAT_LC3`` + * Replaced ``BT_AUDIO_CODEC_PARSE_ERR_`` values with errno values. + * Reworked PACS notify system + * Updated ASCS ISO QOS based on BAP QOS + * Updated BAP to filter PA data duplicates by default + * Updated CSIP to unlock Non-bonded devices immediately. + * Updated PACS to notify bonded clients on reconnect + * Updated ``bt_cap_stream_ops_register`` to always register BAP callbacks + * Updated the ASCS ACL disconnect behavior + * Updated to split ``bt_audio_codec_meta_get`` to ``cfg`` and ``cap`` + * Direction Finding * Host + * Added SMP bondable flag overlay per connection + * Added USE_NRPA advertising option + * Added ``BT_CONN_PARAM_ANY`` to allow setting any value to connection parameters + * Added advanced broadcast ISO parameters + * Added advanced unicast ISO parameters + * Added new API to manage Bluetooth settings storage + * Fixed HCI ISO Data packets fragmentation + * Fixed HCI ISO SDU length sent to controller + * Fixed OTS ``bt_ots_init`` parameter struct naming + * Fixed OTS memory leak while procedure is not finished + * Fixed a connection reference leak + * Fixed forced pairing request handling + * Fixed host to invalidate the Resolvable Private Address when starting legacy advertising + * Fixed issue with ``bt_iso_cig_reconfigure`` + * Fixed possible buffer overflow in ``bt_conn_le_start_encryption`` + * Fixed some SMP issues + * Fixed to abort pairing if connection disconnected + * Updated L2CAP accept callbacks + * Updated LE L2CAP connected callback to be after connection response + * Updated PAwR implementation to use RPA as responder address if BT_PRIVACY=y + * Mesh + * Added TF-M support. + * Added support to use both tinycrypt and PSA based crypto + * Added full virtual addresses support with the collisions resolution. The + :kconfig:option:`CONFIG_BT_MESH_LABEL_NO_RECOVER` Kconfig option is introduced to restore the + addresses for the subscription list and model publication. + * Added statistic module. + * Fixed an issue where a node acting as a LPN was triggering Friend Poll messages when sending a + segmented message over the loopback interface. + * Fixed an issue where provisioning completes successfully on a node when the identical Public Key + is used by a provisioner. + * Fixed an issue where the :c:func:`settings_load` function called from a cooperative thread other + than the system workqueue caused the GATT Mesh Proxy Service registration to fail. + * Fixed an issue where a node could enter IV Update in Progress state if an old SNB with the + current IV Index and IV Update flag set to 1 was resent. + + * Mesh Protocol v1.1 changes + + * Added storing Private GATT Proxy state persistently. + * Added support for Firmware Distribution Upload OOB Start message in the Firwmware Distribution + Server model. The message support can be enabled with the + :kconfig:option:`CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD` Kconfig option. + * Added extended provisioning protocol timeout when OOB methods are used in the provisioning. + * Added support for Composition Data Pages 2, 129 and 130. + * Added documentation for Composition Data Pages 0, 1, 2, 128, 129 and 130. + * Added documentation for the Segmentation and Reassembly in the Transport layer. + * Added documentation for the SAR Configuration models + * Fixed an issue where the Opcode Aggregator Server model did not compile without the Opcode + Aggregator Client model. + * Fixed an issue where the identity address was used in Private GATT Proxy advertisements + instead of Non-Resolvable Private Addresses. + * Fixed the Proxy Privacy parameter support. + * Fixed an issue where the Composition Data Page 128 was not present on a node that has + instantiated the Remote Provisioning Server model. + * Fixed an issue where the Large Composition Data Server model did not support Composition Data + Pages other then 0. + * Fixed an issue where the Remote Provisioning Client model instanted on a node together with + the Remote Provisioning Server model could not reprovision itself. + * Fixed an issue where the acknowledgment timer in the Segmentation and Reassembly was not + restarted when the incoming Segment Acknowledgment message did not contain at least one + segment newly marked as acknowledged. + * Fixed an issue where the On-Demand Private Proxy Server and Client models had interdependency + that did not allow to compile them separately. + * Controller -* HCI Driver + Improved support for Broadcast and Connected Isochronous channels in the Controller, enabling + LE audio application development. The Controller is experimental, is missing implementations for + interleaved packing in Isochronous channels' lower link layer. + + * Added Checks for minimum sizes of Adv PDUs + * Added Kconfig Option to ignore Tx HCI ISO Data Packet Seq Num + * Added Kconfig for avoiding ISO SDU fragmentation + * Added Kconfig to maximize BIG event length and preempt PTO & CTRL subevents + * Added ``BT_CTLR_EVENT_OVERHEAD_RESERVE_MAX`` Kconfig + * Added memory barrier to ticker transactions + * Added missing nRF53x Tx Power Kconfig + * Added support for Flush Timeout in Connected ISO + * Fixed BIS payload sliding window overrun check + * Fixed CIS Central FT calculation + * Fixed CIS Central error handling + * 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 + * Fixed ULL stuck in semaphore under rare conditions + * Fixed assertion due to late PER CIS active set + * Fixed compiler instruction re-ordering that caused assertions + * Fixed connected ISO dynamic tx power + * Fixed failing advertising conformance tests + * Fixed handling received Auxiliary PDUs when Coded PHY not supported + * Fixed leak in scheduled ticker node when rescheduling ticker nodes + * Fixed missing host feature reset + * Fixed nRF53 SoC back-to-back PDU chaining + * Fixed nRF53 SoC back-to-back Tx Rx implementation + * Fixed regression in Adv PDU overflow calculation + * Fixed regression in observer that caused assertions and scheduling stall + * Fixed use of pre-programmed PPI on nRF SoCs + * Removed HCI ISO data with invalid status in preparation for FT support + * Updated Extended Advertising Report to not be generated when ``AUX_ADV_IND`` not received + * Updated to have ``EVENT_OVERHEAD_START_US`` verbose assertion in each state/role LLL + * Updated to stop following ``aux_ptr`` if ``DATA_LEN_MAX`` is reached during extended scanning Boards & SoC Support ******************** @@ -138,9 +304,17 @@ Boards & SoC Support * i.MX RT SOCs no longer support CONFIG_OCRAM_NOCACHE, as this functionality can be achieved using devicetree memory regions * Refactored ESP32 SoC folders. So now these are a proper SoC series. + * RP2040: Changed to reset the I2C device on initializing * Added support for these ARC boards: + * Added support for nsim_vpx5 - simulation (nSIM) platform with ARCv2 VPX5 core, close to + vpx5_integer_full template + * Added support for nsim_hs5x_smp_12cores - simulation (nSIM) platform with 12 cores SMP 32-bit + ARCv3 HS + * Added support for nsim_hs6x_smp_12cores - simulation (nSIM) platform with 12 cores SMP 64-bit + ARCv3 HS + * Added support for these ARM boards: * Nuvoton NuMaker Platform M467 @@ -176,10 +350,17 @@ Boards & SoC Support * Made these changes for ARC boards: + * Turned off unsupported stack checking option for hsdk4xd platform + * Changed vendor prefix for ARC QEMU platforms from "qemu" to "snps" + * Made these changes for ARM boards: * ST morpho connector description was added on ST nucleo boards. + * rpi_pico: + + * The default adapter when debugging with openocd has been changed to cmsis-dap. + * Made these changes for ARM64 boards: * Made these changes for RISC-V boards: @@ -273,8 +454,12 @@ Drivers and Sensors option. * Added support for the ADC sequencer for all STM32 series (except F1) * Fixed STM32F4 ADC temperature and Vbat measurement. - -* Battery-backed RAM + * Added driver for TI ADS1112. + * Added driver for TI TLA2021. + * Added driver for Gecko ADC. + * Added driver for NXP S32 ADC SAR. + * Added driver for MAX1125x family. + * Added driver for MAX11102-MAX1117. * CAN @@ -294,17 +479,18 @@ Drivers and Sensors * Added :kconfig:option:`CONFIG_COUNTER_RTC_STM32_SUBSECONDS` to enable subsecond as the basic time tick on STM32 RTC based counter driver. -* Crypto + * Added support for Raspberry Pi Pico Timer * DAC * Added support for Analog Devices AD56xx * Added support for NXP lpcxpresso55s36 (LPDAC) -* DFU - * Disk + * Ramdisk driver is now configured using devicetree, and supports multiple + instances + * Display * Added support for ST7735S (in ST7735R driver) @@ -328,8 +514,6 @@ Drivers and Sensors * Added a requirement for ``entropy_get_entropy()`` to be thread-safe because of random subsystem needs. -* ESPI - * Ethernet * Added :kconfig:option:`CONFIG_ETH_NATIVE_POSIX_RX_TIMEOUT` to set rx timeout for native posix. @@ -360,16 +544,10 @@ Drivers and Sensors * STM32 QSPI driver now supports Jedec SFDP parameter reading. * STM32 OSPI driver now supports both Low and High ports of IO manager. -* FPGA - -* Fuel Gauge - * GPIO * Added support for Nuvoton NuMaker M46x -* hwinfo - * I2C * STM32 V1 driver now supports large transactions (more than 256 bytes chunks) @@ -387,6 +565,8 @@ Drivers and Sensors * I2S + * Fixed handling of the PCM data format in the NXP MCUX driver. + * I3C * ``i3c_cdns``: @@ -437,16 +617,6 @@ Drivers and Sensors * Renamed the callback definition macro from ``INPUT_LISTENER_CB_DEFINE`` to :c:macro:`INPUT_CALLBACK_DEFINE`. -* IPM - -* KSCAN - -* LED - -* MBOX - -* MEMC - * PCIE * Added support in shell to display PCIe capabilities. @@ -458,7 +628,9 @@ Drivers and Sensors * Added support to get IRQ from ACPI PCI Routing Table (PRT). -* PECI +* ACPI + + * Adopted the ACPICA library as a new module to further enhance ACPI support. * Pin control @@ -467,8 +639,16 @@ Drivers and Sensors * PWM * Added 4 channels capture on STM32 PWM driver. - -* Power domain + * Added driver for Intel Blinky PWM. + * Added driver for MAX31790. + * Added driver for Infineon XMC4XXX CCU4. + * Added driver for Infineon XMC4XXX CCU8. + * Added MCUX CTimer based PWM driver. + * Added PWM driver based on TI CC13xx/CC26xx GPT timer. + * Reworked the pwm_nrf5_sw driver so that it can be used also on nRF53 and + nRF91 Series. Consequently, the driver was renamed to pwm_nrf_sw. + * Added driver for Nuvoton NuMaker family. + * Added PWM driver based on NXP S32 EMIOS peripheral. * Regulators @@ -504,6 +684,9 @@ Drivers and Sensors * SDHC + * Added driver for EMMC Host controller present on Alder lake platforms + * Added driver for Atmel HSMCI controller present on SAM4E MCU series + * Sensor * Reworked the :dtcompatible:`ti,bq274xx` to add ``BQ27427`` support, fixed @@ -559,9 +742,12 @@ Drivers and Sensors * ``uart_emul``: added support for interrupt API. + * ``uart_rpi_pico``: fixed handling Modbus DE-RE signal + * SPI * Remove npcx spi driver implemented by Flash Interface Unit (FIU) module. + * Added support for Raspberry Pi Pico PIO based SPI. * Timer @@ -577,10 +763,6 @@ Drivers and Sensors with UDC API (experimental). * Added support for STM32H5 series on USB driver. -* W1 - -* Watchdog - * WiFi * Increased esp32 default network (TCP workq, RX and mgmt event) stack sizes to 2048 bytes. @@ -658,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. @@ -783,6 +965,1087 @@ USB Devicetree ********** +API +=== + +New general-purpose macros: + +- :c:macro:`DT_REG_ADDR_U64` +- :c:macro:`DT_REG_ADDR_BY_NAME_U64` +- :c:macro:`DT_INST_REG_ADDR_BY_NAME_U64` +- :c:macro:`DT_INST_REG_ADDR_U64` +- :c:macro:`DT_FOREACH_STATUS_OKAY_NODE_VARGS` +- :c:macro:`DT_FOREACH_NODE_VARGS` +- :c:macro:`DT_HAS_COMPAT_ON_BUS_STATUS_OKAY` + +New special-purpose macros introduced for dependency ordinals: + +- :c:macro:`DT_DEP_ORD_STR_SORTABLE` + +New general purpose macros introduced for fixed flash partitions: + +- :c:macro:`DT_MEM_FROM_FIXED_PARTITION` +- :c:macro:`DT_FIXED_PARTITION_ADDR` + +Bindings +======== + +* Generic or vendor-independent: + + * New bindings: + + * :dtcompatible:`current-sense-amplifier` + * :dtcompatible:`current-sense-shunt` + * :dtcompatible:`gpio-qdec` + * :dtcompatible:`regulator-gpio` + * :dtcompatible:`usb-audio-feature-volume` + + * Modified bindings: + + * CAN (Controller Area Network) controller bindings: + + * property ``phase-seg1-data`` deprecation status changed from False to True + * property ``phase-seg1`` deprecation status changed from False to True + * property ``phase-seg2-data`` deprecation status changed from False to True + * property ``phase-seg2`` deprecation status changed from False to True + * property ``prop-seg-data`` deprecation status changed from False to True + * property ``prop-seg`` deprecation status changed from False to True + * property ``sjw-data`` default value changed from None to 1 + * property ``sjw-data`` deprecation status changed from False to True + * property ``sjw`` default value changed from None to 1 + * property ``sjw`` deprecation status changed from False to True + + * Ethernet controller bindings: new ``phy-handle`` property (in some + bindings, this was renamed from ``phy-dev``), matching the Linux + ethernet-controller binding. + + * The ``riscv,isa`` property used by RISC-V CPU bindings no longer has an + ``enum`` value. + + * :dtcompatible:`neorv32-cpu`: + + * new property: ``mmu-type`` + * new property: ``riscv,isa`` + + * :dtcompatible:`regulator-fixed`: + + * new property: ``regulator-min-microvolt`` + * new property: ``regulator-max-microvolt`` + * property ``enable-gpios`` is no longer required + + * :dtcompatible:`ethernet-phy`: + + * removed property: ``address`` + * removed property: ``mdio`` + * property ``reg`` is now required + + * :dtcompatible:`usb-audio-hs` and :dtcompatible:`usb-audio-hp`: + + * new property: ``volume-max`` + * new property: ``volume-min`` + * new property: ``volume-res`` + * new property: ``status`` + * new property: ``compatible`` + * new property: ``reg`` + * new property: ``reg-names`` + * new property: ``interrupts`` + * new property: ``interrupts-extended`` + * new property: ``interrupt-names`` + * new property: ``interrupt-parent`` + * new property: ``label`` + * new property: ``clocks`` + * new property: ``clock-names`` + * new property: ``#address-cells`` + * new property: ``#size-cells`` + * new property: ``dmas`` + * new property: ``dma-names`` + * new property: ``io-channels`` + * new property: ``io-channel-names`` + * new property: ``mboxes`` + * new property: ``mbox-names`` + * new property: ``wakeup-source`` + * new property: ``power-domain`` + * new property: ``zephyr,pm-device-runtime-auto`` + + * :dtcompatible:`ntc-thermistor-generic`: + + * removed property: ``r25-ohm`` + + * :dtcompatible:`ns16550`: + + * new property: ``resets`` + * new property: ``reset-names`` + + * :dtcompatible:`fixed-clock`: + + * removed property: ``clocks`` + + * All CPU bindings got a new ``enable-method`` property. `pull request + 60210 `_ for + details. + +* Analog Devices, Inc. (adi): + + * New bindings: + + * :dtcompatible:`adi,ad5628` + * :dtcompatible:`adi,ad5648` + * :dtcompatible:`adi,ad5668` + * :dtcompatible:`adi,ad5672` + * :dtcompatible:`adi,ad5674` + * :dtcompatible:`adi,ad5676` + * :dtcompatible:`adi,ad5679` + * :dtcompatible:`adi,ad5684` + * :dtcompatible:`adi,ad5686` + * :dtcompatible:`adi,ad5687` + * :dtcompatible:`adi,ad5689` + * :dtcompatible:`adi,adin1110` + * :dtcompatible:`adi,adltc2990` + + * Modified bindings: + + * :dtcompatible:`adi,adin2111-mdio` (on adin2111 bus): + + * removed property: ``protocol`` + +* Altera Corp. (altr): + + * New bindings: + + * :dtcompatible:`altr,pio-1.0` + +* Ambiq Micro, Inc. (ambiq): + + * New bindings: + + * :dtcompatible:`ambiq,am1805` + * :dtcompatible:`ambiq,apollo4-pinctrl` + * :dtcompatible:`ambiq,counter` + * :dtcompatible:`ambiq,i2c` + * :dtcompatible:`ambiq,mspi` + * :dtcompatible:`ambiq,pwrctrl` + * :dtcompatible:`ambiq,spi` + * :dtcompatible:`ambiq,stimer` + * :dtcompatible:`ambiq,uart` + * :dtcompatible:`ambiq,watchdog` + +* AMS AG (ams): + + * New bindings: + + * :dtcompatible:`ams,tsl2540` + +* Andes Technology Corporation (andestech): + + * New bindings: + + * :dtcompatible:`andestech,atcwdt200` + * :dtcompatible:`andestech,plic-sw` + * :dtcompatible:`andestech,qspi-nor` + +* ARM Ltd. (arm): + + * New bindings: + + * :dtcompatible:`arm,cortex-a76` + * :dtcompatible:`arm,gic-v1` + * :dtcompatible:`arm,gic-v2` + * :dtcompatible:`arm,gic-v3` + * :dtcompatible:`arm,psci-1.1` + +* ASPEED Technology Inc. (aspeed): + + * Modified bindings: + + * :dtcompatible:`aspeed,ast10x0-reset`: + + * specifier cells for space "reset" are now named: ['id'] (old value: None) + * specifier cells for space "clock" are now named: None (old value: ['reset_id']) + +* Atmel Corporation (atmel): + + * New bindings: + + * :dtcompatible:`atmel,sam-hsmci` + + * Modified bindings: + + * :dtcompatible:`atmel,sam-mdio`: + + * removed property: ``protocol`` + * property ``#address-cells`` const value changed from None to 1 + * property ``#size-cells`` const value changed from None to 0 + * property ``#address-cells`` is now required + * property ``#size-cells`` is now required + +* Bosch Sensortec GmbH (bosch): + + * New bindings: + + * :dtcompatible:`bosch,bmi08x-accel` + * :dtcompatible:`bosch,bmi08x-accel` + * :dtcompatible:`bosch,bmi08x-gyro` + * :dtcompatible:`bosch,bmi08x-gyro` + + * Modified bindings: + + * :dtcompatible:`bosch,bmm150`: + + * new property: ``drdy-gpios`` + + * :dtcompatible:`bosch,bmi270`: + + * new property: ``irq-gpios`` + +* Broadcom Corporation (brcm): + + * New bindings: + + * :dtcompatible:`brcm,bcm2711-aux-uart` + +* Cadence Design Systems Inc. (cdns): + + * New bindings: + + * :dtcompatible:`cdns,tensilica-xtensa-lx3` + +* DFRobot (dfrobot): + + * New bindings: + + * :dtcompatible:`dfrobot,a01nyub` + +* Efinix Inc (efinix): + + * New bindings: + + * :dtcompatible:`efinix,sapphire-gpio` + * :dtcompatible:`efinix,sapphire-timer0` + * :dtcompatible:`efinix,sapphire-uart0` + +* EPCOS AG (epcos): + + * Modified bindings: + + * :dtcompatible:`epcos,b57861s0103a039`: + + * removed property: ``r25-ohm`` + +* Espressif Systems (espressif): + + * Modified bindings: + + * :dtcompatible:`espressif,esp-at` (on uart bus): + + * new property: ``external-reset`` + + * :dtcompatible:`espressif,esp32-mdio`: + + * removed property: ``protocol`` + * property ``#address-cells`` const value changed from None to 1 + * property ``#size-cells`` const value changed from None to 0 + * property ``#address-cells`` is now required + * property ``#size-cells`` is now required + + * :dtcompatible:`espressif,riscv`: + + * new property: ``mmu-type`` + * new property: ``riscv,isa`` + + * :dtcompatible:`espressif,esp32-spi`: + + * new property: ``line-idle-low`` + +* Feature Integration Technology Inc. (fintek): + + * New bindings: + + * :dtcompatible:`fintek,f75303` + +* FocalTech Systems Co.,Ltd (focaltech): + + * Modified bindings: + + * :dtcompatible:`focaltech,ft5336` (on i2c bus): + + * new property: ``reset-gpios`` + +* Fujitsu Ltd. (fujitsu): + + * New bindings: + + * :dtcompatible:`fujitsu,mb85rcxx` + +* Shenzhen Huiding Technology Co., Ltd. (goodix): + + * Modified bindings: + + * :dtcompatible:`goodix,gt911` (on i2c bus): + + * bus list changed from ['kscan'] to [] + * new property: ``alt-addr`` + +* Himax Technologies, Inc. (himax): + + * New bindings: + + * :dtcompatible:`himax,hx8394` + +* Infineon Technologies (infineon): + + * New bindings: + + * :dtcompatible:`infineon,cat1-counter` + * :dtcompatible:`infineon,cat1-spi` + * :dtcompatible:`infineon,xmc4xxx-ccu4-pwm` + * :dtcompatible:`infineon,xmc4xxx-ccu8-pwm` + * :dtcompatible:`infineon,xmc4xxx-i2c` + +* Intel Corporation (intel): + + * New bindings: + + * :dtcompatible:`intel,agilex5-clock` + * :dtcompatible:`intel,alder-lake` + * :dtcompatible:`intel,apollo-lake` + * :dtcompatible:`intel,blinky-pwm` + * :dtcompatible:`intel,elkhart-lake` + * :dtcompatible:`intel,emmc-host` + * :dtcompatible:`intel,ish` + * :dtcompatible:`intel,loapic` + * :dtcompatible:`intel,sedi-gpio` + * :dtcompatible:`intel,sedi-i2c` + * :dtcompatible:`intel,sedi-ipm` + * :dtcompatible:`intel,sedi-uart` + * :dtcompatible:`intel,socfpga-agilex-sip-smc` + * :dtcompatible:`intel,socfpga-reset` + * :dtcompatible:`intel,timeaware-gpio` + + * Removed bindings: + + * ``intel,agilex-socfpga-sip-smc`` + * ``intel,apollo_lake`` + * ``intel,elkhart_lake`` + * ``intel,gna`` + + * Modified bindings: + + * :dtcompatible:`intel,niosv`: + + * new property: ``mmu-type`` + * new property: ``riscv,isa`` + + * :dtcompatible:`intel,adsp-imr`: + + * new property: ``zephyr,memory-attr`` + * property ``zephyr,memory-region-mpu`` enum value changed from ['RAM', 'RAM_NOCACHE', 'FLASH', 'PPB', 'IO', 'EXTMEM'] to None + * property ``zephyr,memory-region-mpu`` deprecation status changed from False to True + + * :dtcompatible:`intel,lpss`: + + * new property: ``dma-parent`` + + * :dtcompatible:`intel,adsp-shim-clkctl`: + + * new property: ``adsp-clkctl-clk-ipll`` + +* Isentek Inc. (isentek): + + * New bindings: + + * :dtcompatible:`isentek,ist8310` + +* Integrated Silicon Solutions Inc. (issi): + + * New bindings: + + * :dtcompatible:`issi,is31fl3216a` + * :dtcompatible:`issi,is31fl3733` + +* ITE Tech. Inc. (ite): + + * New bindings: + + * :dtcompatible:`ite,it8xxx2-sha` + + * Modified bindings: + + * :dtcompatible:`ite,it8xxx2-pinctrl-func`: + + * new property: ``func3-ext`` + * new property: ``func3-ext-mask`` + + * :dtcompatible:`ite,riscv-ite`: + + * new property: ``mmu-type`` + * new property: ``riscv,isa`` + + * :dtcompatible:`ite,enhance-i2c`: + + * new property: ``target-enable`` + * new property: ``target-pio-mode`` + +* Linaro Limited (linaro): + + * New bindings: + + * :dtcompatible:`linaro,ivshmem-ipm` + +* Maxim Integrated Products (maxim): + + * New bindings: + + * :dtcompatible:`maxim,max11102` + * :dtcompatible:`maxim,max11103` + * :dtcompatible:`maxim,max11105` + * :dtcompatible:`maxim,max11106` + * :dtcompatible:`maxim,max11110` + * :dtcompatible:`maxim,max11111` + * :dtcompatible:`maxim,max11115` + * :dtcompatible:`maxim,max11116` + * :dtcompatible:`maxim,max11117` + * :dtcompatible:`maxim,max11253` + * :dtcompatible:`maxim,max11254` + * :dtcompatible:`maxim,max31790` + +* Microchip Technology Inc. (microchip): + + * New bindings: + + * :dtcompatible:`microchip,mcp251xfd` + * :dtcompatible:`microchip,mpfs-i2c` + * :dtcompatible:`microchip,tcn75a` + + * Modified bindings: + + * :dtcompatible:`microchip,xec-pwmbbled`: + + * new property: ``enable-low-power-32k`` + + * :dtcompatible:`microchip,cap1203` (on i2c bus): + + * bus list changed from ['kscan'] to [] + * new property: ``input-codes`` + + * :dtcompatible:`microchip,xec-ps2`: + + * new property: ``wakerx-gpios`` + +* Motorola, Inc. (motorola): + + * Modified bindings: + + * :dtcompatible:`motorola,mc146818`: + + * new property: ``clock-frequency`` + +* Murata Manufacturing Co., Ltd. (murata): + + * New bindings: + + * :dtcompatible:`murata,ncp15wb473` + +* Nordic Semiconductor (nordic): + + * New bindings: + + * :dtcompatible:`nordic,npm1300-led` + * :dtcompatible:`nordic,npm1300-wdt` + + * Removed bindings: + + * ``nordic,nrf-cc310`` + * ``nordic,nrf-cc312`` + + * Modified bindings: + + * :dtcompatible:`nordic,nrf-ccm`: + + * new property: ``headermask-supported`` + + * :dtcompatible:`nordic,nrf-twi`: + + * new property: ``easydma-maxcnt-bits`` + + * :dtcompatible:`nordic,nrf-twim` and :dtcompatible:`nordic,nrf-twis`: + + * new property: ``easydma-maxcnt-bits`` + * new property: ``memory-regions`` + * new property: ``memory-region-names`` + + * :dtcompatible:`nordic,nrf-spi`, :dtcompatible:`nordic,nrf-spis`, and + :dtcompatible:`nordic,nrf-spim`: + + * new property: ``wake-gpios`` + + * :dtcompatible:`nordic,npm1300-charger`: + + * new property: ``thermistor-cold-millidegrees`` + * new property: ``thermistor-cool-millidegrees`` + * new property: ``thermistor-warm-millidegrees`` + * new property: ``thermistor-hot-millidegrees`` + * new property: ``trickle-microvolt`` + * new property: ``term-current-percent`` + * new property: ``vbatlow-charge-enable`` + * new property: ``disable-recharge`` + + * :dtcompatible:`nordic,nrf-uicr`: + + * new property: ``nfct-pins-as-gpios`` + * new property: ``gpio-as-nreset`` + + * :dtcompatible:`nordic,npm1300` (on i2c bus): + + * new property: ``host-int-gpios`` + * new property: ``pmic-int-pin`` + +* Nuclei System Technology (nuclei): + + * Modified bindings: + + * :dtcompatible:`nuclei,bumblebee`: + + * new property: ``mmu-type`` + * new property: ``riscv,isa`` + +* Nuvoton Technology Corporation (nuvoton): + + * New bindings: + + * :dtcompatible:`nuvoton,nct38xx` + * :dtcompatible:`nuvoton,nct38xx-gpio` + * :dtcompatible:`nuvoton,npcx-fiu-nor` + * :dtcompatible:`nuvoton,npcx-fiu-qspi` + * :dtcompatible:`nuvoton,numaker-fmc` + * :dtcompatible:`nuvoton,numaker-gpio` + * :dtcompatible:`nuvoton,numaker-pcc` + * :dtcompatible:`nuvoton,numaker-pinctrl` + * :dtcompatible:`nuvoton,numaker-pwm` + * :dtcompatible:`nuvoton,numaker-rst` + * :dtcompatible:`nuvoton,numaker-scc` + * :dtcompatible:`nuvoton,numaker-spi` + * :dtcompatible:`nuvoton,numaker-uart` + + * Removed bindings: + + * ``nuvoton,nct38xx-gpio`` + * ``nuvoton,npcx-spi-fiu`` + + * Modified bindings: + + * :dtcompatible:`nuvoton,npcx-sha`: + + * new property: ``context-buffer-size`` + + * :dtcompatible:`nuvoton,npcx-adc`: + + * new property: ``vref-mv`` + * removed property: ``threshold-reg-offset`` + + * :dtcompatible:`nuvoton,adc-cmp`: + + * new property: ``thr-sel`` + + * :dtcompatible:`nuvoton,npcx-pcc`: + + * new property: ``pwdwn-ctl-val`` + * property ``clock-frequency`` enum value changed from [100000000, 96000000, 90000000, 80000000, 66000000, 50000000, 48000000, 40000000, 33000000] to [120000000, 100000000, 96000000, 90000000, 80000000, 66000000, 50000000, 48000000] + * property ``ram-pd-depth`` enum value changed from [12, 15] to [8, 12, 15] + +* NXP Semiconductors (nxp): + + * New bindings: + + * :dtcompatible:`nxp,ctimer-pwm` + * :dtcompatible:`nxp,fs26-wdog` + * :dtcompatible:`nxp,imx-flexspi-w956a8mbya` + * :dtcompatible:`nxp,irqsteer-intc` + * :dtcompatible:`nxp,lpdac` + * :dtcompatible:`nxp,mbox-imx-mu` + * :dtcompatible:`nxp,mcux-dcp` + * :dtcompatible:`nxp,mcux-edma-v3` + * :dtcompatible:`nxp,pcf8563` + * :dtcompatible:`nxp,pxp` + * :dtcompatible:`nxp,s32-adc-sar` + * :dtcompatible:`nxp,s32-clock` + * :dtcompatible:`nxp,s32-emios` + * :dtcompatible:`nxp,s32-emios-pwm` + * :dtcompatible:`nxp,s32-gmac` + * :dtcompatible:`nxp,s32-qspi` + * :dtcompatible:`nxp,s32-qspi-device` + * :dtcompatible:`nxp,s32-qspi-nor` + * :dtcompatible:`nxp,s32k3-pinctrl` + * :dtcompatible:`nxp,smartdma` + * :dtcompatible:`nxp,tempmon` + * :dtcompatible:`nxp,vref` + + * Modified bindings: + + * :dtcompatible:`nxp,s32-netc-emdio`: + + * removed property: ``protocol`` + * property ``#address-cells`` const value changed from None to 1 + * property ``#size-cells`` const value changed from None to 0 + * property ``#address-cells`` is now required + * property ``#size-cells`` is now required + + * :dtcompatible:`nxp,mipi-dsi-2l`: + + * property ``nxp,lcdif`` is no longer required + + * :dtcompatible:`nxp,imx-mipi-dsi`: + + * property ``nxp,lcdif`` is no longer required + + * :dtcompatible:`nxp,pca9633` (on i2c bus): + + * new property: ``disable-allcall`` + + * :dtcompatible:`nxp,s32-sys-timer`: + + * removed property: ``clock-frequency`` + * property ``clocks`` is now required + + * :dtcompatible:`nxp,imx-lpspi`: + + * new property: ``data-pin-config`` + + * :dtcompatible:`nxp,s32-spi`: + + * property ``clock-frequency`` is no longer required + * property ``clocks`` is now required + + * :dtcompatible:`nxp,imx-wdog`: + + * pinctrl support + + * :dtcompatible:`nxp,s32-swt`: + + * removed property: ``clock-frequency`` + * property ``clocks`` is now required + + * :dtcompatible:`nxp,lpc-lpadc`: + + * new property: ``nxp,reference-supply`` + + * :dtcompatible:`nxp,kinetis-pit`: + + * new property: ``max-load-value`` + * property ``clocks`` is now required + + * :dtcompatible:`nxp,mcux-edma`: + + * new property: ``dmamux-reg-offset`` + * new property: ``channel-gap`` + * new property: ``irq-shared-offset`` + + * :dtcompatible:`nxp,imx-elcdif`: + + * new property: ``nxp,pxp`` + +* ON Semiconductor Corp. (onnn): + + * New bindings: + + * :dtcompatible:`onnn,ncp5623` + +* Princeton Technology Corp. (ptc): + + * New bindings: + + * :dtcompatible:`ptc,pt6314` + +* Quectel Wireless Solutions Co., Ltd. (quectel): + + * New bindings: + + * :dtcompatible:`quectel,bg95` + +* QuickLogic Corp. (quicklogic): + + * New bindings: + + * :dtcompatible:`quicklogic,eos-s3-pinctrl` + + * Modified bindings: + + * :dtcompatible:`quicklogic,usbserialport-s3b`: + + * pinctrl support + +* Raspberry Pi Foundation (raspberrypi): + + * New bindings: + + * :dtcompatible:`raspberrypi,pico-header` + * :dtcompatible:`raspberrypi,pico-i2c` + * :dtcompatible:`raspberrypi,pico-spi-pio` + * :dtcompatible:`raspberrypi,pico-timer` + +* Raydium Semiconductor Corp. (raydium): + + * New bindings: + + * :dtcompatible:`raydium,rm67162` + +* Renesas Electronics Corporation (renesas): + + * New bindings: + + * :dtcompatible:`renesas,smartbond-lp-osc` + * :dtcompatible:`renesas,smartbond-timer` + + * Modified bindings: + + * :dtcompatible:`renesas,smartbond-flash-controller`: + + * new property: ``read-cs-idle-delay`` + * new property: ``erase-cs-idle-delay`` + +* Smart Battery System (sbs): + + * New bindings: + + * :dtcompatible:`sbs,default-sbs-gauge` + * :dtcompatible:`sbs,sbs-charger` + +* Seeed Technology Co., Ltd (seeed): + + * New bindings: + + * :dtcompatible:`seeed,hm330x` + +* SiFive, Inc. (sifive): + + * Modified bindings: + + * :dtcompatible:`sifive,i2c0`: + + * pinctrl support + +* Silicon Laboratories (silabs): + + * New bindings: + + * :dtcompatible:`silabs,gecko-adc` + +* Sino Wealth Electronic Ltd (sinowealth): + + * New bindings: + + * :dtcompatible:`sinowealth,sh1106` + * :dtcompatible:`sinowealth,sh1106` + +* Sitronix Technology Corporation (sitronix): + + * Modified bindings: + + * :dtcompatible:`sitronix,st7735r` (on spi bus): + + * property ``reset-gpios`` is no longer required + +* Standard Microsystems Corporation (smsc): + + * Modified bindings: + + * :dtcompatible:`smsc,lan91c111-mdio`: + + * removed property: ``protocol`` + * property ``#address-cells`` const value changed from None to 1 + * property ``#size-cells`` const value changed from None to 0 + * property ``#address-cells`` is now required + * property ``#size-cells`` is now required + + * :dtcompatible:`smsc,lan91c111`: + + * new property: ``local-mac-address`` + * new property: ``zephyr,random-mac-address`` + * property ``reg`` is no longer required + +* Synopsys, Inc. (snps): + + * New bindings: + + * :dtcompatible:`snps,dw-timers` + +* Solomon Systech Limited (solomon): + + * Modified bindings: + + * :dtcompatible:`solomon,ssd1306fb` + + * new property: ``inversion-on`` + * new property: ``ready-time-ms`` + +* Sequans Communications (sqn): + + * New bindings: + + * :dtcompatible:`sqn,hwspinlock` + +* STMicroelectronics (st): + + * New bindings: + + * :dtcompatible:`st,stm32-bxcan` + * :dtcompatible:`st,stm32-spi-host-cmd` + * :dtcompatible:`st,stm32f1-rcc` + * :dtcompatible:`st,stm32f3-rcc` + * :dtcompatible:`st,stm32wba-flash-controller` + * :dtcompatible:`st,stm32wba-hse-clock` + * :dtcompatible:`st,stm32wba-pll-clock` + * :dtcompatible:`st,stm32wba-rcc` + * :dtcompatible:`st,stmpe811` + + * Removed bindings: + + * ``st,stm32-can`` + + * Modified bindings: + + * :dtcompatible:`st,stm32-pwm`: + + * new property: ``four-channel-capture-support`` + + * :dtcompatible:`st,stm32f4-adc`: + + * new property: ``st,adc-clock-source`` + * new property: ``st,adc-prescaler`` + * new property: ``st,adc-sequencer`` + * removed property: ``temp-channel`` + * removed property: ``vref-channel`` + * removed property: ``vbat-channel`` + + * :dtcompatible:`st,stm32-adc`: + + * new property: ``st,adc-clock-source`` + * new property: ``st,adc-prescaler`` + * new property: ``st,adc-sequencer`` + * removed property: ``temp-channel`` + * removed property: ``vref-channel`` + * removed property: ``vbat-channel`` + + * :dtcompatible:`st,stm32f1-adc`: + + * new property: ``st,adc-sequencer`` + * removed property: ``temp-channel`` + * removed property: ``vref-channel`` + * removed property: ``vbat-channel`` + + * :dtcompatible:`st,stm32-ospi`: + + * new property: ``io-low-port`` + * new property: ``io-high-port`` + + * :dtcompatible:`st,stm32c0-hsi-clock`: + + * removed property: ``clocks`` + + * :dtcompatible:`st,stm32-hse-clock`: + + * removed property: ``clocks`` + + * :dtcompatible:`st,stm32wl-hse-clock`: + + * removed property: ``clocks`` + + * :dtcompatible:`st,stm32g0-hsi-clock`: + + * removed property: ``clocks`` + + * :dtcompatible:`st,stm32h7-hsi-clock`: + + * removed property: ``clocks`` + + * :dtcompatible:`st,stm32-lse-clock`: + + * removed property: ``clocks`` + + * :dtcompatible:`st,stm32u5-pll-clock`: + + * new property: ``fracn`` + +* Telink Semiconductor (telink): + + * Modified bindings: + + * :dtcompatible:`telink,b91-pwm`: + + * pinctrl support + + * :dtcompatible:`telink,b91`: + + * new property: ``mmu-type`` + * new property: ``riscv,isa`` + + * :dtcompatible:`telink,b91-i2c`: + + * pinctrl support + + * :dtcompatible:`telink,b91-spi`: + + * pinctrl support + + * :dtcompatible:`telink,b91-uart`: + + * pinctrl support + +* Texas Instruments (ti): + + * New bindings: + + * :dtcompatible:`ti,ads1112` + * :dtcompatible:`ti,bq27z746` + * :dtcompatible:`ti,cc13xx-cc26xx-rtc-timer` + * :dtcompatible:`ti,cc13xx-cc26xx-timer` + * :dtcompatible:`ti,cc13xx-cc26xx-timer-pwm` + * :dtcompatible:`ti,cc32xx-pinctrl` + * :dtcompatible:`ti,davinci-gpio` + * :dtcompatible:`ti,davinci-gpio-nexus` + * :dtcompatible:`ti,lp5009` + * :dtcompatible:`ti,lp5012` + * :dtcompatible:`ti,lp5018` + * :dtcompatible:`ti,lp5024` + * :dtcompatible:`ti,lp5030` + * :dtcompatible:`ti,lp5036` + * :dtcompatible:`ti,lp5569` + * :dtcompatible:`ti,tas6422dac` + * :dtcompatible:`ti,tcan4x5x` + * :dtcompatible:`ti,tla2021` + * :dtcompatible:`ti,tmag5170` + * :dtcompatible:`ti,vim` + + * Removed bindings: + + * ``ti,cc13xx-cc26xx-rtc`` + * ``ti,lp503x`` + + * Modified bindings: + + * :dtcompatible:`ti,cc32xx-i2c`: + + * pinctrl support + + * :dtcompatible:`ti,ina230` (on i2c bus): + + * new property: ``alert-config`` + * new property: ``adc-mode`` + * new property: ``vbus-conversion-time-us`` + * new property: ``vshunt-conversion-time-us`` + * new property: ``avg-count`` + * new property: ``rshunt-micro-ohms`` + * removed property: ``rshunt-milliohms`` + * property ``config`` default value changed from None to 0 + * property ``config`` deprecation status changed from False to True + * property ``config`` is no longer required + + * :dtcompatible:`ti,ina237` (on i2c bus): + + * new property: ``adc-mode`` + * new property: ``vbus-conversion-time-us`` + * new property: ``vshunt-conversion-time-us`` + * new property: ``temp-conversion-time-us`` + * new property: ``avg-count`` + * new property: ``high-precision`` + * new property: ``rshunt-micro-ohms`` + * removed property: ``rshunt-milliohms`` + * property ``adc-config`` default value changed from None to 0 + * property ``config`` default value changed from None to 0 + * property ``adc-config`` deprecation status changed from False to True + * property ``config`` deprecation status changed from False to True + * property ``adc-config`` is no longer required + * property ``config`` is no longer required + + * :dtcompatible:`ti,cc32xx-uart`: + + * pinctrl support + +* A stand-in for a real vendor which can be used in examples and tests (vnd): + + * New bindings: + + * :dtcompatible:`vnd,memory-attr` + * :dtcompatible:`vnd,reg-holder-64` + * :dtcompatible:`vnd,reserved-compat` + + * Modified bindings: + + * :dtcompatible:`vnd,serial`: + + * property ``reg`` is no longer required + +* X-Powers (x-powers): + + * New bindings: + + * :dtcompatible:`x-powers,axp192` + * :dtcompatible:`x-powers,axp192-gpio` + * :dtcompatible:`x-powers,axp192-regulator` + +* Xen Hypervisor (xen): + + * New bindings: + + * :dtcompatible:`xen,xen` + + * Removed bindings: + + * ``xen,xen-4.15`` + +* Xilinx (xlnx): + + * New bindings: + + * :dtcompatible:`xlnx,zynqmp-ipi-mailbox` + +* Shenzhen Xptek Technology Co., Ltd (xptek): + + * Modified bindings: + + * :dtcompatible:`xptek,xpt2046` (on spi bus): + + * bus list changed from ['kscan'] to [] + +* Zephyr-specific binding (zephyr): + + * New bindings: + + * :dtcompatible:`zephyr,fake-rtc` + * :dtcompatible:`zephyr,i2c-dump-allowlist` + * :dtcompatible:`zephyr,lvgl-button-input` + * :dtcompatible:`zephyr,lvgl-encoder-input` + * :dtcompatible:`zephyr,lvgl-pointer-input` + * :dtcompatible:`zephyr,mdio-gpio` + * :dtcompatible:`zephyr,native-tty-uart` + * :dtcompatible:`zephyr,ram-disk` + * :dtcompatible:`zephyr,sensing` + * :dtcompatible:`zephyr,sensing-phy-3d-sensor` + + * Removed bindings: + + * ``zephyr,gpio-keys`` + + * Modified bindings: + + * :dtcompatible:`zephyr,mmc-disk` (on sd bus): + + * new property: ``bus-width`` + + * :dtcompatible:`zephyr,bt-hci-spi` (on spi bus): + + * new property: ``controller-data-delay-us`` + + * :dtcompatible:`zephyr,sdhc-spi-slot` (on spi bus): + + * new property: ``pwr-gpios`` + + * :dtcompatible:`zephyr,memory-region`: + + * new property: ``zephyr,memory-attr`` + * property ``zephyr,memory-region-mpu`` enum value changed from ['RAM', 'RAM_NOCACHE', 'FLASH', 'PPB', 'IO', 'EXTMEM'] to None + * property ``zephyr,memory-region-mpu`` deprecation status changed from False to True + * property ``reg`` is now required + Libraries / Subsystems ********************** @@ -852,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 @@ -896,9 +2159,57 @@ Libraries / Subsystems * Added support for CAN FD. +* RTIO + + * Added atomic completion counter fixing a race caught by unit tests + * Added a :c:macro:`RTIO_SQE_NO_RESPONSE` flag for submissions when no completion notification + is needed + * Removed unused Kconfig options for different executors + +* ZBus + + * Changed channels' and observers' metadata to comply with the data/config approach. ZBus stores + immutable config in iterable sections in Flash and the mutable portion of data in the RAM. + * The relationship between channels and observers is mapped using a new entity called + observation. The observation enables us to increase the granularity of masking observation. + Developers can mask individual observations, disable the observer, or use runtime observers. + * Added API :c:macro:`ZBUS_CHAN_ADD_OBS` macro for adding post-definition static observers of a + channel. That can replace the runtime observer feature, enabling developers to add static + observers after the channel definition in different files. It increases the composability of + the system using ZBus, making post-definition channel observation rely on the stack instead of + the heap. + * Added a new type of observer called Message Subscriber. ZBus' VDED will send a copy of the + message during the publication/notification process. + * Changed the VDED delivery sequence. Check the ref:`documentation`. + * ZBus runtime observers now rely on the heap instead of a memory pool. + * Added new iterable section iterators APIs (for channels and observers) can now receive a + ``user_data`` pointer to keep context between the function calls. + * Added APIs :c:macro:`ZBUS_LISTENER_DEFINE_WITH_ENABLE` and + :c:macro:`ZBUS_SUBSCRIBER_DEFINE_WITH_ENABLE` that allows developers to define observers' + statuses (enabled/disabled) programmatically. With the API, developers can create observers + initially disabled and enable them in runtime. + +* Power management + + * Added :kconfig:option:`CONFIG_PM_NEED_ALL_DEVICES_IDLE`. When this + option is set the power management will keep the system active + if there is any device busy. + * :c:func:`pm_device_runtime_get` can be called from ISR now. + * Power states can be disabled directly in devicetree doing ``status = "disabled";`` + * Added the helper function, :c:func:`pm_device_driver_init`, for + initializing devices into a specific power state. + +* Modem modules + + * Added the :ref:`modem` subsystem. + HALs **** +* Nordic + + * Updated nrfx to version 3.1.0. + * Nuvoton * Added Nuvoton NuMaker M46x @@ -998,20 +2309,11 @@ LVGL * LVGL shell allows for monkey testing (requires :kconfig:option:`CONFIG_LV_USE_MONKEY`) and inspecting memory usage. -Storage -******* - -Trusted Firmware-M -****************** - Trusted Firmware-A ****************** * Updated to TF-A 2.9.0. -zcbor -***** - Documentation ************* @@ -1023,5 +2325,7 @@ Tests and Samples * Created common sample for file systems (`fs_sample`). It originates from sample for FAT (`fat_fs`) and supports both FAT and ext2 file systems. -Known Issues -************ +* Created the zbus confirmed channel sample to demonstrate how to implement a delivery-guaranteed + channel using subscribers. + +* Created the zbus message subscriber sample to demonstrate how to use message subscribers. diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst new file mode 100644 index 000000000000000..e317bd1049e4761 --- /dev/null +++ b/doc/releases/release-notes-3.6.rst @@ -0,0 +1,468 @@ +:orphan: + +.. _zephyr_3.6: + +Zephyr 3.6.0 (Working Draft) +############################ + +We are pleased to announce the release of Zephyr version 3.6.0. + +Major enhancements with this release include: + +An overview of the changes required or recommended when migrating your application from Zephyr +v3.5.0 to Zephyr v3.6.0 can be found in the separate :ref:`migration guide`. + +The following sections provide detailed lists of changes by component. + +Security Vulnerability Related +****************************** +The following CVEs are addressed by this release: + +More detailed information can be found in: +https://docs.zephyrproject.org/latest/security/vulnerabilities.html + +Kernel +****** + +Architectures +************* + +* ARC + +* ARM + +* ARM64 + +* RISC-V + +* Xtensa + + * Removed the unused Kconfig option ``CONFIG_XTENSA_NO_IPC``. + +* x86 + +* POSIX + +Bluetooth +********* + +* Audio + +* Direction Finding + +* Host + +* 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 + +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: + +* Added support for these X86 boards: + +* Added support for these Xtensa boards: + +* Added support for these POSIX boards: + +* Made these changes for ARC boards: + +* Made these changes for ARM boards: + +* Made these changes for ARM64 boards: + +* Made these changes for RISC-V boards: + +* Made these changes for X86 boards: + +* Made these changes for Xtensa 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: + +* Removed support for these ARM boards: + +* Removed support for these ARM64 boards: + +* Removed support for these RISC-V boards: + +* Removed support for these X86 boards: + +* Removed support for these Xtensa boards: + +* Made these changes in other boards: + +* Added support for these following shields: + +Build system and infrastructure +******************************* + +* 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. + +Drivers and Sensors +******************* + +* ADC + +* 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 + +* Display + +* DMA + +* EEPROM + +* 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. + +* Interrupt Controller + +* Input + +* PCIE + +* ACPI + +* Pin control + + * Renesas R-Car pinctrl driver now supports Gen4 SoCs + * Renamed ``CONFIG_PINCTRL_RA`` to :kconfig:option:`CONFIG_PINCTRL_RENESAS_RA` + +* PWM + +* Regulators + +* Reset + +* Retained memory + + * Retained memory driver backend for registers has been added. + + * Retained memory API status changed from experimental to unstable. + +* RTC + +* SDHC + +* Sensor + +* Serial + + * Renamed ``CONFIG_UART_RA`` to :kconfig:option:`CONFIG_UART_RENESAS_RA` + +* SPI + +* Timer + +* USB + +* WiFi + +Networking +********** + +* CoAP: + + * Emit observer/service network events using the Network Event subsystem. + + * Added new API functions: + + * :c:func:`coap_get_transmission_parameters` + * :c:func:`coap_set_transmission_parameters` + +* Connection Manager: + +* DHCP: + +* Ethernet: + +* gPTP: + +* ICMP: + +* IPv6: + +* LwM2M: + +* 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: + +* PPP: + +* 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: + +* WebSocket + +* Wi-Fi: + + +USB +*** + +Devicetree +********** + +API +=== + +Bindings +======== + +Libraries / Subsystems +********************** + +* Management + + * Fixed an issue in MCUmgr image management whereby erasing an already erased slot would return + an unknown error, it now returns success. + + * Fixed MCUmgr UDP transport structs being statically initialised, this results in about a + ~5KiB flash saving. + + * Fixed an issue in MCUmgr which would cause a user data buffer overflow if the UDP transport was + enabled on IPv4 only but IPv6 support was enabled in the kernel. + + * 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 + +* Power management + +* Random + +* 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. + +* Binary descriptors + +* POSIX API + +* LoRa/LoRaWAN + +* CAN ISO-TP + +* RTIO + +* 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 +**** + +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 +**** + +Trusted Firmware-A +****************** + +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 45bb461e518967d..e7747b5f13f51a3 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/secure-coding.rst b/doc/security/secure-coding.rst index a22859d78daaf4c..fe712eea82caa0c 100644 --- a/doc/security/secure-coding.rst +++ b/doc/security/secure-coding.rst @@ -207,7 +207,7 @@ scripting, missing authentication, and missing authorization. See the `CWE/SANS top 25`_ or `OWASP Top 10`_ for commonly used lists. .. Turn this into something specific. Can we find examples of - mistakes. Perhaps an example of things Coverity has sent us. + mistakes. Perhaps an example of things static analysis tool has sent us. .. _CWE/SANS top 25: http://cwe.mitre.org/top25/ diff --git a/doc/security/security-overview.rst b/doc/security/security-overview.rst index e02f42b5916c08b..6ed15fa55ba892c 100644 --- a/doc/security/security-overview.rst +++ b/doc/security/security-overview.rst @@ -105,8 +105,8 @@ The three major security measures currently implemented are: requires all code to be reviewed before being committed to the common repository. Furthermore, the reuse of proven building blocks such as network stacks increases the overall quality level - and guarantees stable APIs. Static code analyses are provided by - Coverity Scan. + and guarantees stable APIs. Static code analyses provide additional + quality checks. - **Execution Protection** including thread separation, stack and memory protection is currently available in the upstream @@ -180,17 +180,15 @@ the experience of the reviewer. Especially for security relevant code, concrete and detailed guidelines need to be developed and aligned with the developers (see: :ref:`secure code`). -Static code analyses are run on the Zephyr code tree on a regular basis -using the open source Coverity Scan tool. Coverity Scan now includes -complexity analysis. +Static code analyses are run on the Zephyr code tree on a regular basis, +see :ref:`static_analysis`. -Bug and issue tracking and management is performed using Jira. The term +Bug and issue tracking and management is performed using Github. The term "survivability" was coined to cover pro-active security tasks such as -security issue categorization and management. Initial effort has been -started on the definition of vulnerability categorization and mitigation -processes within Jira. +security issue categorization and management. A problem identified as +vulnerability is managed within Github security advisories. -Issues determined by Coverity should have more stringent reviews before +Issues determined by static analyses should have more stringent reviews before they are closed as non-issues (at least another person educated in security processes need to agree on non-issue before closing). diff --git a/doc/security/vulnerabilities.rst b/doc/security/vulnerabilities.rst index 669383e7d0feaad..a03b5202a028175 100644 --- a/doc/security/vulnerabilities.rst +++ b/doc/security/vulnerabilities.rst @@ -1176,7 +1176,7 @@ This has been fixed in main for v3.0.0 CVE-2022-1041 -------------- -Out-of-bound write vulnerability in the Bluetooth mesh core stack can be triggered during provisioning +Out-of-bound write vulnerability in the Bluetooth Mesh core stack can be triggered during provisioning This has been fixed in main for v3.1.0 @@ -1195,7 +1195,7 @@ This has been fixed in main for v3.1.0 CVE-2022-1042 -------------- -Out-of-bound write vulnerability in the Bluetooth mesh core stack can be triggered during provisioning +Out-of-bound write vulnerability in the Bluetooth Mesh core stack can be triggered during provisioning This has been fixed in main for v3.1.0 @@ -1501,17 +1501,52 @@ 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 ------------- -Under embargo until 2023/10/25 +Potential buffer overflow vulnerability in the Zephyr STM32 Crypto driver. + +- `Zephyr project bug tracker GHSA-rhrc-pcxp-4453 + `_ + +This has been fixed in main for v3.5.0 + +- `PR 61839 fix for main + `_ CVE-2023-5184 ------------- @@ -1547,3 +1582,33 @@ This has been fixed in main for v3.5.0 - `PR 63717 fix for 3.3 `_ + +CVE-2023-5753 +------------- + +Potential buffer overflow vulnerabilities in the Zephyr Bluetooth +subsystem source code when asserts are disabled. + +- `Zephyr project bug tracker GHSA-hmpr-px56-rvww + `_ + +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 ef44b8265afe30b..9cd6f8fe2ccd8e5 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 000000000000000..05e506bb14a9644 --- /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 f39f8335cf3cbf6..ccf5325d135aba0 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 5b702d9569802fb..c2062ec304dcd38 100644 --- a/doc/services/debugging/gdbstub.rst +++ b/doc/services/debugging/gdbstub.rst @@ -87,8 +87,9 @@ Using Serial Backend Example ******* -This is an example using ``samples/subsys/debug/gdbstub`` to demonstrate -how GDB stub works. +This is an example to demonstrate how GDB stub works. +You can also refer to ``tests/subsys/debug/gdbstub`` +for its implementation as a Twister test. #. Open two terminal windows. @@ -148,7 +149,7 @@ how GDB stub works. #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 96ba59e4a0146ca..6094e49acc1cda7 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 f868aaceb17b64d..0b21ce0771a3231 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_0.rst b/doc/services/device_mgmt/smp_groups/smp_group_0.rst index ba15ac22a1d23d8..7fb91463e336f6a 100644 --- a/doc/services/device_mgmt/smp_groups/smp_group_0.rst +++ b/doc/services/device_mgmt/smp_groups/smp_group_0.rst @@ -20,7 +20,7 @@ OS management group defines following commands: +-------------------+-----------------------------------------------+ | ``3`` | Memory pool statistics | +-------------------+-----------------------------------------------+ - | ``4`` | Date-time string; unimplemented by Zephyr | + | ``4`` | Date-time string | +-------------------+-----------------------------------------------+ | ``5`` | System reset | +-------------------+-----------------------------------------------+ diff --git a/doc/services/device_mgmt/smp_groups/smp_group_1.rst b/doc/services/device_mgmt/smp_groups/smp_group_1.rst index 819d83301497253..2a1d1f2708632b6 100644 --- a/doc/services/device_mgmt/smp_groups/smp_group_1.rst +++ b/doc/services/device_mgmt/smp_groups/smp_group_1.rst @@ -3,7 +3,7 @@ Application/software image management group ########################################### -Application/software image management management group defines following commands: +Application/software image management group defines following commands: .. table:: :align: center @@ -75,7 +75,7 @@ Get state of images request header fields: | ``0`` | ``1`` | ``0`` | +--------+--------------+----------------+ -The command sends sends empty CBOR map as data. +The command sends an empty CBOR map as data. .. _mcumgr_smp_protocol_op_1_grp_1_cmd_0: 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 a6f1ee73b7aaab2..0636e72e3f64977 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 @@ -333,7 +333,7 @@ Commit settings request header fields: | ``2`` | ``3`` | ``2`` | +--------+--------------+----------------+ -The command sends sends empty CBOR map as data. +The command sends an empty CBOR map as data. Commit settings response ======================== @@ -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 @@ -409,7 +409,7 @@ Load settings request header fields: | ``0`` | ``3`` | ``3`` | +--------+--------------+----------------+ -The command sends sends empty CBOR map as data. +The command sends an empty CBOR map as data. Load settings response ====================== @@ -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 @@ -479,7 +479,7 @@ Save settings request header fields: | ``2`` | ``3`` | ``3`` | +--------+--------------+----------------+ -The command sends sends empty CBOR map as data. +The command sends an empty CBOR map as data. Save settings response ====================== @@ -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 000000000000000..8d1f9015bcb1fc5 --- /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 44c30f32d29c97d..1ad4634d6e7bd30 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 87bebc24379f169..9e4dc3c98dc15ef 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 @@ -22,6 +23,7 @@ OS Services resource_management/index.rst mem_mgmt/index.rst modbus/index.rst + modem/index.rst notify.rst pm/index.rst portability/index.rst diff --git a/doc/services/input/diodes-cr.svg b/doc/services/input/diodes-cr.svg new file mode 100644 index 000000000000000..d374b8e0c412568 --- /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 000000000000000..91e0f9607ab4c6e --- /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 000000000000000..2910405bdd28e3c --- /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 03851d795c0db00..01d7d92b0887470 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 ************* @@ -87,3 +96,8 @@ Input Event Definitions *********************** .. doxygengroup:: input_events + +Analog Axis API Reference +************************* + +.. 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 000000000000000..ced8ad7ce78ffae --- /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 000000000000000..b79188fbe923af4 --- /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/backends/ipc_service_icbmsg.rst b/doc/services/ipc/ipc_service/backends/ipc_service_icbmsg.rst new file mode 100644 index 000000000000000..26b9006ae81d348 --- /dev/null +++ b/doc/services/ipc/ipc_service/backends/ipc_service_icbmsg.rst @@ -0,0 +1,83 @@ +.. _ipc_service_backend_icbmsg: + +ICMsg with dynamically allocated buffers backend +################################################ + +This backend is built on top of the :ref:`ipc_service_backend_icmsg`. +Data transferred over this backend travels in dynamically allocated buffers on shared memory. +The ICMsg just sends references to the buffers. +It also supports multiple endpoints. + +This architecture allows for overcoming some common problems with other backends (mostly related to multithread access and zero-copy). +This backend provides an alternative with no significant limitations. + +Overview +======== + +The shared memory is divided into two parts. +One is reserved for the ICMsg and the other contains equal-sized blocks. +The number of blocks is configured in the devicetree. + +The data sending process is following: + +* The sender allocates one or more blocks. + If there are not enough sequential blocks, it waits using the timeout provided in the parameter that also includes K_FOREVER and K_NO_WAIT. +* The allocated blocks are filled with data. + For the zero-copy case, this is done by the caller, otherwise, it is copied automatically. + During this time other threads are not blocked in any way as long as there are enough free blocks for them. + They can allocate, send data and receive data. +* A message containing the block index is sent over ICMsg to the receiver. + The size of the ICMsg queue is large enough to hold messages for all blocks, so it will never overflow. +* The receiver can hold the data as long as desired. + Again, other threads are not blocked as long as there are enough free blocks for them. +* When data is no longer needed, the backend sends a release message over ICMsg. +* When the backend receives this message, it deallocates all blocks. + It is done internally by the backend and it is invisible to the caller. + +Configuration +============= + +The backend is configured using Kconfig and devicetree. +When configuring the backend, do the following: + +* Define two memory regions and assign them to ``tx-region`` and ``rx-region`` of an instance. + Ensure that the memory regions used for data exchange are unique (not overlapping any other region) and accessible by both domains (or CPUs). +* Define the number of allocable blocks for each region with ``tx-blocks`` and ``rx-blocks``. +* Define MBOX devices for sending a signal that informs the other domain (or CPU) of the written data. + Ensure that the other domain (or CPU) can receive the signal. + +See the following configuration example for one of the instances: + +.. code-block:: devicetree + + reserved-memory { + tx: memory@20070000 { + reg = <0x20070000 0x0800>; + }; + + rx: memory@20078000 { + reg = <0x20078000 0x0800>; + }; + }; + + ipc { + ipc0: ipc0 { + compatible = "zephyr,ipc-icbmsg"; + tx-region = <&tx>; + rx-region = <&rx>; + tx-blocks = <16>; + rx-blocks = <32>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "tx", "rx"; + status = "okay"; + }; + }; + + +You must provide a similar configuration for the other side of the communication (domain or CPU). +Swap the MBOX channels, memory regions (``tx-region`` and ``rx-region``), and block count (``tx-blocks`` and ``rx-blocks``). + +Samples +======= + +* :ref:`ipc_multi_endpoint_sample` diff --git a/doc/services/ipc/ipc_service/ipc_service.rst b/doc/services/ipc/ipc_service/ipc_service.rst index 35cdfbf1ddeb557..ec8551fe9ce305c 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); @@ -185,6 +185,7 @@ backend. :maxdepth: 1 backends/ipc_service_icmsg.rst + backends/ipc_service_icbmsg.rst API Reference ************* diff --git a/doc/services/logging/index.rst b/doc/services/logging/index.rst index 8201e728b9a6e6d..84d862b9076fadd 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 @@ -142,10 +142,16 @@ packet buffer. :kconfig:option:`CONFIG_LOG_FRONTEND_ONLY`: No backends are used when messages goes to frontend. +:kconfig:option:`CONFIG_LOG_FRONTEND_OPT_API`: Optional API optimized for the most common +simple messages. + :kconfig:option:`CONFIG_LOG_CUSTOM_HEADER`: Injects an application provided header into log.h :kconfig:option:`CONFIG_LOG_TIMESTAMP_64BIT`: 64 bit timestamp. +:kconfig:option:`CONFIG_LOG_SIMPLE_MSG_OPTIMIZE`: Optimizes simple log messages for size +and performance. Option available only for 32 bit architectures. + Formatting options: :kconfig:option:`CONFIG_LOG_FUNC_NAME_PREFIX_ERR`: Prepend standard ERROR log messages @@ -236,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. @@ -299,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 @@ -350,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: @@ -378,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 | @@ -440,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 eb689c409d1dda2..d42b72ebe51bedc 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/modem/index.rst b/doc/services/modem/index.rst new file mode 100644 index 000000000000000..d831d2546263fc4 --- /dev/null +++ b/doc/services/modem/index.rst @@ -0,0 +1,53 @@ +.. _modem: + +Modem modules +############# + +This service provides modules necessary to communicate with modems. + +Modems are self-contained devices that implement the hardware and +software necessary to perform RF (Radio-Frequency) communication, +including GNSS, Cellular, WiFi etc. + +The modem modules are inter-connected dynamically using +data-in/data-out pipes making them independently testable and +highly flexible, ensuring stability and scalability. + +Modem pipe +********** + +This module is used to abstract data-in/data-out communication over +a variety of mechanisms, like UART and CMUX DLCI channels, in a +thread-safe manner. + +A modem backend will internally contain an instance of a modem_pipe +structure, alongside any buffers and additional structures required +to abstract away its underlying mechanism. + +The modem backend will return a pointer to its internal modem_pipe +structure when initialized, which will be used to interact with the +backend through the modem pipe API. + +.. doxygengroup:: modem_pipe + +Modem PPP +********* + +This module defines and binds a L2 PPP network interface, described in +:ref:`net_l2_interface`, to a modem backend. The L2 PPP interface sends +and receives network packets. These network packets have to be wrapped +in PPP frames before being transported via a modem backend. This module +performs said wrapping. + +.. doxygengroup:: modem_ppp + +Modem CMUX +********** + +This module is an implementation of CMUX following the 3GPP 27.010 +specification. CMUX is a multiplexing protocol, allowing for multiple +bi-directional streams of data, called DLCI channels. The module +attaches to a single modem backend, exposing multiple modem backends, +each representing a DLCI channel. + +.. doxygengroup:: modem_cmux diff --git a/doc/services/pm/device.rst b/doc/services/pm/device.rst index 490102e78a4cf43..3eb936942ea8e9d 100644 --- a/doc/services/pm/device.rst +++ b/doc/services/pm/device.rst @@ -146,7 +146,7 @@ support in a device driver. #define DT_DRV_COMPAT dummy_device static int dummy_driver_pm_action(const struct device *dev, - enum pm_device_action *action) + enum pm_device_action action) { switch (action) { case PM_DEVICE_ACTION_SUSPEND: diff --git a/doc/services/pm/device_runtime.rst b/doc/services/pm/device_runtime.rst index 5d9df2d8706e791..b0dd57db02e16fd 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 989fcdb4a915034..b71b793c94d558d 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 18b1a83c95f7f1d..357aa778514a254 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 392147594c83ad0..000000000000000 --- 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 c21ecba2ae507a6..000000000000000 --- 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 000000000000000..5e28fa10397d807 --- /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 000000000000000..0c38955337eee5c --- /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 000000000000000..361b0405576cd89 --- /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 000000000000000..5fc5117df4419f7 --- /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 000000000000000..c1599dd55063c0c --- /dev/null +++ b/doc/services/portability/posix/kconfig/index.rst @@ -0,0 +1,52 @@ +.. _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_APP_LINK_WITH_POSIX_SUBSYS` +* :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 000000000000000..729bd0c5803ddea --- /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(), + +.. _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(), + sched_getscheduler(), + sched_rr_get_interval(), + 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 000000000000000..4ef1f9a596dac74 --- /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 000000000000000..a62be70994ec2fd --- /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 b82972d7f687b6f..df6e75d7702c880 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 @@ -212,214 +212,6 @@ There is a small cost to each RTIO context and iodev. This cost could be weighed against using a thread for each concurrent I/O operation or custom queues and threads per peripheral. RTIO is much lower cost than that. -Examples -******** - -Examples speak loudly about the intended uses and goals of an API. So several key -examples are presented below. Some are entirely plausible today without a -big leap. Others (the sensor example) would require additional work in other -APIs outside of RTIO as a sub system and are theoretical. - -Chained Blocking Requests -========================= - -A common scenario is needing to write the register address to then read from. -This can be accomplished by chaining a write into a read operation. - -The transaction on i2c is implicit for each operation chain. - -.. code-block:: C - - RTIO_I2C_IODEV(i2c_dev, I2C_DT_SPEC_INST(n)); - RTIO_DEFINE(ez_io, 4, 4); - static uint16_t reg_addr; - static uint8_t buf[32]; - - int do_some_io(void) - { - struct rtio_sqe *write_sqe = rtio_spsc_acquire(ez_io.sq); - struct rtio_sqe *read_sqe = rtio_spsc_acquire(ez_io.sq); - - rtio_sqe_prep_write(write_sqe, i2c_dev, RTIO_PRIO_LOW, ®_addr, 2); - write_sqe->flags = RTIO_SQE_CHAINED; /* the next item in the queue will wait on this one */ - - rtio_sqe_prep_read(read_sqe, i2c_dev, RTIO_PRIO_LOW, buf, 32); - - rtio_submit(rtio_inplace_executor, &ez_io, 2); - - struct rtio_cqe *read_cqe = rtio_spsc_consume(ez_io.cq); - struct rtio_cqe *write_cqe = rtio_spsc_consume(ez_io.cq); - - if(read_cqe->result < 0) { - LOG_ERR("read failed!"); - } - - if(write_cqe->result < 0) { - LOG_ERR("write failed!"); - } - - rtio_spsc_release(ez_io.cq); - rtio_spsc_release(ez_io.cq); - } - -Non blocking device to device -============================= - -Imagine wishing to read from one device on an I2C bus and then write the same -buffer to a device on a SPI bus without blocking the thread or setting up -callbacks or other IPC notification mechanisms. - -Perhaps an I2C temperature sensor and a SPI lowrawan module. The following is a -simplified version of that potential operation chain. - -.. code-block:: C - - RTIO_I2C_IODEV(i2c_dev, I2C_DT_SPEC_INST(n)); - RTIO_SPI_IODEV(spi_dev, SPI_DT_SPEC_INST(m)); - - RTIO_DEFINE(ez_io, 4, 4); - static uint8_t buf[32]; - - int do_some_io(void) - { - uint32_t read, write; - struct rtio_sqe *read_sqe = rtio_spsc_acquire(ez_io.sq); - rtio_sqe_prep_read(read_sqe, i2c_dev, RTIO_PRIO_LOW, buf, 32); - read_sqe->flags = RTIO_SQE_CHAINED; /* the next item in the queue will wait on this one */ - - /* Safe to do as the chained operation *ensures* that if one fails all subsequent ops fail */ - struct rtio_sqe *write_sqe = rtio_spsc_acquire(ez_io.sq); - rtio_sqe_prep_write(write_sqe, spi_dev, RTIO_PRIO_LOW, buf, 32); - - /* call will return immediately without blocking if possible */ - rtio_submit(rtio_inplace_executor, &ez_io, 0); - - /* These calls might return NULL if the operations have not yet completed! */ - for (int i = 0; i < 2; i++) { - struct rtio_cqe *cqe = rtio_spsc_consume(ez_io.cq); - while(cqe == NULL) { - cqe = rtio_spsc_consume(ez_io.cq); - k_yield(); - } - if(cqe->userdata == &read && cqe->result < 0) { - LOG_ERR("read from i2c failed!"); - } - if(cqe->userdata == &write && cqe->result < 0) { - LOG_ERR("write to spi failed!"); - } - /* Must release the completion queue event after consume */ - rtio_spsc_release(ez_io.cq); - } - } - -Nested iodevs for Devices on Buses (Sensors), Theoretical -========================================================= - -Consider a device like a sensor or audio codec sitting on a bus. - -Its useful to consider that the sensor driver can use RTIO to do I/O on the SPI -bus, while also being an RTIO device itself. The sensor iodev can set aside a -small portion of the buffer in front or in back to store some metadata describing -the format of the data. This metadata could then be used in creating a sensor -readings iterator which lazily lets you map over each reading, doing -calculations such as FIR/IIR filtering, or perhaps translating the readings into -other numerical formats with useful measurement units such as SI. RTIO is a -common movement API and allows for such uses while not deciding the mechanism. - -This same sort of setup could be done for other data streams such as audio or -video. - -.. code-block:: C - - /* Note that the sensor device itself can use RTIO to get data over I2C/SPI - * potentially with DMA, but we don't need to worry about that here - * All we need to know is the device tree node_id and that it can be an iodev - */ - RTIO_SENSOR_IODEV(sensor_dev, DEVICE_DT_GET(DT_NODE(super6axis)); - - RTIO_DEFINE(ez_io, 4, 4); - - - /* The sensor driver decides the minimum buffer size for us, we decide how - * many bufs. This could be a typical multiple of a fifo packet the sensor - * produces, ICM42688 for example produces a FIFO packet of 20 bytes in - * 20bit mode at 32KHz so perhaps we'd like to get 4 buffers of 4ms of data - * each in this setup to process on. and its already been defined here for us. - */ - #include - static uint8_t bufs[4][ICM42688_RTIO_BUF_SIZE]; - - int do_some_sensors(void) { - /* Obtain a dmac executor from the DMA device */ - struct device *dma = DEVICE_DT_GET(DT_NODE(dma0)); - const struct rtio_executor *rtio_dma_exec = - dma_rtio_executor(dma); - - /* - * Set the executor for our queue context - */ - rtio_set_executor(ez_io, rtio_dma_exec); - - /* Mostly we want to feed the sensor driver enough buffers to fill while - * we wait and process! Small enough to process quickly with low latency, - * big enough to not spend all the time setting transfers up. - * - * It's assumed here that the sensor has been configured already - * and each FIFO watermark interrupt that occurs it attempts - * to pull from the queue, fill the buffer with a small metadata - * offset using its own rtio request to the SPI bus using DMA. - */ - for(int i = 0; i < 4; i++) { - struct rtio_sqe *read_sqe = rtio_spsc_acquire(ez_io.sq); - - rtio_sqe_prep_read(read_sqe, sensor_dev, RTIO_PRIO_HIGH, bufs[i], ICM42688_RTIO_BUF_SIZE); - } - struct device *sensor = DEVICE_DT_GET(DT_NODE(super6axis)); - struct sensor_reader reader; - struct sensor_channels channels[4] = { - SENSOR_TIMESTAMP_CHANNEL, - SENSOR_CHANNEL(int32_t, SENSOR_ACC_X, 0, SENSOR_RAW), - SENSOR_CHANNEL(int32_t SENSOR_ACC_Y, 0, SENSOR_RAW), - SENSOR_CHANNEL(int32_t, SENSOR_ACC_Z, 0, SENSOR_RAW), - }; - while (true) { - /* call will wait for one completion event */ - rtio_submit(ez_io, 1); - struct rtio_cqe *cqe = rtio_spsc_consume(ez_io.cq); - if(cqe->result < 0) { - LOG_ERR("read failed!"); - goto next; - } - - /* Bytes read into the buffer */ - int32_t bytes_read = cqe->result; - - /* Retrieve soon to be reusable buffer pointer from completion */ - uint8_t *buf = cqe->userdata; - - - /* Get an iterator (reader) that obtains sensor readings in integer - * form, 16 bit signed values in the native sensor reading format - */ - res = sensor_reader(sensor, buf, cqe->result, &reader, channels, - sizeof(channels)); - __ASSERT(res == 0); - while(sensor_reader_next(&reader)) { - printf("time(raw): %d, acc (x,y,z): (%d, %d, %d)\n", - channels[0].value.u32, channels[1].value.i32, - channels[2].value.i32, channels[3].value.i32); - } - - next: - /* Release completion queue event */ - rtio_spsc_release(ez_io.cq); - - /* resubmit a read request with the newly freed buffer to the sensor */ - struct rtio_sqe *read_sqe = rtio_spsc_acquire(ez_io.sq); - rtio_sqe_prep_read(read_sqe, sensor_dev, RTIO_PRIO_HIGH, buf, ICM20649_RTIO_BUF_SIZE); - } - } - API Reference ************* diff --git a/doc/services/sensing/index.rst b/doc/services/sensing/index.rst index 99fdc48d6b70743..fac113a1772484c 100644 --- a/doc/services/sensing/index.rst +++ b/doc/services/sensing/index.rst @@ -197,7 +197,7 @@ Sensor Sample Value The ``header`` defines a **base_timestamp**, and each element in the **readings[]** array defines **timestamp_delta**. - The **timestamp_delta** is is in relation to the previous **readings** (or the **base_timestamp**) + The **timestamp_delta** is in relation to the previous **readings** (or the **base_timestamp**) For example: @@ -241,7 +241,7 @@ Device Tree Configuration Sensing subsystem using device tree to configuration all sensor instances and their properties, reporting relationships. -See the example :zephyr_file:`samples/subsys/sensing/simple/boards/native_posix.overlay` +See the example :zephyr_file:`samples/subsys/sensing/simple/boards/native_sim.overlay` API Reference ************* diff --git a/doc/services/shell/index.rst b/doc/services/shell/index.rst index 6ce250f563a6457..504bef139fe019f 100644 --- a/doc/services/shell/index.rst +++ b/doc/services/shell/index.rst @@ -43,6 +43,7 @@ interaction is required. This module is a Unix-like shell with these features: The module can be connected to any transport for command input and output. At this point, the following transport layers are implemented: +* MQTT * Segger RTT * SMP * Telnet @@ -74,6 +75,29 @@ procedure: to the shell. +Telnet Backend +============== + +Enabling :kconfig:option:`CONFIG_SHELL_BACKEND_TELNET` will allow users to use telnet +as a shell backend. Connecting to it can be done using PuTTY or any ``telnet`` client. +For example: + +.. code-block:: none + + telnet + +By default the telnet client won't handle telnet commands and configuration. Although +command support can be enabled with :kconfig:option:`CONFIG_SHELL_TELNET_SUPPORT_COMMAND`. +This will give the telnet client access to a very limited set of supported commands but +still can be turned on if needed. One of the command options it supports is the ``ECHO`` +option. This will allow the client to be in character mode (character at a time), +similar to a UART backend in that regard. This will make the client send a character +as soon as it is typed having the effect of increasing the network traffic +considerably. For that cost, it will enable the line editing, +`tab completion `_, and `history `_ +features of the shell. + + Commands ******** @@ -427,6 +451,7 @@ These commands are activated by :kconfig:option:`CONFIG_SHELL_CMDS` set to ``y`` case of Bluetooth shell to limit the amount of transferred bytes. * :command:`stats` - Shows shell statistics. +.. _tab-feature: Tab Feature *********** @@ -447,6 +472,8 @@ the shell will do one of 3 possible things: :align: center :alt: Tab Feature usage example +.. _history-feature: + History Feature *************** @@ -627,28 +654,28 @@ 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 to channel ``0``. There are two options: 1. The Shell buffer can use an alternate channel, for example using -:kconfig:option:`SHELL_BACKEND_RTT_BUFFER` set to ``1``. +:kconfig:option:`CONFIG_SHELL_BACKEND_RTT_BUFFER` set to ``1``. This allows monitoring the log using `JLinkRTTViewer `_ while a script interfaces over channel 1. 2. The Log buffer can use an alternate channel, for example using -:kconfig:option:`LOG_BACKEND_RTT_BUFFER` set to ``1``. +:kconfig:option:`CONFIG_LOG_BACKEND_RTT_BUFFER` set to ``1``. This allows interactive use of the shell through JLinkRTTViewer, while the log is written to file. .. warning:: Regardless of the channel selection, the RTT log backend must be explicitly - enabled using :kconfig:option:`LOG_BACKEND_RTT` set to ``y``, because it + enabled using :kconfig:option:`CONFIG_LOG_BACKEND_RTT` set to ``y``, because it defaults to ``n`` when the Shell RTT backend is also enabled using - :kconfig:option:`SHELL_BACKEND_RTT` being set to ``y``. + :kconfig:option:`CONFIG_SHELL_BACKEND_RTT` being set to ``y``. Usage ***** diff --git a/doc/services/smf/index.rst b/doc/services/smf/index.rst index d82de94513abeab..d5f1f918471900c 100644 --- a/doc/services/smf/index.rst +++ b/doc/services/smf/index.rst @@ -3,6 +3,8 @@ State Machine Framework ####################### +.. highlight:: c + Overview ======== diff --git a/doc/services/storage/disk/nvme.rst b/doc/services/storage/disk/nvme.rst index 4f8f94818f29eb8..f9a2e935f340736 100644 --- a/doc/services/storage/disk/nvme.rst +++ b/doc/services/storage/disk/nvme.rst @@ -36,7 +36,7 @@ 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 diff --git a/doc/services/tfm/overview.rst b/doc/services/tfm/overview.rst index 7b2f8db51de66e3..ef71b53a113a075 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/tracing/index.rst b/doc/services/tracing/index.rst index 74212d2f5a17fa7..eb32d385b31c151 100644 --- a/doc/services/tracing/index.rst +++ b/doc/services/tracing/index.rst @@ -181,7 +181,7 @@ The following backends are currently supported: * UART * USB -* File (Using native posix port) +* File (Using the native port with POSIX architecture based targets) * RTT (With SystemView) * RAM (buffer to be retrieved by a debugger) @@ -191,14 +191,14 @@ Using Tracing The sample :zephyr_file:`samples/subsys/tracing` demonstrates tracing with different formats and backends. -To get started, the simplest way is to use the CTF format with the ``native_posix`` +To get started, the simplest way is to use the CTF format with the :ref:`native_sim ` port, build the sample as follows: .. zephyr-app-commands:: :tool: all :app: samples/subsys/tracing - :board: native_posix - :gen-args: -DCONF_FILE=prj_native_posix_ctf.conf + :board: native_sim + :gen-args: -DCONF_FILE=prj_native_ctf.conf :goals: build You can then run the resulting binary with the option ``-trace-file`` to generate @@ -343,14 +343,14 @@ Locking may not be needed if multiple independent channels are available. ``emit(a,thread_id); emit(b,thread_id); emit(c,thread_id);`` - The system has atomic write but one shared channel - E.g. ``native_posix`` or board with DMA. May or may not need locking. + E.g. ``native_sim`` or board with DMA. May or may not need locking. ``emit(a ## b ## c); /* Concat to buffer */`` ``lock(); emit(a); emit(b); emit(c); release(); /* No extra mem */`` - The system has atomic write and many channels - E.g. native_posix or board with multi-channel DMA. Lock-free. + E.g. native_sim or board with multi-channel DMA. Lock-free. ``emit(a ## b ## c, thread_id);`` diff --git a/doc/services/zbus/images/zbus_publishing_process_example.svg b/doc/services/zbus/images/zbus_publishing_process_example.svg index 72d7430a1637670..84fbbdd6b1facca 100644 --- a/doc/services/zbus/images/zbus_publishing_process_example.svg +++ b/doc/services/zbus/images/zbus_publishing_process_example.svg @@ -1,70 +1,71 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - + - - - - - - - - + + + + + + + + - - - - + + + + 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 000000000000000..fcd9f64c5814df8 --- /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 45e9e0ea69a892a..7d69835c95408f7 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. @@ -235,17 +233,22 @@ priority. it cannot access the channel since it is still locked. * - i - - VDED finishes the publishing by unlocking channel A. + - VDED finishes the publishing by unlocking channel A. The MS1 leaves the pending state and + starts executing. - * - j, k, l + * - j + - MS1 finishes execution. The MS2 leaves the pending state and starts executing. + + * - k + - MS2 finishes execution. The S1 leaves the pending state and starts executing. + + * - l, m, n - The S1 leaves the pending state since channel A is not locked. It gets in the CPU again and - starts executing. As it did receive a notification from channel A, it performs a channel read - (as simple as lock, memory copy, unlock), continues its execution, and goes out the CPU. - * - m - - S1 goes out of the MCU. + starts executing. As it did receive a notification from channel A, it performed a channel read + (as simple as lock, memory copy, unlock), continues its execution and goes out of the CPU. - * - n, o - - MS2 and MS1 execute and finish their workload. + * - o + - S1 finishes its workload. The figure below illustrates the actions performed during the VDED execution when T1 publishes to @@ -268,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. @@ -286,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. @@ -303,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 =========== @@ -330,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 @@ -419,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}; @@ -500,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: @@ -517,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 @@ -540,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 ================================ @@ -660,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. @@ -701,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 @@ -758,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 @@ -780,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 @@ -808,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 @@ -815,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 4ab6a73a89441b3..2332b2f5932d29a 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/ \ @@ -1368,7 +1372,7 @@ HTML_EXTRA_FILES = @ZEPHYR_BASE@/doc/_doxygen/doxygen-awesome-darkmode-tog # The default value is: AUTO_LIGHT. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_COLORSTYLE = AUTO_LIGHT +HTML_COLORSTYLE = LIGHT # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to @@ -2397,6 +2401,7 @@ PREDEFINED = __DOXYGEN__ \ __deprecated= \ __packed= \ __aligned(x)= \ + __attribute_nonnull(...)= \ "__printf_like(x, y)=" \ __attribute__(x)= \ __syscall= \ diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index e9a1603f8cc5368..6310146bb3d47e3 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -5,6 +5,7 @@ add_compile_options($) add_definitions(-D__ZEPHYR_SUPERVISOR__) +# zephyr-keep-sorted-start add_subdirectory(disk) add_subdirectory(interrupt_controller) add_subdirectory(misc) @@ -13,14 +14,15 @@ add_subdirectory(usb) add_subdirectory(usb_c) add_subdirectory_ifdef(CONFIG_ADC adc) +add_subdirectory_ifdef(CONFIG_ARM_SIP_SVC_DRIVER sip_svc) add_subdirectory_ifdef(CONFIG_AUDIO audio) +add_subdirectory_ifdef(CONFIG_AUXDISPLAY auxdisplay) add_subdirectory_ifdef(CONFIG_BBRAM bbram) -add_subdirectory_ifdef(CONFIG_XEN xen) add_subdirectory_ifdef(CONFIG_BT_DRIVERS bluetooth) add_subdirectory_ifdef(CONFIG_CACHE_MANAGEMENT cache) add_subdirectory_ifdef(CONFIG_CAN can) -add_subdirectory_ifdef(CONFIG_CLOCK_CONTROL clock_control) add_subdirectory_ifdef(CONFIG_CHARGER charger) +add_subdirectory_ifdef(CONFIG_CLOCK_CONTROL clock_control) add_subdirectory_ifdef(CONFIG_CONSOLE console) add_subdirectory_ifdef(CONFIG_COREDUMP_DEVICE coredump) add_subdirectory_ifdef(CONFIG_COUNTER counter) @@ -28,7 +30,6 @@ add_subdirectory_ifdef(CONFIG_CRYPTO crypto) add_subdirectory_ifdef(CONFIG_DAC dac) add_subdirectory_ifdef(CONFIG_DAI dai) add_subdirectory_ifdef(CONFIG_DISPLAY display) -add_subdirectory_ifdef(CONFIG_AUXDISPLAY auxdisplay) add_subdirectory_ifdef(CONFIG_DMA dma) add_subdirectory_ifdef(CONFIG_EDAC edac) add_subdirectory_ifdef(CONFIG_EEPROM eeprom) @@ -37,10 +38,11 @@ add_subdirectory_ifdef(CONFIG_ESPI espi) add_subdirectory_ifdef(CONFIG_FLASH flash) add_subdirectory_ifdef(CONFIG_FPGA fpga) add_subdirectory_ifdef(CONFIG_FUEL_GAUGE fuel_gauge) +add_subdirectory_ifdef(CONFIG_GNSS gnss) add_subdirectory_ifdef(CONFIG_GPIO gpio) add_subdirectory_ifdef(CONFIG_HWINFO hwinfo) +add_subdirectory_ifdef(CONFIG_HWSPINLOCK hwspinlock) add_subdirectory_ifdef(CONFIG_I2C i2c) -add_subdirectory_ifdef(CONFIG_SMBUS smbus) add_subdirectory_ifdef(CONFIG_I2S i2s) add_subdirectory_ifdef(CONFIG_I3C i3c) add_subdirectory_ifdef(CONFIG_IEEE802154 ieee802154) @@ -69,9 +71,11 @@ add_subdirectory_ifdef(CONFIG_PWM pwm) add_subdirectory_ifdef(CONFIG_REGULATOR regulator) add_subdirectory_ifdef(CONFIG_RESET reset) add_subdirectory_ifdef(CONFIG_RETAINED_MEM retained_mem) +add_subdirectory_ifdef(CONFIG_RTC rtc) add_subdirectory_ifdef(CONFIG_SDHC sdhc) add_subdirectory_ifdef(CONFIG_SENSOR sensor) add_subdirectory_ifdef(CONFIG_SERIAL serial) +add_subdirectory_ifdef(CONFIG_SMBUS smbus) add_subdirectory_ifdef(CONFIG_SPI spi) add_subdirectory_ifdef(CONFIG_SYSCON syscon) add_subdirectory_ifdef(CONFIG_SYS_CLOCK_EXISTS timer) @@ -80,6 +84,5 @@ add_subdirectory_ifdef(CONFIG_VIRTUALIZATION virtualization) add_subdirectory_ifdef(CONFIG_W1 w1) add_subdirectory_ifdef(CONFIG_WATCHDOG watchdog) add_subdirectory_ifdef(CONFIG_WIFI wifi) -add_subdirectory_ifdef(CONFIG_RTC rtc) -add_subdirectory_ifdef(CONFIG_ARM_SIP_SVC_DRIVER sip_svc) -add_subdirectory_ifdef(CONFIG_HWSPINLOCK hwspinlock) +add_subdirectory_ifdef(CONFIG_XEN xen) +# zephyr-keep-sorted-stop diff --git a/drivers/Kconfig b/drivers/Kconfig index f486badbb389ac8..45b03e4829c6b4f 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -5,9 +5,10 @@ menu "Device Drivers" +# zephyr-keep-sorted-start source "drivers/adc/Kconfig" -source "drivers/auxdisplay/Kconfig" source "drivers/audio/Kconfig" +source "drivers/auxdisplay/Kconfig" source "drivers/bbram/Kconfig" source "drivers/bluetooth/Kconfig" source "drivers/cache/Kconfig" @@ -31,12 +32,13 @@ source "drivers/ethernet/Kconfig" source "drivers/flash/Kconfig" source "drivers/fpga/Kconfig" source "drivers/fuel_gauge/Kconfig" +source "drivers/gnss/Kconfig" source "drivers/gpio/Kconfig" source "drivers/hwinfo/Kconfig" +source "drivers/hwspinlock/Kconfig" source "drivers/i2c/Kconfig" source "drivers/i2s/Kconfig" source "drivers/i3c/Kconfig" -source "drivers/smbus/Kconfig" source "drivers/ieee802154/Kconfig" source "drivers/input/Kconfig" source "drivers/interrupt_controller/Kconfig" @@ -70,6 +72,8 @@ source "drivers/rtc/Kconfig" source "drivers/sdhc/Kconfig" source "drivers/sensor/Kconfig" source "drivers/serial/Kconfig" +source "drivers/sip_svc/Kconfig" +source "drivers/smbus/Kconfig" source "drivers/spi/Kconfig" source "drivers/syscon/Kconfig" source "drivers/timer/Kconfig" @@ -81,7 +85,6 @@ source "drivers/w1/Kconfig" source "drivers/watchdog/Kconfig" source "drivers/wifi/Kconfig" source "drivers/xen/Kconfig" -source "drivers/sip_svc/Kconfig" -source "drivers/hwspinlock/Kconfig" +# zephyr-keep-sorted-stop endmenu diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index 4dc526298004fa9..98a65f00dfc0a01 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -47,3 +47,6 @@ zephyr_library_sources_ifdef(CONFIG_ADC_TLA2021 adc_tla2021.c) zephyr_library_sources_ifdef(CONFIG_ADC_NXP_S32_ADC_SAR adc_nxp_s32_adc_sar.c) 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 8369b5728fb1596..a004a55ae955fb2 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -17,7 +17,6 @@ if ADC config ADC_SHELL bool "ADC Shell" - default y depends on SHELL help Enable ADC Shell for testing. @@ -116,6 +115,12 @@ source "drivers/adc/Kconfig.max1125x" source "drivers/adc/Kconfig.max11102_17" +source "drivers/adc/Kconfig.ad5592" + +source "drivers/adc/Kconfig.ltc2451" + +source "drivers/adc/Kconfig.numaker" + source "drivers/adc/Kconfig.mspm0g3xxx" endif # ADC diff --git a/drivers/adc/Kconfig.ad5592 b/drivers/adc/Kconfig.ad5592 new file mode 100644 index 000000000000000..92b80f34217229a --- /dev/null +++ b/drivers/adc/Kconfig.ad5592 @@ -0,0 +1,25 @@ +# Copyright (c) 2023 Grinn +# SPDX -License-Identifier: Apache-2.0 + +config ADC_AD5592 + bool "AD5592 ADC driver" + default y + depends on DT_HAS_ADI_AD5592_ADC_ENABLED + select MFD + help + Enable the AD5592 ADC driver. + +config ADC_AD5592_ACQUISITION_THREAD_STACK_SIZE + int "Stack size for the ADC data acquisition thread" + depends on ADC_AD5592 + default 384 + help + Size of the stack used for the internal data acquisition + thread. + +config ADC_AD5592_ACQUISITION_THREAD_PRIO + int "Priority for the ADC data acquisition thread" + depends on ADC_AD5592 + default 0 + help + Priority level for the internal ADC data acquisition thread. diff --git a/drivers/adc/Kconfig.ltc2451 b/drivers/adc/Kconfig.ltc2451 new file mode 100644 index 000000000000000..8f3cb384cfbc724 --- /dev/null +++ b/drivers/adc/Kconfig.ltc2451 @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Brill Power +# SPDX-License-Identifier: Apache-2.0 + +config ADC_LTC2451 + bool "LTC2451 driver" + default y + depends on DT_HAS_LLTC_LTC2451_ENABLED + select I2C diff --git a/drivers/adc/Kconfig.npcx b/drivers/adc/Kconfig.npcx index 8f48aefe7609542..0209fd845d976ac 100644 --- a/drivers/adc/Kconfig.npcx +++ b/drivers/adc/Kconfig.npcx @@ -11,3 +11,19 @@ config ADC_NPCX This option enables the ADC driver for NPCX family of processors. Say y if you wish to use ADC channels on NPCX MCU. + +if ADC_NPCX + +config ADC_NPCX_CMP_V1 + bool "ADC comparator version 1 support" + default y if SOC_SERIES_NPCX7 || SOC_SERIES_NPCX9 + help + This option enables ADC comparator V1 support. + +config ADC_NPCX_CMP_V2 + bool "ADC comparator version 2 support" + default y if SOC_SERIES_NPCX4 + help + This option enables ADC comparator V2 support. + +endif #ADC_NPCX diff --git a/drivers/adc/Kconfig.numaker b/drivers/adc/Kconfig.numaker new file mode 100644 index 000000000000000..ea5f1288beba7e7 --- /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 f185e7664b687e6..4672a6396a4d613 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 fff48ed82af5c34..9c09b74536ea285 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 new file mode 100644 index 000000000000000..69f7b7732580ebc --- /dev/null +++ b/drivers/adc/adc_ad5592.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_ad5592_adc + +#include +#include +#include + +#include + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + +#include +LOG_MODULE_REGISTER(adc_ad5592, CONFIG_ADC_LOG_LEVEL); + +#define AD5592_ADC_RESOLUTION 12U +#define AD5592_ADC_MAX_VAL 4096 + +struct adc_ad5592_config { + const struct device *mfd_dev; +}; + +struct adc_ad5592_data { + struct adc_context ctx; + const struct device *dev; + uint8_t adc_conf; + uint16_t *buffer; + uint16_t *repeat_buffer; + uint8_t channels; + struct k_thread thread; + struct k_sem sem; + + K_KERNEL_STACK_MEMBER(stack, CONFIG_ADC_AD5592_ACQUISITION_THREAD_STACK_SIZE); +}; + +static int adc_ad5592_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + const struct adc_ad5592_config *config = dev->config; + struct adc_ad5592_data *data = dev->data; + + if (channel_cfg->channel_id >= AD5592_PIN_MAX) { + LOG_ERR("invalid channel id %d", channel_cfg->channel_id); + return -EINVAL; + } + + data->adc_conf |= BIT(channel_cfg->channel_id); + + return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_ADC_CONFIG, data->adc_conf); +} + +static int adc_ad5592_validate_buffer_size(const struct device *dev, + const struct adc_sequence *sequence) +{ + uint8_t channels; + size_t needed; + + channels = POPCOUNT(sequence->channels); + needed = channels * sizeof(uint16_t); + + if (sequence->buffer_size < needed) { + return -ENOMEM; + } + + return 0; +} + +static int adc_ad5592_start_read(const struct device *dev, const struct adc_sequence *sequence) +{ + struct adc_ad5592_data *data = dev->data; + int ret; + + if (sequence->resolution != AD5592_ADC_RESOLUTION) { + LOG_ERR("invalid resolution %d", sequence->resolution); + return -EINVAL; + } + + if (find_msb_set(sequence->channels) > AD5592_PIN_MAX) { + LOG_ERR("invalid channels in mask: 0x%08x", sequence->channels); + return -EINVAL; + } + + ret = adc_ad5592_validate_buffer_size(dev, sequence); + if (ret < 0) { + LOG_ERR("insufficient buffer size"); + return ret; + } + + data->buffer = sequence->buffer; + adc_context_start_read(&data->ctx, sequence); + + return adc_context_wait_for_completion(&data->ctx); +} + +static int adc_ad5592_read_channel(const struct device *dev, uint8_t channel, uint16_t *result) +{ + const struct adc_ad5592_config *config = dev->config; + uint16_t val; + int ret; + + ret = mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_SEQ_ADC, BIT(channel)); + if (ret < 0) { + return ret; + } + + /* + * Invalid data: + * See Figure 46. Single-Channel ADC Conversion Sequence. + * The first conversion result always returns invalid data. + */ + (void) mfd_ad5592_read_raw(config->mfd_dev, &val); + + ret = mfd_ad5592_read_raw(config->mfd_dev, &val); + if (ret < 0) { + return ret; + } + + val = sys_be16_to_cpu(val); + if (channel >= 1) { + val -= channel * AD5592_ADC_MAX_VAL; + } + + *result = val; + + return 0; +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct adc_ad5592_data *data = CONTAINER_OF(ctx, struct adc_ad5592_data, ctx); + + data->channels = ctx->sequence.channels; + data->repeat_buffer = data->buffer; + + k_sem_give(&data->sem); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat_sampling) +{ + struct adc_ad5592_data *data = CONTAINER_OF(ctx, struct adc_ad5592_data, ctx); + + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} + +static void adc_ad5592_acquisition_thread(struct adc_ad5592_data *data) +{ + uint16_t result; + uint8_t channel; + int ret; + + while (true) { + k_sem_take(&data->sem, K_FOREVER); + + while (data->channels != 0) { + channel = find_lsb_set(data->channels) - 1; + + ret = adc_ad5592_read_channel(data->dev, channel, &result); + if (ret < 0) { + LOG_ERR("failed to read channel %d (ret %d)", channel, ret); + adc_context_complete(&data->ctx, ret); + break; + } + + *data->buffer++ = result; + WRITE_BIT(data->channels, channel, 0); + } + + adc_context_on_sampling_done(&data->ctx, data->dev); + } +} + +static int adc_ad5592_read_async(const struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + struct adc_ad5592_data *data = dev->data; + int ret; + + adc_context_lock(&data->ctx, async ? true : false, async); + ret = adc_ad5592_start_read(dev, sequence); + adc_context_release(&data->ctx, ret); + + return ret; +} + +static int adc_ad5592_read(const struct device *dev, + const struct adc_sequence *sequence) +{ + return adc_ad5592_read_async(dev, sequence, NULL); +} + +static int adc_ad5592_init(const struct device *dev) +{ + const struct adc_ad5592_config *config = dev->config; + struct adc_ad5592_data *data = dev->data; + k_tid_t tid; + int ret; + + if (!device_is_ready(config->mfd_dev)) { + return -ENODEV; + } + + ret = mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_PD_REF_CTRL, AD5592_EN_REF); + if (ret < 0) { + return ret; + } + + data->dev = dev; + + k_sem_init(&data->sem, 0, 1); + adc_context_init(&data->ctx); + + tid = k_thread_create(&data->thread, data->stack, + CONFIG_ADC_AD5592_ACQUISITION_THREAD_STACK_SIZE, + (k_thread_entry_t)adc_ad5592_acquisition_thread, data, NULL, NULL, + CONFIG_ADC_AD5592_ACQUISITION_THREAD_PRIO, 0, K_NO_WAIT); + + ret = k_thread_name_set(tid, "adc_ad5592"); + if (ret < 0) { + return ret; + } + + adc_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +static const struct adc_driver_api adc_ad5592_api = { + .channel_setup = adc_ad5592_channel_setup, + .read = adc_ad5592_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = adc_ad5592_read_async, +#endif +}; + +#define ADC_AD5592_DEFINE(inst) \ + static const struct adc_ad5592_config adc_ad5592_config##inst = { \ + .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(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, \ + POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ + &adc_ad5592_api); + +DT_INST_FOREACH_STATUS_OKAY(ADC_AD5592_DEFINE) diff --git a/drivers/adc/adc_ads1119.c b/drivers/adc/adc_ads1119.c index 23f71ded75b7b46..1abdcaad7202abf 100644 --- a/drivers/adc/adc_ads1119.c +++ b/drivers/adc/adc_ads1119.c @@ -433,8 +433,12 @@ static int ads1119_read(const struct device *dev, #endif #if CONFIG_ADC_ASYNC -static void ads1119_acquisition_thread(struct device *dev) +static void ads1119_acquisition_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; while (true) { ads1119_adc_perform_read(dev); } @@ -463,10 +467,10 @@ static int ads1119_init(const struct device *dev) } #if CONFIG_ADC_ASYNC - const k_tid_t tid = + k_tid_t tid = k_thread_create(&data->thread, config->stack, CONFIG_ADC_ADS1119_ACQUISITION_THREAD_STACK_SIZE, - (k_thread_entry_t)ads1119_acquisition_thread, + ads1119_acquisition_thread, (void *)dev, NULL, NULL, CONFIG_ADC_ADS1119_ASYNC_THREAD_INIT_PRIO, 0, K_NO_WAIT); diff --git a/drivers/adc/adc_ads114s0x.c b/drivers/adc/adc_ads114s0x.c index 3b050e4e61391ab..936aecf6f1a0bd8 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; } @@ -1063,8 +1080,12 @@ static int ads114s0x_read(const struct device *dev, const struct adc_sequence *s #endif #if CONFIG_ADC_ASYNC -static void ads114s0x_acquisition_thread(struct device *dev) +static void ads114s0x_acquisition_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; while (true) { ads114s0x_adc_perform_read(dev); } @@ -1075,8 +1096,7 @@ static void ads114s0x_acquisition_thread(struct device *dev) static int ads114s0x_gpio_write_config(const struct device *dev) { struct ads114s0x_data *data = dev->data; - const struct ads114s0x_config *config = dev->config; - uint8_t register_addresses[2]; + enum ads114s0x_register register_addresses[2]; uint8_t register_values[ARRAY_SIZE(register_addresses)]; uint8_t gpio_dat = 0; uint8_t gpio_con = 0; @@ -1089,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) @@ -1111,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; } @@ -1139,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; } @@ -1162,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; } @@ -1185,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); @@ -1211,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; } @@ -1243,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; @@ -1311,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; } } @@ -1326,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; } @@ -1347,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 - const k_tid_t tid = k_thread_create( - &data->thread, config->stack, CONFIG_ADC_ADS114S0X_ACQUISITION_THREAD_STACK_SIZE, - (k_thread_entry_t)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 { @@ -1374,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; } @@ -1391,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; } @@ -1420,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 @@ -1456,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_ads1x1x.c b/drivers/adc/adc_ads1x1x.c index a448eb6bf72f301..6b2a476f24b9e06 100644 --- a/drivers/adc/adc_ads1x1x.c +++ b/drivers/adc/adc_ads1x1x.c @@ -537,8 +537,12 @@ static int ads1x1x_read(const struct device *dev, const struct adc_sequence *seq return ads1x1x_adc_read_async(dev, sequence, NULL); } -static void ads1x1x_acquisition_thread(const struct device *dev) +static void ads1x1x_acquisition_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; struct ads1x1x_data *data = dev->data; int rc; @@ -570,9 +574,9 @@ static int ads1x1x_init(const struct device *dev) return -ENODEV; } - const k_tid_t tid = + k_tid_t tid = k_thread_create(&data->thread, data->stack, K_THREAD_STACK_SIZEOF(data->stack), - (k_thread_entry_t)ads1x1x_acquisition_thread, (void *)dev, NULL, + ads1x1x_acquisition_thread, (void *)dev, NULL, NULL, CONFIG_ADC_ADS1X1X_ACQUISITION_THREAD_PRIO, 0, K_NO_WAIT); k_thread_name_set(tid, "adc_ads1x1x"); diff --git a/drivers/adc/adc_ads7052.c b/drivers/adc/adc_ads7052.c index 14b79459505098f..735c73a1bf0871f 100644 --- a/drivers/adc/adc_ads7052.c +++ b/drivers/adc/adc_ads7052.c @@ -219,8 +219,12 @@ static int ads7052_read_channel(const struct device *dev, uint8_t channel, uint1 return 0; } -static void ads7052_acquisition_thread(struct ads7052_data *data) +static void ads7052_acquisition_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct ads7052_data *data = p1; uint16_t result = 0; uint8_t channel; int err = 0; @@ -272,7 +276,7 @@ static int adc_ads7052_init(const struct device *dev) k_thread_create(&data->thread, data->stack, CONFIG_ADC_ADS7052_ACQUISITION_THREAD_STACK_SIZE, - (k_thread_entry_t)ads7052_acquisition_thread, data, NULL, NULL, + ads7052_acquisition_thread, data, NULL, NULL, CONFIG_ADC_ADS7052_ACQUISITION_THREAD_PRIO, 0, K_NO_WAIT); adc_context_unlock_unconditionally(&data->ctx); diff --git a/drivers/adc/adc_b91.c b/drivers/adc/adc_b91.c index 4b1d4abba26aa27..30e76c88a764a5c 100644 --- a/drivers/adc/adc_b91.c +++ b/drivers/adc/adc_b91.c @@ -216,8 +216,12 @@ static int adc_b91_adc_start_read(const struct device *dev, const struct adc_seq } /* Main ADC Acquisition thread */ -static void adc_b91_acquisition_thread(const struct device *dev) +static void adc_b91_acquisition_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; int16_t adc_code; struct b91_adc_data *data = dev->data; @@ -260,7 +264,7 @@ static int adc_b91_init(const struct device *dev) k_thread_create(&data->thread, data->stack, CONFIG_ADC_B91_ACQUISITION_THREAD_STACK_SIZE, - (k_thread_entry_t)adc_b91_acquisition_thread, + adc_b91_acquisition_thread, (void *)dev, NULL, NULL, CONFIG_ADC_B91_ACQUISITION_THREAD_PRIO, 0, K_NO_WAIT); diff --git a/drivers/adc/adc_emul.c b/drivers/adc/adc_emul.c index 4ef7a869390b41e..20b9764fd5fbb0f 100644 --- a/drivers/adc/adc_emul.c +++ b/drivers/adc/adc_emul.c @@ -470,8 +470,12 @@ static int adc_emul_get_chan_value(struct adc_emul_data *data, * * @return This thread should not end */ -static void adc_emul_acquisition_thread(struct adc_emul_data *data) +static void adc_emul_acquisition_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct adc_emul_data *data = p1; int err; while (true) { @@ -533,7 +537,7 @@ static int adc_emul_init(const struct device *dev) k_thread_create(&data->thread, data->stack, CONFIG_ADC_EMUL_ACQUISITION_THREAD_STACK_SIZE, - (k_thread_entry_t)adc_emul_acquisition_thread, + adc_emul_acquisition_thread, data, NULL, NULL, CONFIG_ADC_EMUL_ACQUISITION_THREAD_PRIO, 0, K_NO_WAIT); diff --git a/drivers/adc/adc_handlers.c b/drivers/adc/adc_handlers.c index cf6319a6264aa9f..2b00c2d95a9fcd6 100644 --- a/drivers/adc/adc_handlers.c +++ b/drivers/adc/adc_handlers.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include static inline int z_vrfy_adc_channel_setup(const struct device *dev, @@ -13,8 +13,8 @@ static inline int z_vrfy_adc_channel_setup(const struct device *dev, { struct adc_channel_cfg channel_cfg; - Z_OOPS(Z_SYSCALL_DRIVER_ADC(dev, channel_setup)); - Z_OOPS(z_user_from_copy(&channel_cfg, + K_OOPS(K_SYSCALL_DRIVER_ADC(dev, channel_setup)); + K_OOPS(k_usermode_from_copy(&channel_cfg, (struct adc_channel_cfg *)user_channel_cfg, sizeof(struct adc_channel_cfg))); @@ -27,13 +27,13 @@ static bool copy_sequence(struct adc_sequence *dst, struct adc_sequence_options *options, struct adc_sequence *src) { - if (z_user_from_copy(dst, src, sizeof(struct adc_sequence)) != 0) { + if (k_usermode_from_copy(dst, src, sizeof(struct adc_sequence)) != 0) { printk("couldn't copy adc_sequence struct\n"); return false; } if (dst->options) { - if (z_user_from_copy(options, dst->options, + if (k_usermode_from_copy(options, dst->options, sizeof(struct adc_sequence_options)) != 0) { printk("couldn't copy adc_options struct\n"); return false; @@ -41,7 +41,7 @@ static bool copy_sequence(struct adc_sequence *dst, dst->options = options; } - if (Z_SYSCALL_MEMORY_WRITE(dst->buffer, dst->buffer_size) != 0) { + if (K_SYSCALL_MEMORY_WRITE(dst->buffer, dst->buffer_size) != 0) { printk("no access to buffer memory\n"); return false; } @@ -55,12 +55,12 @@ static inline int z_vrfy_adc_read(const struct device *dev, struct adc_sequence sequence; struct adc_sequence_options options; - Z_OOPS(Z_SYSCALL_DRIVER_ADC(dev, read)); - Z_OOPS(Z_SYSCALL_VERIFY_MSG(copy_sequence(&sequence, &options, + K_OOPS(K_SYSCALL_DRIVER_ADC(dev, read)); + K_OOPS(K_SYSCALL_VERIFY_MSG(copy_sequence(&sequence, &options, (struct adc_sequence *)user_sequence), "invalid ADC sequence")); if (sequence.options != NULL) { - Z_OOPS(Z_SYSCALL_VERIFY_MSG(sequence.options->callback == NULL, + K_OOPS(K_SYSCALL_VERIFY_MSG(sequence.options->callback == NULL, "ADC sequence callbacks forbidden from user mode")); } @@ -76,15 +76,15 @@ static inline int z_vrfy_adc_read_async(const struct device *dev, struct adc_sequence sequence; struct adc_sequence_options options; - Z_OOPS(Z_SYSCALL_DRIVER_ADC(dev, read_async)); - Z_OOPS(Z_SYSCALL_VERIFY_MSG(copy_sequence(&sequence, &options, + K_OOPS(K_SYSCALL_DRIVER_ADC(dev, read_async)); + K_OOPS(K_SYSCALL_VERIFY_MSG(copy_sequence(&sequence, &options, (struct adc_sequence *)user_sequence), "invalid ADC sequence")); if (sequence.options != NULL) { - Z_OOPS(Z_SYSCALL_VERIFY_MSG(sequence.options->callback == NULL, + K_OOPS(K_SYSCALL_VERIFY_MSG(sequence.options->callback == NULL, "ADC sequence callbacks forbidden from user mode")); } - Z_OOPS(Z_SYSCALL_OBJ(async, K_OBJ_POLL_SIGNAL)); + K_OOPS(K_SYSCALL_OBJ(async, K_OBJ_POLL_SIGNAL)); return z_impl_adc_read_async((const struct device *)dev, &sequence, (struct k_poll_signal *)async); diff --git a/drivers/adc/adc_lmp90xxx.c b/drivers/adc/adc_lmp90xxx.c index 7ecb2c6cfa6f0f7..2dc23a792f30918 100644 --- a/drivers/adc/adc_lmp90xxx.c +++ b/drivers/adc/adc_lmp90xxx.c @@ -650,8 +650,12 @@ static int lmp90xxx_adc_read_channel(const struct device *dev, return 0; } -static void lmp90xxx_acquisition_thread(struct lmp90xxx_data *data) +static void lmp90xxx_acquisition_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct lmp90xxx_data *data = p1; uint8_t bgcalcn = LMP90XXX_BGCALN(0x3); /* Default to BgCalMode3 */ int32_t result = 0; uint8_t channel; @@ -1014,7 +1018,7 @@ static int lmp90xxx_init(const struct device *dev) tid = k_thread_create(&data->thread, data->stack, CONFIG_ADC_LMP90XXX_ACQUISITION_THREAD_STACK_SIZE, - (k_thread_entry_t)lmp90xxx_acquisition_thread, + lmp90xxx_acquisition_thread, data, NULL, NULL, CONFIG_ADC_LMP90XXX_ACQUISITION_THREAD_PRIO, 0, K_NO_WAIT); diff --git a/drivers/adc/adc_ltc2451.c b/drivers/adc/adc_ltc2451.c new file mode 100644 index 000000000000000..95b86f30d68a56a --- /dev/null +++ b/drivers/adc/adc_ltc2451.c @@ -0,0 +1,105 @@ +/* LLTC LTC2451 ADC + * + * Copyright (c) 2023 Brill Power Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(ltc2451, CONFIG_ADC_LOG_LEVEL); + +#define DT_DRV_COMPAT lltc_ltc2451 + +struct ltc2451_config { + struct i2c_dt_spec i2c; + uint8_t conversion_speed; +}; + +static int ltc2451_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + ARG_UNUSED(dev); + + if (channel_cfg->channel_id != 0) { + LOG_ERR("Invalid channel id '%d'", channel_cfg->channel_id); + return -EINVAL; + } + + return 0; +} + +static int ltc2451_set_conversion_speed(const struct device *dev, uint8_t conversion_speed) +{ + const struct ltc2451_config *config = dev->config; + uint8_t wr_buf[1]; + int err; + + if (conversion_speed == 60) { + wr_buf[0] = 0; + } else if (conversion_speed == 30) { + wr_buf[0] = 1; + } else { + LOG_ERR("Invalid conversion speed selected"); + return -EINVAL; + } + + err = i2c_write_dt(&config->i2c, wr_buf, sizeof(wr_buf)); + + if (err != 0) { + LOG_ERR("LTC write failed (err %d)", err); + } + + return err; +} + +static int ltc2451_read_latest_conversion(const struct device *dev, + const struct adc_sequence *sequence) +{ + const struct ltc2451_config *config = dev->config; + uint8_t rd_buf[2]; + uint16_t *value_buf; + int err = i2c_read_dt(&config->i2c, rd_buf, sizeof(rd_buf)); + + if (err == 0) { + value_buf = (uint16_t *)sequence->buffer; + value_buf[0] = sys_get_be16(rd_buf); + } else { + LOG_ERR("LTC read failed (err %d)", err); + } + + return err; +} + +static int ltc2451_init(const struct device *dev) +{ + const struct ltc2451_config *config = dev->config; + + if (!device_is_ready(config->i2c.bus)) { + LOG_ERR("I2C device not ready"); + return -ENODEV; + } + + return ltc2451_set_conversion_speed(dev, config->conversion_speed); +} + +static const struct adc_driver_api ltc2451_api = { + .channel_setup = ltc2451_channel_setup, + .read = ltc2451_read_latest_conversion, +}; + +#define LTC2451_DEFINE(index) \ + static const struct ltc2451_config ltc2451_cfg_##index = { \ + .i2c = I2C_DT_SPEC_INST_GET(index), \ + .conversion_speed = DT_INST_PROP(index, conversion_speed), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(index, <c2451_init, NULL, NULL, \ + <c2451_cfg_##index, POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, \ + <c2451_api); + +DT_INST_FOREACH_STATUS_OKAY(LTC2451_DEFINE) diff --git a/drivers/adc/adc_max11102_17.c b/drivers/adc/adc_max11102_17.c index fa87ce7c55eb224..5443de03753573d 100644 --- a/drivers/adc/adc_max11102_17.c +++ b/drivers/adc/adc_max11102_17.c @@ -315,8 +315,12 @@ static int max11102_17_read(const struct device *dev, const struct adc_sequence #endif #if CONFIG_ADC_ASYNC -static void max11102_17_acquisition_thread(const struct device *dev) +static void max11102_17_acquisition_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; while (true) { max11102_17_adc_perform_read(dev); } @@ -366,9 +370,9 @@ static int max11102_17_init(const struct device *dev) data->current_channel_id = 0; #if CONFIG_ADC_ASYNC - const k_tid_t tid = k_thread_create( + k_tid_t tid = k_thread_create( &data->thread, data->stack, CONFIG_ADC_MAX11102_17_ACQUISITION_THREAD_STACK_SIZE, - (k_thread_entry_t)max11102_17_acquisition_thread, (void *)dev, NULL, NULL, + max11102_17_acquisition_thread, (void *)dev, NULL, NULL, CONFIG_ADC_MAX11102_17_ACQUISITION_THREAD_INIT_PRIO, 0, K_NO_WAIT); k_thread_name_set(tid, "adc_max11102_17"); #endif diff --git a/drivers/adc/adc_max1125x.c b/drivers/adc/adc_max1125x.c index 7a9bf0ed026a59a..a6e005defff9cf4 100644 --- a/drivers/adc/adc_max1125x.c +++ b/drivers/adc/adc_max1125x.c @@ -690,8 +690,12 @@ static int max1125x_read(const struct device *dev, const struct adc_sequence *se return max1125x_adc_read_async(dev, sequence, NULL); } -static void max1125x_acquisition_thread(const struct device *dev) +static void max1125x_acquisition_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; struct max1125x_data *data = dev->data; int rc; @@ -750,9 +754,9 @@ static int max1125x_init(const struct device *dev) return -EIO; } - const k_tid_t tid = k_thread_create( + k_tid_t tid = k_thread_create( &data->thread, data->stack, K_THREAD_STACK_SIZEOF(data->stack), - (k_thread_entry_t)max1125x_acquisition_thread, (void *)dev, NULL, NULL, + max1125x_acquisition_thread, (void *)dev, NULL, NULL, CONFIG_ADC_MAX1125X_ACQUISITION_THREAD_PRIORITY, 0, K_NO_WAIT); k_thread_name_set(tid, "adc_max1125x"); diff --git a/drivers/adc/adc_mcp320x.c b/drivers/adc/adc_mcp320x.c index b5ff94a105fec3c..dff4e579c5fc748 100644 --- a/drivers/adc/adc_mcp320x.c +++ b/drivers/adc/adc_mcp320x.c @@ -232,8 +232,12 @@ static int mcp320x_read_channel(const struct device *dev, uint8_t channel, return 0; } -static void mcp320x_acquisition_thread(struct mcp320x_data *data) +static void mcp320x_acquisition_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct mcp320x_data *data = p1; uint16_t result = 0; uint8_t channel; int err; @@ -281,7 +285,7 @@ static int mcp320x_init(const struct device *dev) k_thread_create(&data->thread, data->stack, CONFIG_ADC_MCP320X_ACQUISITION_THREAD_STACK_SIZE, - (k_thread_entry_t)mcp320x_acquisition_thread, + mcp320x_acquisition_thread, data, NULL, NULL, CONFIG_ADC_MCP320X_ACQUISITION_THREAD_PRIO, 0, K_NO_WAIT); diff --git a/drivers/adc/adc_npcx.c b/drivers/adc/adc_npcx.c index 6a5a1ad802afc99..ae1cf65ffbb2db2 100644 --- a/drivers/adc/adc_npcx.c +++ b/drivers/adc/adc_npcx.c @@ -168,16 +168,16 @@ static inline void adc_npcx_enable_threshold_detect(const struct device *dev, ui const struct adc_npcx_config *config = dev->config; if (enable) { -#ifdef CONFIG_SOC_SERIES_NPCX4 +#ifdef CONFIG_ADC_NPCX_CMP_V2 THEN(config->base) |= BIT(th_sel); -#else +#else /* CONFIG_ADC_NPCX_CMP_V1 */ THRCTL(config->base, th_sel) |= BIT(NPCX_THRCTL_THEN); #endif } else { -#ifdef CONFIG_SOC_SERIES_NPCX4 +#ifdef CONFIG_ADC_NPCX_CMP_V2 THEN(config->base) &= ~BIT(th_sel); -#else +#else /* CONFIG_ADC_NPCX_CMP_V1 */ THRCTL(config->base, th_sel) &= ~BIT(NPCX_THRCTL_THEN); #endif } diff --git a/drivers/adc/adc_nrfx_saadc.c b/drivers/adc/adc_nrfx_saadc.c index 72a20f47fc9f015..6d1973ca0aae9c2 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 000000000000000..4fae17f422d479d --- /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 0c7f525ec0c20c4..76c3a52a15b149e 100644 --- a/drivers/adc/adc_rpi_pico.c +++ b/drivers/adc/adc_rpi_pico.c @@ -8,6 +8,9 @@ #define DT_DRV_COMPAT raspberrypi_pico_adc #include +#include +#include +#include #include #include @@ -31,8 +34,16 @@ LOG_MODULE_REGISTER(adc_rpi, CONFIG_ADC_LOG_LEVEL); struct adc_rpi_config { /** Number of supported channels */ uint8_t num_channels; + /** pinctrl configs */ + 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; }; /** @@ -289,6 +300,22 @@ static int adc_rpi_init(const struct device *dev) { const struct adc_rpi_config *config = dev->config; struct adc_rpi_data *data = dev->data; + int ret; + + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + 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(); @@ -323,29 +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) \ - 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, \ - 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 2069b97b5ece31d..bc002d769725cfb 100644 --- a/drivers/adc/adc_shell.c +++ b/drivers/adc/adc_shell.c @@ -74,36 +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) + /* 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 53562734bd0dc39..0dcb8a77c78a7d7 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #if defined(CONFIG_SOC_SERIES_STM32U5X) #include @@ -188,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; @@ -210,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) { @@ -256,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); @@ -341,6 +358,52 @@ static int check_buffer(const struct adc_sequence *sequence, return 0; } +/* + * Enable ADC peripheral, and wait until ready if required by SOC. + */ +static int adc_stm32_enable(ADC_TypeDef *adc) +{ + if (LL_ADC_IsEnabled(adc) == 1UL) { + return 0; + } + +#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ + !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) + LL_ADC_ClearFlag_ADRDY(adc); + LL_ADC_Enable(adc); + + /* + * Enabling ADC modules in many series may fail if they are + * still not stabilized, this will wait for a short time (about 1ms) + * to ensure ADC modules are properly enabled. + */ + uint32_t count_timeout = 0; + + while (LL_ADC_IsActiveFlag_ADRDY(adc) == 0) { +#ifdef CONFIG_SOC_SERIES_STM32F0X + /* For F0, continue to write ADEN=1 until ADRDY=1 */ + if (LL_ADC_IsEnabled(adc) == 0UL) { + LL_ADC_Enable(adc); + } +#endif /* CONFIG_SOC_SERIES_STM32F0X */ + count_timeout++; + k_busy_wait(100); + if (count_timeout >= 10) { + return -ETIMEDOUT; + } + } +#else + /* + * On STM32F1, F2, F37x, F4, F7 and L1, do not re-enable the ADC. + * On F1 and F37x if ADON holds 1 (LL_ADC_IsEnabled is true) and 1 is + * written, then conversion starts. That's not what is expected. + */ + LL_ADC_Enable(adc); +#endif + + return 0; +} + static void adc_stm32_start_conversion(const struct device *dev) { const struct adc_stm32_cfg *config = dev->config; @@ -356,6 +419,53 @@ static void adc_stm32_start_conversion(const struct device *dev) #endif } +/* + * Disable ADC peripheral, and wait until it is disabled + */ +static void adc_stm32_disable(ADC_TypeDef *adc) +{ + if (LL_ADC_IsEnabled(adc) != 1UL) { + return; + } + + /* Stop ongoing conversion if any + * Software must poll ADSTART (or JADSTART) until the bit is reset before assuming + * the ADC is completely stopped. + */ + +#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ + !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) + if (LL_ADC_REG_IsConversionOngoing(adc)) { + LL_ADC_REG_StopConversion(adc); + while (LL_ADC_REG_IsConversionOngoing(adc)) { + } + } +#endif + +#if !defined(CONFIG_SOC_SERIES_STM32C0X) && \ + !defined(CONFIG_SOC_SERIES_STM32F0X) && \ + !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ + !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) && \ + !defined(CONFIG_SOC_SERIES_STM32G0X) && \ + !defined(CONFIG_SOC_SERIES_STM32L0X) && \ + !defined(CONFIG_SOC_SERIES_STM32WBAX) && \ + !defined(CONFIG_SOC_SERIES_STM32WLX) + if (LL_ADC_INJ_IsConversionOngoing(adc)) { + LL_ADC_INJ_StopConversion(adc); + while (LL_ADC_INJ_IsConversionOngoing(adc)) { + } + } +#endif + + LL_ADC_Disable(adc); + + /* Wait ADC is fully disabled so that we don't leave the driver into intermediate state + * which could prevent enabling the peripheral + */ + while (LL_ADC_IsEnabled(adc) == 1UL) { + } +} + #if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) #define HAS_CALIBRATION @@ -369,7 +479,7 @@ static void adc_stm32_start_conversion(const struct device *dev) #define ADC_DELAY_CALIB_ADC_CYCLES LL_ADC_DELAY_DISABLE_CALIB_ADC_CYCLES #endif -static void adc_stm32_calib_delay(const struct device *dev) +static void adc_stm32_calibration_delay(const struct device *dev) { /* * Calibration of F1 and F3 (ADC1_V2_5) must start two cycles after ADON @@ -397,7 +507,7 @@ static void adc_stm32_calib_delay(const struct device *dev) } } -static void adc_stm32_calib(const struct device *dev) +static void adc_stm32_calibration_start(const struct device *dev) { const struct adc_stm32_cfg *config = (const struct adc_stm32_cfg *)dev->config; @@ -429,54 +539,61 @@ static void adc_stm32_calib(const struct device *dev) while (LL_ADC_IsCalibrationOnGoing(adc)) { } } -#endif -/* - * Disable ADC peripheral, and wait until it is disabled - */ -static void adc_stm32_disable(ADC_TypeDef *adc) +static int adc_stm32_calibrate(const struct device *dev) { - if (LL_ADC_IsEnabled(adc) != 1UL) { - return; - } - - /* Stop ongoing conversion if any - * Software must poll ADSTART (or JADSTART) until the bit is reset before assuming - * the ADC is completely stopped. - */ + const struct adc_stm32_cfg *config = + (const struct adc_stm32_cfg *)dev->config; + ADC_TypeDef *adc = config->base; + int err; -#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ - !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) - if (LL_ADC_REG_IsConversionOngoing(adc)) { - LL_ADC_REG_StopConversion(adc); - while (LL_ADC_REG_IsConversionOngoing(adc)) { - } - } -#endif +#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) + adc_stm32_disable(adc); + adc_stm32_calibration_start(dev); + adc_stm32_calibration_delay(dev); +#endif /* !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */ -#if !defined(CONFIG_SOC_SERIES_STM32C0X) && \ - !defined(CONFIG_SOC_SERIES_STM32F0X) && \ - !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ - !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) && \ - !defined(CONFIG_SOC_SERIES_STM32G0X) && \ - !defined(CONFIG_SOC_SERIES_STM32L0X) && \ - !defined(CONFIG_SOC_SERIES_STM32WBAX) && \ - !defined(CONFIG_SOC_SERIES_STM32WLX) - if (LL_ADC_INJ_IsConversionOngoing(adc)) { - LL_ADC_INJ_StopConversion(adc); - while (LL_ADC_INJ_IsConversionOngoing(adc)) { - } + err = adc_stm32_enable(adc); + if (err < 0) { + return err; } -#endif - LL_ADC_Disable(adc); +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) + adc_stm32_calibration_delay(dev); + adc_stm32_calibration_start(dev); +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */ - /* Wait ADC is fully disabled so that we don't leave the driver into intermediate state - * which could prevent enabling the peripheral +#if defined(CONFIG_SOC_SERIES_STM32H7X) && \ + defined(CONFIG_CPU_CORTEX_M7) + /* + * To ensure linearity the factory calibration values + * should be loaded on initialization. */ - while (LL_ADC_IsEnabled(adc) == 1UL) { + uint32_t channel_offset = 0U; + uint32_t linear_calib_buffer = 0U; + + if (adc == ADC1) { + channel_offset = 0UL; + } else if (adc == ADC2) { + channel_offset = 8UL; + } else /*Case ADC3*/ { + channel_offset = 16UL; + } + /* Read factory calibration factors */ + for (uint32_t count = 0UL; count < ADC_LINEAR_CALIB_REG_COUNT; count++) { + linear_calib_buffer = *(uint32_t *)( + ADC_LINEAR_CALIB_REG_1_ADDR + channel_offset + count + ); + LL_ADC_SetCalibrationLinearFactor( + adc, LL_ADC_CALIB_LINEARITY_WORD1 << count, + linear_calib_buffer + ); } +#endif /* CONFIG_SOC_SERIES_STM32H7X */ + + return 0; } +#endif /* !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) */ #if !defined(CONFIG_SOC_SERIES_STM32F0X) && \ !defined(CONFIG_SOC_SERIES_STM32F1X) && \ @@ -559,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 */ @@ -609,52 +726,6 @@ static int adc_stm32_oversampling(ADC_TypeDef *adc, uint8_t ratio) } #endif /* CONFIG_SOC_SERIES_STM32xxx */ -/* - * Enable ADC peripheral, and wait until ready if required by SOC. - */ -static int adc_stm32_enable(ADC_TypeDef *adc) -{ - if (LL_ADC_IsEnabled(adc) == 1UL) { - return 0; - } - -#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ - !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) - LL_ADC_ClearFlag_ADRDY(adc); - LL_ADC_Enable(adc); - - /* - * Enabling ADC modules in many series may fail if they are - * still not stabilized, this will wait for a short time (about 1ms) - * to ensure ADC modules are properly enabled. - */ - uint32_t count_timeout = 0; - - while (LL_ADC_IsActiveFlag_ADRDY(adc) == 0) { -#ifdef CONFIG_SOC_SERIES_STM32F0X - /* For F0, continue to write ADEN=1 until ADRDY=1 */ - if (LL_ADC_IsEnabled(adc) == 0UL) { - LL_ADC_Enable(adc); - } -#endif /* CONFIG_SOC_SERIES_STM32F0X */ - count_timeout++; - k_busy_wait(100); - if (count_timeout >= 10) { - return -ETIMEDOUT; - } - } -#else - /* - * On STM32F1, F2, F37x, F4, F7 and L1, do not re-enable the ADC. - * On F1 and F37x if ADON holds 1 (LL_ADC_IsEnabled is true) and 1 is - * written, then conversion starts. That's not what is expected. - */ - LL_ADC_Enable(adc); -#endif - - return 0; -} - #ifdef CONFIG_ADC_STM32_DMA static void dma_callback(const struct device *dev, void *user_data, uint32_t channel, int status) @@ -687,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; @@ -899,12 +976,8 @@ static int start_read(const struct device *dev, #endif /* HAS_OVERSAMPLING */ if (sequence->calibrate) { -#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ - !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) - - /* we cannot calibrate the ADC while the ADC is enabled */ - adc_stm32_disable(adc); - adc_stm32_calib(dev); +#if defined(HAS_CALIBRATION) + adc_stm32_calibrate(dev); #else LOG_ERR("Calibration not supported"); return -ENOTSUP; @@ -991,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); + } } } @@ -1007,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 */ } @@ -1029,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); @@ -1044,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); @@ -1051,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; @@ -1071,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_* @@ -1091,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: @@ -1122,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; @@ -1163,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; } @@ -1236,6 +1337,8 @@ static int adc_stm32_init(const struct device *dev) ADC_TypeDef *adc = (ADC_TypeDef *)config->base; int err; + ARG_UNUSED(adc); /* Necessary to avoid warnings on some series */ + LOG_DBG("Initializing %s", dev->name); if (!device_is_ready(clk)) { @@ -1249,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); @@ -1264,6 +1368,7 @@ static int adc_stm32_init(const struct device *dev) LOG_ERR("ADC pinctrl setup failed (%d)", err); return err; } + #if defined(CONFIG_SOC_SERIES_STM32U5X) /* Enable the independent analog supply */ LL_PWR_EnableVDDA(); @@ -1289,12 +1394,9 @@ static int adc_stm32_init(const struct device *dev) * mode, and restore its calibration parameters if there are some * previously stored calibration parameters. */ - LL_ADC_DisableDeepPowerDown(adc); -#elif defined(CONFIG_SOC_SERIES_STM32WLX) - /* The ADC clock must be disabled by clock gating during CPU1 sleep/stop */ - LL_APB2_GRP1_DisableClockSleep(LL_APB2_GRP1_PERIPH_ADC); #endif + /* * Many ADC modules need some time to be stabilized before performing * any enable or calibration actions. @@ -1306,56 +1408,99 @@ static int adc_stm32_init(const struct device *dev) k_busy_wait(LL_ADC_DELAY_INTERNAL_REGUL_STAB_US); #endif -#if defined(HAS_CALIBRATION) && !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) - adc_stm32_disable(adc); - adc_stm32_calib(dev); - adc_stm32_calib_delay(dev); -#endif /* HAS_CALIBRATION && !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */ - - err = adc_stm32_enable(adc); - if (err < 0) { - return err; + if (config->irq_cfg_func) { + config->irq_cfg_func(); } - config->irq_cfg_func(); - -#if defined(HAS_CALIBRATION) && DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) - adc_stm32_calib_delay(dev); - adc_stm32_calib(dev); +#if defined(HAS_CALIBRATION) + adc_stm32_calibrate(dev); LL_ADC_REG_SetTriggerSource(adc, LL_ADC_REG_TRIG_SOFTWARE); -#endif /* HAS_CALIBRATION && DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */ +#endif /* HAS_CALIBRATION */ -#ifdef CONFIG_SOC_SERIES_STM32H7X + adc_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +#ifdef CONFIG_PM_DEVICE +static int adc_stm32_suspend_setup(const struct device *dev) +{ + const struct adc_stm32_cfg *config = dev->config; + ADC_TypeDef *adc = (ADC_TypeDef *)config->base; + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + int err; + + /* Disable ADC */ + adc_stm32_disable(adc); + +#if !defined(CONFIG_SOC_SERIES_STM32F0X) && \ + !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) && \ + !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) + /* Disable ADC internal voltage regulator */ + LL_ADC_DisableInternalRegulator(adc); + while (LL_ADC_IsInternalRegulatorEnabled(adc) == 1U) { + } +#endif + +#if defined(CONFIG_SOC_SERIES_STM32L4X) || \ + defined(CONFIG_SOC_SERIES_STM32L5X) || \ + defined(CONFIG_SOC_SERIES_STM32WBX) || \ + defined(CONFIG_SOC_SERIES_STM32G4X) || \ + defined(CONFIG_SOC_SERIES_STM32H5X) || \ + defined(CONFIG_SOC_SERIES_STM32H7X) || \ + defined(CONFIG_SOC_SERIES_STM32U5X) /* - * To ensure linearity the factory calibration values - * should be loaded on initialization. + * L4, WB, G4, H5, H7 and U5 series STM32 needs to be put into + * deep sleep mode. */ - uint32_t channel_offset = 0U; - uint32_t linear_calib_buffer = 0U; - if (adc == ADC1) { - channel_offset = 0UL; - } else if (adc == ADC2) { - channel_offset = 8UL; - } else /*Case ADC3*/ { - channel_offset = 16UL; + LL_ADC_EnableDeepPowerDown(adc); +#endif + +#if defined(CONFIG_SOC_SERIES_STM32U5X) + /* Disable the independent analog supply */ + LL_PWR_DisableVDDA(); +#endif /* CONFIG_SOC_SERIES_STM32U5X */ + + /* Stop device clock. Note: fixed clocks are not handled yet. */ + err = clock_control_off(clk, (clock_control_subsys_t)&config->pclken[0]); + if (err != 0) { + LOG_ERR("Could not disable ADC clock"); + return err; } - /* Read factory calibration factors */ - for (uint32_t count = 0UL; count < ADC_LINEAR_CALIB_REG_COUNT; count++) { - linear_calib_buffer = *(uint32_t *)( - ADC_LINEAR_CALIB_REG_1_ADDR + channel_offset + count - ); - LL_ADC_SetCalibrationLinearFactor( - adc, LL_ADC_CALIB_LINEARITY_WORD1 << count, - linear_calib_buffer - ); + + /* Move pins to sleep state */ + err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP); + if ((err < 0) && (err != -ENOENT)) { + /* + * If returning -ENOENT, no pins where defined for sleep mode : + * Do not output on console (might sleep already) when going to sleep, + * "ADC pinctrl sleep state not available" + * and don't block PM suspend. + * Else return the error. + */ + return err; } -#endif - adc_context_unlock_unconditionally(&data->ctx); return 0; } +static int adc_stm32_pm_action(const struct device *dev, + enum pm_device_action action) +{ + switch (action) { + case PM_DEVICE_ACTION_RESUME: + return adc_stm32_init(dev); + case PM_DEVICE_ACTION_SUSPEND: + return adc_stm32_suspend_setup(dev); + default: + return -ENOTSUP; + } + + return 0; +} +#endif /* CONFIG_PM_DEVICE */ + static const struct adc_driver_api api_stm32_driver_api = { .channel_setup = adc_stm32_channel_setup, .read = adc_stm32_read, @@ -1388,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 +#if defined(CONFIG_ADC_STM32_DMA) -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); -} - -#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,)) -#endif /* CONFIG_ADC_STM32_DMA && CONFIG_ADC_STM32_SHARED_IRQS */ +/* + * 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)) + +/* + * 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); \ \ @@ -1515,11 +1697,13 @@ 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); \ + \ DEVICE_DT_INST_DEFINE(index, \ - &adc_stm32_init, NULL, \ + &adc_stm32_init, PM_DEVICE_DT_INST_GET(index), \ &adc_stm32_data_##index, &adc_stm32_cfg_##index, \ POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, \ &api_stm32_driver_api); diff --git a/drivers/adc/iadc_gecko.c b/drivers/adc/iadc_gecko.c index 1317a4e47295a81..d9dc542a5bf94d3 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 b1802f9cf260928..c38c35c8807ad17 100644 --- a/drivers/audio/CMakeLists.txt +++ b/drivers/audio/CMakeLists.txt @@ -7,3 +7,5 @@ zephyr_library_sources_ifdef(CONFIG_AUDIO_MPXXDTYY mpxxdtyy.c) 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 a45e003f80a49ee..500e36e7e44c924 100644 --- a/drivers/audio/Kconfig +++ b/drivers/audio/Kconfig @@ -25,6 +25,12 @@ config AUDIO_CODEC_INIT_PRIORITY help Audio codec device driver initialization priority. +config AUDIO_CODEC_SHELL + bool "Audio Codec shell" + depends on SHELL + help + Enable the Audio Codec shell with Audio Codec related commands. + module = AUDIO_CODEC module-str = audio codec source "subsys/logging/Kconfig.template.log_config" @@ -53,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 000000000000000..993e30fdb53f537 --- /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 new file mode 100644 index 000000000000000..b5c3421bf265e17 --- /dev/null +++ b/drivers/audio/codec_shell.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2023 Centralp + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define CODEC_START_HELP \ + "Start output audio playback. Syntax:\n" \ + "" + +#define CODEC_STOP_HELP \ + "Stop output audio playback. Syntax:\n" \ + "" + +#define CODEC_SET_PROP_HELP \ + "Set a codec property. Syntax:\n" \ + " " + +#define CODEC_APPLY_PROP_HELP \ + "Apply any cached properties. Syntax:\n" \ + "" + +static const char *const codec_property_name[] = { + [AUDIO_PROPERTY_OUTPUT_VOLUME] = "volume", + [AUDIO_PROPERTY_OUTPUT_MUTE] = "mute", +}; + +static const char *const codec_channel_name[] = { + [AUDIO_CHANNEL_FRONT_LEFT] = "front_left", + [AUDIO_CHANNEL_FRONT_RIGHT] = "front_right", + [AUDIO_CHANNEL_LFE] = "lfe", + [AUDIO_CHANNEL_FRONT_CENTER] = "front_center", + [AUDIO_CHANNEL_REAR_LEFT] = "rear_left", + [AUDIO_CHANNEL_REAR_RIGHT] = "rear_right", + [AUDIO_CHANNEL_REAR_CENTER] = "rear_center", + [AUDIO_CHANNEL_SIDE_LEFT] = "side_left", + [AUDIO_CHANNEL_SIDE_RIGHT] = "side_right", + [AUDIO_CHANNEL_ALL] = "all", +}; + +struct args_index { + uint8_t device; + uint8_t property; + uint8_t channel; + uint8_t value; +}; + +static const struct args_index args_indx = { + .device = 1, + .property = 2, + .channel = 3, + .value = 4, +}; + +static int parse_named_int(const char *name, const char *const keystack[], size_t count) +{ + char *endptr; + int i; + + /* Attempt to parse name as a number first */ + i = strtoul(name, &endptr, 0); + if (*endptr == '\0') { + return i; + } + + /* Name is not a number, look it up */ + for (i = 0; i < count; i++) { + if (strcmp(name, keystack[i]) == 0) { + return i; + } + } + + return -ENOTSUP; +} + +static int cmd_start(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + + dev = device_get_binding(argv[args_indx.device]); + if (!dev) { + shell_error(sh, "Audio Codec device not found"); + return -ENODEV; + } + audio_codec_start_output(dev); + + return 0; +} + +static int cmd_stop(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + + dev = device_get_binding(argv[args_indx.device]); + if (!dev) { + shell_error(sh, "Audio Codec device not found"); + return -ENODEV; + } + audio_codec_stop_output(dev); + + return 0; +} + +static int cmd_set_prop(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + int property; + int channel; + long value; + char *endptr; + audio_property_value_t property_value; + + dev = device_get_binding(argv[args_indx.device]); + if (!dev) { + shell_error(sh, "Audio Codec device not found"); + return -ENODEV; + } + + property = parse_named_int(argv[args_indx.property], codec_property_name, + ARRAY_SIZE(codec_property_name)); + if (property < 0) { + shell_error(sh, "Property '%s' unknown", argv[args_indx.property]); + return -EINVAL; + } + + channel = parse_named_int(argv[args_indx.channel], codec_channel_name, + ARRAY_SIZE(codec_channel_name)); + if (channel < 0) { + shell_error(sh, "Channel '%s' unknown", argv[args_indx.channel]); + return -EINVAL; + } + + value = strtol(argv[args_indx.value], &endptr, 0); + if (*endptr != '\0') { + return -EINVAL; + } + if (value > INT32_MAX || value < INT32_MIN) { + return -EINVAL; + } + switch (property) { + case AUDIO_PROPERTY_OUTPUT_VOLUME: + property_value.vol = value; + break; + case AUDIO_PROPERTY_OUTPUT_MUTE: + property_value.mute = value; + break; + default: + return -EINVAL; + } + + return audio_codec_set_property(dev, property, channel, property_value); +} + +static int cmd_apply_prop(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + + dev = device_get_binding(argv[args_indx.device]); + if (!dev) { + shell_error(sh, "Audio Codec device not found"); + return -ENODEV; + } + + return audio_codec_apply_properties(dev); +} + +/* 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); + +/* clang-format off */ +SHELL_STATIC_SUBCMD_SET_CREATE(sub_codec, + SHELL_CMD_ARG(start, &dsub_device_name, CODEC_START_HELP, cmd_start, + 2, 0), + SHELL_CMD_ARG(stop, &dsub_device_name, CODEC_STOP_HELP, cmd_stop, + 2, 0), + SHELL_CMD_ARG(set_prop, &dsub_device_name, CODEC_SET_PROP_HELP, cmd_set_prop, + 5, 0), + SHELL_CMD_ARG(apply_prop, &dsub_device_name, CODEC_APPLY_PROP_HELP, cmd_apply_prop, + 2, 0), + SHELL_SUBCMD_SET_END +); +/* clang-format on */ + +SHELL_CMD_REGISTER(codec, &sub_codec, "Audio Codec commands", NULL); diff --git a/drivers/audio/dmic_mcux.c b/drivers/audio/dmic_mcux.c new file mode 100644 index 000000000000000..ff357fda9bbb867 --- /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 91c36de289788fe..cb1efb597edf95a 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/CMakeLists.txt b/drivers/auxdisplay/CMakeLists.txt index 91a86610526a901..ce53a06713bfdc6 100644 --- a/drivers/auxdisplay/CMakeLists.txt +++ b/drivers/auxdisplay/CMakeLists.txt @@ -8,3 +8,4 @@ zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_HD44780 auxdisplay_hd44780.c) zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_ITRON auxdisplay_itron.c) zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_JHD1313 auxdisplay_jhd1313.c) zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_PT6314 auxdisplay_pt6314.c) +zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_SERLCD auxdisplay_serlcd.c) diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index f28b463a633c55d..908ceab179684d2 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -24,5 +24,6 @@ source "drivers/auxdisplay/Kconfig.hd44780" source "drivers/auxdisplay/Kconfig.itron" source "drivers/auxdisplay/Kconfig.jhd1313" source "drivers/auxdisplay/Kconfig.pt6314" +source "drivers/auxdisplay/Kconfig.serlcd" endif # AUXDISPLAY diff --git a/drivers/auxdisplay/Kconfig.serlcd b/drivers/auxdisplay/Kconfig.serlcd new file mode 100644 index 000000000000000..d90acfe78d46c3a --- /dev/null +++ b/drivers/auxdisplay/Kconfig.serlcd @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Jan Henke +# SPDX-License-Identifier: Apache-2.0 + +config AUXDISPLAY_SERLCD + bool "SparkFun SerLCD dot character LCD driver" + default y + select I2C + depends on DT_HAS_SPARKFUN_SERLCD_ENABLED + help + Enable driver for SparkFun SerLCD. diff --git a/drivers/auxdisplay/auxdisplay_handlers.c b/drivers/auxdisplay/auxdisplay_handlers.c index 8944b3da9fff83a..5c88e7afa09bcef 100644 --- a/drivers/auxdisplay/auxdisplay_handlers.c +++ b/drivers/auxdisplay/auxdisplay_handlers.c @@ -5,25 +5,25 @@ */ #include -#include +#include static inline int z_vrfy_auxdisplay_display_on(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_display_on(dev); } #include static inline int z_vrfy_auxdisplay_display_off(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_display_off(dev); } #include static inline int z_vrfy_auxdisplay_cursor_set_enabled(const struct device *dev, bool enabled) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_cursor_set_enabled(dev, enabled); } #include @@ -31,7 +31,7 @@ static inline int z_vrfy_auxdisplay_cursor_set_enabled(const struct device *dev, static inline int z_vrfy_auxdisplay_position_blinking_set_enabled(const struct device *dev, bool enabled) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_position_blinking_set_enabled(dev, enabled); } #include @@ -39,7 +39,7 @@ static inline int z_vrfy_auxdisplay_position_blinking_set_enabled(const struct d static inline int z_vrfy_auxdisplay_cursor_shift_set(const struct device *dev, uint8_t direction, bool display_shift) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_cursor_shift_set(dev, direction, display_shift); } #include @@ -48,7 +48,7 @@ static inline int z_vrfy_auxdisplay_cursor_position_set(const struct device *dev enum auxdisplay_position type, int16_t x, int16_t y) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_cursor_position_set(dev, type, x, y); } #include @@ -56,7 +56,7 @@ static inline int z_vrfy_auxdisplay_cursor_position_set(const struct device *dev static inline int z_vrfy_auxdisplay_cursor_position_get(const struct device *dev, int16_t *x, int16_t *y) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_cursor_position_get(dev, x, y); } #include @@ -65,7 +65,7 @@ static inline int z_vrfy_auxdisplay_display_position_set(const struct device *de enum auxdisplay_position type, int16_t x, int16_t y) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_display_position_set(dev, type, x, y); } #include @@ -73,7 +73,7 @@ static inline int z_vrfy_auxdisplay_display_position_set(const struct device *de static inline int z_vrfy_auxdisplay_display_position_get(const struct device *dev, int16_t *x, int16_t *y) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_display_position_get(dev, x, y); } #include @@ -81,14 +81,14 @@ static inline int z_vrfy_auxdisplay_display_position_get(const struct device *de static inline int z_vrfy_auxdisplay_capabilities_get(const struct device *dev, struct auxdisplay_capabilities *capabilities) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_capabilities_get(dev, capabilities); } #include static inline int z_vrfy_auxdisplay_clear(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_clear(dev); } #include @@ -96,7 +96,7 @@ static inline int z_vrfy_auxdisplay_clear(const struct device *dev) static inline int z_vrfy_auxdisplay_brightness_get(const struct device *dev, uint8_t *brightness) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_brightness_get(dev, brightness); } #include @@ -104,7 +104,7 @@ static inline int z_vrfy_auxdisplay_brightness_get(const struct device *dev, static inline int z_vrfy_auxdisplay_brightness_set(const struct device *dev, uint8_t brightness) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_brightness_set(dev, brightness); } #include @@ -112,7 +112,7 @@ static inline int z_vrfy_auxdisplay_brightness_set(const struct device *dev, static inline int z_vrfy_auxdisplay_backlight_get(const struct device *dev, uint8_t *backlight) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_backlight_get(dev, backlight); } #include @@ -120,14 +120,14 @@ static inline int z_vrfy_auxdisplay_backlight_get(const struct device *dev, static inline int z_vrfy_auxdisplay_backlight_set(const struct device *dev, uint8_t backlight) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_backlight_set(dev, backlight); } #include static inline int z_vrfy_auxdisplay_is_busy(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_is_busy(dev); } #include @@ -135,7 +135,7 @@ static inline int z_vrfy_auxdisplay_is_busy(const struct device *dev) static inline int z_vrfy_auxdisplay_custom_character_set(const struct device *dev, struct auxdisplay_character *character) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_custom_character_set(dev, character); } #include @@ -143,7 +143,7 @@ static inline int z_vrfy_auxdisplay_custom_character_set(const struct device *de static inline int z_vrfy_auxdisplay_write(const struct device *dev, const uint8_t *data, uint16_t len) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_write(dev, data, len); } #include @@ -151,7 +151,7 @@ static inline int z_vrfy_auxdisplay_write(const struct device *dev, const uint8_ static inline int z_vrfy_auxdisplay_custom_command(const struct device *dev, struct auxdisplay_custom_data *data) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AUXDISPLAY)); return z_impl_auxdisplay_custom_command(dev, data); } #include diff --git a/drivers/auxdisplay/auxdisplay_serlcd.c b/drivers/auxdisplay/auxdisplay_serlcd.c new file mode 100644 index 000000000000000..19c7154de293c9e --- /dev/null +++ b/drivers/auxdisplay/auxdisplay_serlcd.c @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2023 Jan Henke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT sparkfun_serlcd + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(auxdisplay_serlcd, CONFIG_AUXDISPLAY_LOG_LEVEL); + +/* + * | in ASCII, used to begin a display command + */ +#define SERLCD_BEGIN_COMMAND 0x7C + +/* + * special command for the underlying display controller + */ +#define SERLCD_BEGIN_SPECIAL_COMMAND 0xFE + +/* + * maximum amount of custom chars the display supports + */ +#define SERLCD_CUSTOM_CHAR_MAX_COUNT 8 + +/* + * height of a custom char in bits + */ +#define SERLCD_CUSTOM_CHAR_HEIGHT 8 + +/* + * width of a custom char in bits + */ +#define SERLCD_CUSTOM_CHAR_WIDTH 5 + +/* + * char code for the first custom char + */ +#define SERLCD_CUSTOM_CHAR_INDEX_BASE 0x08 + +/* + * bitmask for custom character detection + */ +#define SERLCD_CUSTOM_CHAR_BITMASK 0xf8 + +/* + * bit to set in the display control special command to indicate the display should be powered on + */ +#define SERLCD_DISPLAY_CONTROL_POWER_BIT BIT(2) + +/* + * bit to set in the display control special command to indicate the cursor should be displayed + */ +#define SERLCD_DISPLAY_CONTROL_CURSOR_BIT BIT(1) + +/* + * bit to set in the display control special command to indicate the cursor should be blinking + */ +#define SERLCD_DISPLAY_CONTROL_BLINKING_BIT BIT(0) + +struct auxdisplay_serlcd_data { + bool power; + bool cursor; + bool blinking; + uint16_t cursor_x; + uint16_t cursor_y; +}; + +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 { + SERLCD_COMMAND_SET_CUSTOM_CHAR = 0x1B, + SERLCD_COMMAND_WRITE_CUSTOM_CHAR = 0x23, + SERLCD_COMMAND_CLEAR = 0x2D, +}; + +enum auxdisplay_serlcd_special_command { + SERLCD_SPECIAL_RETURN_HOME = 0x02, + SERLCD_SPECIAL_DISPLAY_CONTROL = 0x08, + SERLCD_SPECIAL_SET_DD_RAM_ADDRESS = 0x80, +}; + +static int auxdisplay_serlcd_send_command(const struct device *dev, + const enum auxdisplay_serlcd_command command) +{ + const struct auxdisplay_serlcd_config *config = dev->config; + const uint8_t buffer[2] = {SERLCD_BEGIN_COMMAND, command}; + + int rc = i2c_write_dt(&config->bus, buffer, sizeof(buffer)); + + k_sleep(K_MSEC(config->command_delay_ms)); + return rc; +} + +static int +auxdisplay_serlcd_send_special_command(const struct device *dev, + const enum auxdisplay_serlcd_special_command command) +{ + const struct auxdisplay_serlcd_config *config = dev->config; + const uint8_t buffer[2] = {SERLCD_BEGIN_SPECIAL_COMMAND, command}; + + int rc = i2c_write_dt(&config->bus, buffer, sizeof(buffer)); + + k_sleep(K_MSEC(config->special_command_delay_ms)); + return rc; +} + +static int auxdisplay_serlcd_send_display_state(const struct device *dev, + const struct auxdisplay_serlcd_data *data) +{ + uint8_t command = SERLCD_SPECIAL_DISPLAY_CONTROL; + + if (data->power) { + command |= SERLCD_DISPLAY_CONTROL_POWER_BIT; + } + if (data->cursor) { + command |= SERLCD_DISPLAY_CONTROL_CURSOR_BIT; + } + if (data->blinking) { + command |= SERLCD_DISPLAY_CONTROL_BLINKING_BIT; + } + + return auxdisplay_serlcd_send_special_command(dev, command); +} + +static int auxdisplay_serlcd_display_on(const struct device *dev) +{ + struct auxdisplay_serlcd_data *data = dev->data; + + data->power = true; + + return auxdisplay_serlcd_send_display_state(dev, data); +} + +static int auxdisplay_serlcd_display_off(const struct device *dev) +{ + struct auxdisplay_serlcd_data *data = dev->data; + + data->power = false; + + return auxdisplay_serlcd_send_display_state(dev, data); +} + +static int auxdisplay_serlcd_cursor_set_enabled(const struct device *dev, bool enable) +{ + struct auxdisplay_serlcd_data *data = dev->data; + + data->cursor = enable; + + return auxdisplay_serlcd_send_display_state(dev, data); +} + +static int auxdisplay_serlcd_position_blinking_set_enabled(const struct device *dev, bool enable) +{ + struct auxdisplay_serlcd_data *data = dev->data; + + data->blinking = enable; + + return auxdisplay_serlcd_send_display_state(dev, data); +} + +static int auxdisplay_serlcd_cursor_position_set(const struct device *dev, + enum auxdisplay_position type, int16_t x, + int16_t y) +{ + static const uint8_t row_offsets[] = {0x00, 0x40, 0x14, 0x54}; + + const struct auxdisplay_serlcd_config *config = dev->config; + const struct auxdisplay_capabilities capabilities = config->capabilities; + const uint16_t columns = capabilities.columns; + const uint16_t rows = capabilities.rows; + struct auxdisplay_serlcd_data *data = dev->data; + + if (type == AUXDISPLAY_POSITION_ABSOLUTE) { + /* + * shortcut for (0,0) position + */ + if (x == 0 && y == 0) { + data->cursor_x = x; + data->cursor_y = y; + return auxdisplay_serlcd_send_special_command(dev, + SERLCD_SPECIAL_RETURN_HOME); + } + + /* + * bounds checking + */ + if (x < 0 || x >= columns) { + return -EINVAL; + } + if (y < 0 || y >= rows) { + return -EINVAL; + } + + data->cursor_x = x; + data->cursor_y = y; + + const uint8_t cursor_address = x + row_offsets[y]; + + return auxdisplay_serlcd_send_special_command( + dev, SERLCD_SPECIAL_SET_DD_RAM_ADDRESS | cursor_address); + + } else if (type == AUXDISPLAY_POSITION_RELATIVE) { + /* + * clip relative move to display dimensions + */ + const int new_x = (data->cursor_x + x) % columns; + const int new_y = (data->cursor_y + y + x / columns) % rows; + const uint16_t column = new_x < 0 ? new_x + columns : new_x; + const uint16_t row = new_y < 0 ? new_y + rows : new_y; + + data->cursor_x = column; + data->cursor_y = row; + + const uint8_t cursor_address = column + row_offsets[row]; + + return auxdisplay_serlcd_send_special_command( + dev, SERLCD_SPECIAL_SET_DD_RAM_ADDRESS | cursor_address); + } + + /* + * other types of movement are not implemented/supported + */ + return -ENOSYS; +} + +static int auxdisplay_serlcd_cursor_position_get(const struct device *dev, int16_t *x, int16_t *y) +{ + const struct auxdisplay_serlcd_data *data = dev->data; + + *x = (int16_t)data->cursor_x; + *y = (int16_t)data->cursor_y; + + return 0; +} + +static int auxdisplay_serlcd_capabilities_get(const struct device *dev, + struct auxdisplay_capabilities *capabilities) +{ + const struct auxdisplay_serlcd_config *config = dev->config; + + memcpy(capabilities, &config->capabilities, sizeof(struct auxdisplay_capabilities)); + + return 0; +} + +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(config->command_delay_ms)); + return rc; +} + +static int auxdisplay_serlcd_custom_character_set(const struct device *dev, + struct auxdisplay_character *character) +{ + const struct auxdisplay_serlcd_config *config = dev->config; + int rc; + + /* + * only indexes 0..7 are supported + */ + const uint8_t char_index = character->index; + + if (char_index > (SERLCD_CUSTOM_CHAR_MAX_COUNT - 1)) { + return -EINVAL; + } + + /* + * custom characters are accessible via char codes 0x08..0x0f + */ + character->character_code = SERLCD_CUSTOM_CHAR_INDEX_BASE | char_index; + + rc = auxdisplay_serlcd_send_command(dev, SERLCD_COMMAND_SET_CUSTOM_CHAR + char_index); + if (!rc) { + return rc; + } + + /* + * the display expects the custom character as 8 lines of 5 bit each, shades are not + * supported + */ + for (int l = 0; l < SERLCD_CUSTOM_CHAR_HEIGHT; ++l) { + uint8_t buffer = 0; + + for (int i = 0; i < SERLCD_CUSTOM_CHAR_WIDTH; ++i) { + if (character->data[(l * 5) + i]) { + buffer |= BIT(4 - i); + } + } + rc = i2c_write_dt(&config->bus, &buffer, sizeof(buffer)); + if (!rc) { + return rc; + } + } + + return rc; +} + +static void auxdisplay_serlcd_advance_current_position(const struct device *dev) +{ + const struct auxdisplay_serlcd_config *config = dev->config; + struct auxdisplay_serlcd_data *data = dev->data; + + ++(data->cursor_x); + if (data->cursor_x >= config->capabilities.columns) { + data->cursor_x = 0; + ++(data->cursor_y); + } + if (data->cursor_y >= config->capabilities.rows) { + data->cursor_y = 0; + } +} + +static int auxdisplay_serlcd_write(const struct device *dev, const uint8_t *text, uint16_t len) +{ + const struct auxdisplay_serlcd_config *config = dev->config; + + int rc = 0; + + /* + * the display wraps around by itself, just write the text and update the position data + */ + for (int i = 0; i < len; ++i) { + uint8_t character = text[i]; + + /* + * customer characters require a special command, so check for custom char + */ + if ((character & SERLCD_CUSTOM_CHAR_BITMASK) == SERLCD_CUSTOM_CHAR_INDEX_BASE) { + const uint8_t command = SERLCD_COMMAND_WRITE_CUSTOM_CHAR + + (character & ~SERLCD_CUSTOM_CHAR_BITMASK); + + rc = auxdisplay_serlcd_send_command(dev, command); + if (!rc) { + return rc; + } + auxdisplay_serlcd_advance_current_position(dev); + } else if (character == SERLCD_BEGIN_COMMAND || + character == SERLCD_BEGIN_SPECIAL_COMMAND) { + /* + * skip these characters in text, as they have a special meaning, if + * required a custom character can be used as replacement + */ + continue; + } else { + rc = i2c_write_dt(&config->bus, text, len); + if (!rc) { + return rc; + } + auxdisplay_serlcd_advance_current_position(dev); + } + } + + return rc; +} + +static int auxdisplay_serlcd_init(const struct device *dev) +{ + const struct auxdisplay_serlcd_config *config = dev->config; + struct auxdisplay_serlcd_data *data = dev->data; + + /* + * Initialize our data structure + */ + data->power = true; + + if (!device_is_ready(config->bus.bus)) { + return -ENODEV; + } + + auxdisplay_serlcd_clear(dev); + + return 0; +} + +static const struct auxdisplay_driver_api auxdisplay_serlcd_auxdisplay_api = { + .display_on = auxdisplay_serlcd_display_on, + .display_off = auxdisplay_serlcd_display_off, + .cursor_set_enabled = auxdisplay_serlcd_cursor_set_enabled, + .position_blinking_set_enabled = auxdisplay_serlcd_position_blinking_set_enabled, + .cursor_position_set = auxdisplay_serlcd_cursor_position_set, + .cursor_position_get = auxdisplay_serlcd_cursor_position_get, + .capabilities_get = auxdisplay_serlcd_capabilities_get, + .clear = auxdisplay_serlcd_clear, + .custom_character_set = auxdisplay_serlcd_custom_character_set, + .write = auxdisplay_serlcd_write, +}; + +#define AUXDISPLAY_SERLCD_INST(inst) \ + static const struct auxdisplay_serlcd_config auxdisplay_serlcd_config_##inst = { \ + .capabilities = { \ + .columns = DT_INST_PROP(inst, columns), \ + .rows = DT_INST_PROP(inst, rows), \ + .mode = 0, \ + .brightness.minimum = AUXDISPLAY_LIGHT_NOT_SUPPORTED, \ + .brightness.maximum = AUXDISPLAY_LIGHT_NOT_SUPPORTED, \ + .backlight.minimum = AUXDISPLAY_LIGHT_NOT_SUPPORTED, \ + .backlight.maximum = AUXDISPLAY_LIGHT_NOT_SUPPORTED, \ + .custom_characters = SERLCD_CUSTOM_CHAR_MAX_COUNT, \ + .custom_character_width = SERLCD_CUSTOM_CHAR_WIDTH, \ + .custom_character_height = SERLCD_CUSTOM_CHAR_HEIGHT, \ + }, \ + .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; \ + \ + DEVICE_DT_INST_DEFINE(inst, &auxdisplay_serlcd_init, NULL, &auxdisplay_serlcd_data_##inst, \ + &auxdisplay_serlcd_config_##inst, POST_KERNEL, \ + CONFIG_AUXDISPLAY_INIT_PRIORITY, &auxdisplay_serlcd_auxdisplay_api); + +DT_INST_FOREACH_STATUS_OKAY(AUXDISPLAY_SERLCD_INST) diff --git a/drivers/bbram/CMakeLists.txt b/drivers/bbram/CMakeLists.txt index 538384e9d14a79e..9027ab548b38210 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 a3af7e9537b9ad0..64ed29f1a528e15 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 015b2bcb12462f0..35fd828e6a52935 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 4b5cc135b7201d6..e529022213ec3d0 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_handlers.c b/drivers/bbram/bbram_handlers.c index 1bc20dcd359bd2a..14e4abe21b35d03 100644 --- a/drivers/bbram/bbram_handlers.c +++ b/drivers/bbram/bbram_handlers.c @@ -5,33 +5,33 @@ */ #include -#include +#include static inline int z_vrfy_bbram_check_invalid(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_BBRAM)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_BBRAM)); return z_impl_bbram_check_invalid(dev); } #include static inline int z_vrfy_bbram_check_standby_power(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_BBRAM)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_BBRAM)); return z_impl_bbram_check_standby_power(dev); } #include static inline int z_vrfy_bbram_check_power(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_BBRAM)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_BBRAM)); return z_impl_bbram_check_power(dev); } #include static inline int z_vrfy_bbram_get_size(const struct device *dev, size_t *size) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_BBRAM)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(size, sizeof(size_t))); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_BBRAM)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(size, sizeof(size_t))); return z_impl_bbram_get_size(dev, size); } #include @@ -39,8 +39,8 @@ static inline int z_vrfy_bbram_get_size(const struct device *dev, size_t *size) static inline int z_vrfy_bbram_read(const struct device *dev, size_t offset, size_t size, uint8_t *data) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_BBRAM)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(data, size)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_BBRAM)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(data, size)); return z_impl_bbram_read(dev, offset, size, data); } #include @@ -48,8 +48,8 @@ static inline int z_vrfy_bbram_read(const struct device *dev, size_t offset, static inline int z_vrfy_bbram_write(const struct device *dev, size_t offset, size_t size, const uint8_t *data) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_BBRAM)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(data, size)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_BBRAM)); + K_OOPS(K_SYSCALL_MEMORY_READ(data, size)); return z_impl_bbram_write(dev, offset, size, data); } #include diff --git a/drivers/bbram/bbram_it8xxx2.c b/drivers/bbram/bbram_it8xxx2.c index cae7715e702c0c5..cecf555ee8db16e 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 000000000000000..901a09835f1f85c --- /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 c3b538c842f825b..ff5b7850576a6ac 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 000000000000000..56a848259488970 --- /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 b9b02f90eb3cda8..ba9500ae6f16b96 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 000000000000000..799e158eefd0662 --- /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/bbram_stm32.c b/drivers/bbram/bbram_stm32.c index 30bc2c5edaaa78e..0ba429d66f8fd6e 100644 --- a/drivers/bbram/bbram_stm32.c +++ b/drivers/bbram/bbram_stm32.c @@ -14,7 +14,14 @@ LOG_MODULE_REGISTER(bbram, CONFIG_BBRAM_LOG_LEVEL); #define STM32_BKP_REG_BYTES 4 -#define STM32_BKP_REG_OFFSET 0x50 +#ifdef TAMP +/* If a SoC has a TAMP peripherals, then the backup registers are defined there, + * not in the RTC. + */ +#define STM32_BKP_REG_OFFSET (TAMP_BASE + offsetof(TAMP_TypeDef, BKP0R) - RTC_BASE) +#else +#define STM32_BKP_REG_OFFSET offsetof(RTC_TypeDef, BKP0R) +#endif #define STM32_BKP_REG_INDEX(offset) ((offset) >> 2) #define STM32_BKP_REG_BYTE_INDEX(offset) ((offset)&0x3UL) #define STM32_BKP_REG(i) (((volatile uint32_t *)config->base_addr)[(i)]) diff --git a/drivers/bbram/it8xxx2.h b/drivers/bbram/it8xxx2.h new file mode 100644 index 000000000000000..d5e905d4f7253e4 --- /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 000000000000000..b177a94f32ad95e --- /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 5b09bbd81cc49ac..adda6ea0e2ab05a 100644 --- a/drivers/bluetooth/hci/CMakeLists.txt +++ b/drivers/bluetooth/hci/CMakeLists.txt @@ -1,14 +1,35 @@ # SPDX-License-Identifier: Apache-2.0 +# Remove after 3.7.0 is released +if(CONFIG_BT_RPMSG) + message(FATAL_ERROR "CONFIG_BT_RPMSG has been renamed to CONFIG_BT_HCI_IPC") +endif() + +# Remove after 3.7.0 is released +if(CONFIG_BT_HCI_IPC) + dt_chosen(chosen_hci_rpmsg PROPERTY "zephyr,bt-hci-rpmsg-ipc") + if(DEFINED chosen_hci_rpmsg) + message(FATAL_ERROR "zephyr,bt-hci-rpmsg-ipc has been renamed to zephyr,bt-hci-ipc") + endif() +endif() + zephyr_library_sources_ifdef(CONFIG_BT_B91 hci_b91.c) -zephyr_library_sources_ifdef(CONFIG_BT_CYW43XXX cyw43xxx.c) +zephyr_library_sources_ifdef(CONFIG_BT_AIROC cyw43xxx.c) 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_RPMSG rpmsg.c) -zephyr_library_sources_ifdef(CONFIG_BT_SPI spi.c) +zephyr_library_sources_ifdef(CONFIG_BT_HCI_IPC ipc.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 07aa505f8b4e1b0..ad1d9da2df2a646 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -10,6 +10,7 @@ config BT_UART select SERIAL select UART_INTERRUPT_DRIVEN + choice BT_HCI_BUS_TYPE prompt "Bluetooth HCI driver" @@ -28,14 +29,21 @@ config BT_H5 Bluetooth three-wire (H:5) UART driver. Implementation of HCI Three-Wire UART Transport Layer. +# Removed: Here only to give the user a warning about its removal +# Remove after 3.7.0 is released config BT_RPMSG - bool "HCI using RPMsg" + bool "[REMOVED] HCI using RPMsg" + help + Use BT_HCI_IPC instead + +config BT_HCI_IPC + bool "HCI using the IPC subsystem" select BT_HAS_HCI_VS select IPC_SERVICE select MBOX help Bluetooth HCI driver for communication with another CPU - using RPMsg framework. + using the IPC subsystem. config BT_SPI bool "SPI HCI" @@ -54,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 @@ -102,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 @@ -112,27 +136,34 @@ 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" depends on BT_STM32_IPM default 512 -menuconfig BT_CYW43XXX - bool "CYW43XXX BT connectivity" +menuconfig BT_AIROC + bool "AIROC BT connectivity" default y select BT_HCI_SETUP + select UART_USE_RUNTIME_CONFIGURE depends on GPIO depends on DT_HAS_INFINEON_CYW43XXX_BT_HCI_ENABLED depends on BT_H4 @@ -145,7 +176,7 @@ source "drivers/bluetooth/hci/Kconfig.infineon" config BT_DRIVER_QUIRK_NO_AUTO_DLE bool "Host auto-initiated Data Length Update quirk" depends on BT_AUTO_DATA_LEN_UPDATE - default y if BT_RPMSG || BT_ESP32 + default y if BT_HCI_IPC || BT_ESP32 help Enable the quirk wherein BT Host stack will auto-initiate Data Length Update procedure for new connections for controllers that do not @@ -155,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 @@ -176,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 d0e4478ac3439fd..6204ed4f8a2fdfd 100644 --- a/drivers/bluetooth/hci/Kconfig.infineon +++ b/drivers/bluetooth/hci/Kconfig.infineon @@ -2,10 +2,10 @@ # an affiliate of Cypress Semiconductor Corporation # SPDX-License-Identifier: Apache-2.0 -if BT_CYW43XXX +if BT_AIROC -choice CYW43XXX_PART - prompt "Select CYW43XXX part" +choice AIROC_PART + prompt "Select AIROC part" config CYW4343W bool "CYW4343W" @@ -42,12 +42,12 @@ config CYW43439 More information about CYW43439 device you can find on https://www.infineon.com/cms/en/product/wireless-connectivity/airoc-wi-fi-plus-bluetooth-combos/cyw43439/ -config BT_CYW43XXX_CUSTOM - bool "Custom CYW43xx device/module" +config BT_AIROC_CUSTOM + bool "Custom AIROC device/module" help - Select Custom CYW43xx device/module. For this option, + Select Custom AIROC device/module. For this option, user must to provide path to BT firmware HCD file for - custom or vendor CYW43xx modules in CYW43XX_CUSTOM_FIRMWARE_HCD_BLOB. + custom or vendor AIROC modules in AIROC_CUSTOM_FIRMWARE_HCD_BLOB. endchoice @@ -117,8 +117,8 @@ config CYW43439_MURATA_1YN endchoice -config CYW43XX_CUSTOM_FIRMWARE_HCD_BLOB - depends on BT_CYW43XXX_CUSTOM +config AIROC_CUSTOM_FIRMWARE_HCD_BLOB + depends on BT_AIROC_CUSTOM string "Path to user BT firmware HCD file" help Path to BT firmware HCD file for custom or vendor CYW43xx modules. @@ -129,12 +129,7 @@ config CYW43XX_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_CYW43XXX +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 000000000000000..eff8d8fbd812550 --- /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 000000000000000..a05238657e5a518 --- /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 c263c3f0c5d7b1e..e5cd81a06b8cd99 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/h5.c b/drivers/bluetooth/hci/h5.c index c9395509248ebcd..25a3b3e28f622e6 100644 --- a/drivers/bluetooth/hci/h5.c +++ b/drivers/bluetooth/hci/h5.c @@ -607,8 +607,12 @@ static int h5_queue(struct net_buf *buf) return 0; } -static void tx_thread(void) +static void tx_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + LOG_DBG(""); /* FIXME: make periodic sending */ @@ -653,8 +657,12 @@ static void h5_set_txwin(uint8_t *conf) conf[2] = h5.tx_win & 0x07; } -static void rx_thread(void) +static void rx_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + LOG_DBG(""); while (true) { @@ -721,7 +729,7 @@ static void h5_init(void) k_fifo_init(&h5.tx_queue); k_thread_create(&tx_thread_data, tx_stack, K_KERNEL_STACK_SIZEOF(tx_stack), - (k_thread_entry_t)tx_thread, NULL, NULL, NULL, + tx_thread, NULL, NULL, NULL, K_PRIO_COOP(CONFIG_BT_HCI_TX_PRIO), 0, K_NO_WAIT); k_thread_name_set(&tx_thread_data, "tx_thread"); @@ -729,7 +737,7 @@ static void h5_init(void) k_fifo_init(&h5.rx_queue); k_thread_create(&rx_thread_data, rx_stack, K_KERNEL_STACK_SIZEOF(rx_stack), - (k_thread_entry_t)rx_thread, NULL, NULL, NULL, + rx_thread, NULL, NULL, NULL, K_PRIO_COOP(CONFIG_BT_RX_PRIO), 0, K_NO_WAIT); k_thread_name_set(&rx_thread_data, "rx_thread"); diff --git a/drivers/bluetooth/hci/hci_ambiq.c b/drivers/bluetooth/hci/hci_ambiq.c new file mode 100644 index 000000000000000..b0c6ee43337fbb2 --- /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 8dae220dd944d94..121157d41bb32e2 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 3a5fddb1000d304..9f56eba7f608e1e 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 000000000000000..3626375768418ed --- /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 000000000000000..fd718d5efb68695 --- /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/ipc.c b/drivers/bluetooth/hci/ipc.c new file mode 100644 index 000000000000000..56671c702d62c3c --- /dev/null +++ b/drivers/bluetooth/hci/ipc.c @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_hci_driver); + +#define IPC_CMD 0x01 +#define IPC_ACL 0x02 +#define IPC_SCO 0x03 +#define IPC_EVT 0x04 +#define IPC_ISO 0x05 + +#define IPC_BOUND_TIMEOUT_IN_MS K_MSEC(1000) + +static struct ipc_ept hci_ept; +static K_SEM_DEFINE(ipc_bound_sem, 0, 1); + +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; +#if defined(CONFIG_BT_EXT_ADV) + case BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT: + { + const struct bt_hci_evt_le_ext_advertising_report *ext_adv = + (void *)&evt_data[3]; + + return (ext_adv->num_reports == 1) && + ((ext_adv->adv_info[0].evt_type & + BT_HCI_LE_ADV_EVT_TYPE_LEGACY) != 0); + } +#endif + default: + return false; + } + } + default: + return false; + } +} + +static struct net_buf *bt_ipc_evt_recv(const uint8_t *data, size_t remaining) +{ + bool discardable; + struct bt_hci_evt_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (remaining < 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); + remaining -= sizeof(hdr); + + if (remaining != hdr.len) { + LOG_ERR("Event payload length is not correct"); + return NULL; + } + LOG_DBG("len %u", hdr.len); + + do { + buf = bt_buf_get_evt(hdr.evt, discardable, discardable ? K_NO_WAIT : K_SECONDS(10)); + if (!buf) { + if (discardable) { + LOG_DBG("Discardable buffer pool full, ignoring event"); + return buf; + } + LOG_WRN("Couldn't allocate a buffer after waiting 10 seconds."); + } + } while (!buf); + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < remaining) { + LOG_ERR("Not enough space in buffer %zu/%zu", remaining, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, data, remaining); + + return buf; +} + +static struct net_buf *bt_ipc_acl_recv(const uint8_t *data, size_t remaining) +{ + struct bt_hci_acl_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (remaining < 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); + remaining -= sizeof(hdr); + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + } else { + LOG_ERR("No available ACL buffers!"); + return NULL; + } + + if (remaining != sys_le16_to_cpu(hdr.len)) { + LOG_ERR("ACL payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < remaining) { + LOG_ERR("Not enough space in buffer %zu/%zu", remaining, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + LOG_DBG("len %u", remaining); + net_buf_add_mem(buf, data, remaining); + + return buf; +} + +static struct net_buf *bt_ipc_iso_recv(const uint8_t *data, size_t remaining) +{ + struct bt_hci_iso_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (remaining < 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); + remaining -= sizeof(hdr); + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + } else { + LOG_ERR("No available ISO buffers!"); + return NULL; + } + + if (remaining != bt_iso_hdr_len(sys_le16_to_cpu(hdr.len))) { + LOG_ERR("ISO payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < remaining) { + LOG_ERR("Not enough space in buffer %zu/%zu", remaining, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + LOG_DBG("len %zu", remaining); + net_buf_add_mem(buf, data, remaining); + + return buf; +} + +static void bt_ipc_rx(const uint8_t *data, size_t len) +{ + uint8_t pkt_indicator; + struct net_buf *buf = NULL; + size_t remaining = len; + + LOG_HEXDUMP_DBG(data, len, "ipc data:"); + + pkt_indicator = *data++; + remaining -= sizeof(pkt_indicator); + + switch (pkt_indicator) { + case IPC_EVT: + buf = bt_ipc_evt_recv(data, remaining); + break; + + case IPC_ACL: + buf = bt_ipc_acl_recv(data, remaining); + break; + + case IPC_ISO: + buf = bt_ipc_iso_recv(data, remaining); + break; + + default: + LOG_ERR("Unknown HCI type %u", pkt_indicator); + return; + } + + if (buf) { + LOG_DBG("Calling bt_recv(%p)", buf); + + /* The IPC service does not guarantee that the handler thread + * is cooperative. In particular, the OpenAMP implementation is + * preemtible by default. OTOH, the HCI driver interface requires + * that the bt_recv() function is called from a cooperative + * thread. + * + * Calling `k_sched lock()` has the effect of making the current + * thread cooperative. + */ + k_sched_lock(); + bt_recv(buf); + k_sched_unlock(); + + LOG_HEXDUMP_DBG(buf->data, buf->len, "RX buf payload:"); + } +} + +static int bt_ipc_send(struct net_buf *buf) +{ + int err; + uint8_t pkt_indicator; + + 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 = IPC_ACL; + break; + case BT_BUF_CMD: + pkt_indicator = IPC_CMD; + break; + case BT_BUF_ISO_OUT: + pkt_indicator = IPC_ISO; + break; + default: + LOG_ERR("Unknown type %u", bt_buf_get_type(buf)); + goto done; + } + net_buf_push_u8(buf, pkt_indicator); + + LOG_HEXDUMP_DBG(buf->data, buf->len, "Final HCI buffer:"); + err = ipc_service_send(&hci_ept, buf->data, buf->len); + if (err < 0) { + LOG_ERR("Failed to send (err %d)", err); + } + +done: + net_buf_unref(buf); + return 0; +} + +static void hci_ept_bound(void *priv) +{ + k_sem_give(&ipc_bound_sem); +} + +static void hci_ept_recv(const void *data, size_t len, void *priv) +{ + bt_ipc_rx(data, len); +} + +static struct ipc_ept_cfg hci_ept_cfg = { + .name = "nrf_bt_hci", + .cb = { + .bound = hci_ept_bound, + .received = hci_ept_recv, + }, +}; + +int __weak bt_hci_transport_setup(const struct device *dev) +{ + ARG_UNUSED(dev); + return 0; +} + +int __weak bt_hci_transport_teardown(const struct device *dev) +{ + ARG_UNUSED(dev); + return 0; +} + +static int bt_ipc_open(void) +{ + int err; + + const struct device *hci_ipc_instance = + DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_hci_ipc)); + + err = bt_hci_transport_setup(NULL); + if (err) { + LOG_ERR("HCI transport setup failed with: %d\n", err); + return err; + } + + LOG_DBG(""); + + err = ipc_service_open_instance(hci_ipc_instance); + if (err && (err != -EALREADY)) { + LOG_ERR("IPC service instance initialization failed: %d\n", err); + return err; + } + + err = ipc_service_register_endpoint(hci_ipc_instance, &hci_ept, &hci_ept_cfg); + if (err) { + LOG_ERR("Registering endpoint failed with %d", err); + return err; + } + + err = k_sem_take(&ipc_bound_sem, IPC_BOUND_TIMEOUT_IN_MS); + if (err) { + LOG_ERR("Endpoint binding failed with %d", err); + return err; + } + + return 0; +} + +static int bt_ipc_close(void) +{ + int err; + + if (IS_ENABLED(CONFIG_BT_HCI_HOST)) { + err = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, NULL); + if (err) { + LOG_ERR("Sending reset command failed with: %d", err); + return err; + } + } + + err = ipc_service_deregister_endpoint(&hci_ept); + if (err) { + LOG_ERR("Deregistering HCI endpoint failed with: %d", err); + return err; + } + + const struct device *hci_ipc_instance = + DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_hci_ipc)); + + err = ipc_service_close_instance(hci_ipc_instance); + if (err) { + LOG_ERR("Closing IPC service failed with: %d", err); + return err; + } + + err = bt_hci_transport_teardown(NULL); + if (err) { + LOG_ERR("HCI transport teardown failed with: %d", err); + return err; + } + + return 0; +} + +static const struct bt_hci_driver drv = { + .name = "IPC", + .open = bt_ipc_open, + .close = bt_ipc_close, + .send = bt_ipc_send, + .bus = BT_HCI_DRIVER_BUS_IPM, +#if defined(CONFIG_BT_DRIVER_QUIRK_NO_AUTO_DLE) + .quirks = BT_QUIRK_NO_AUTO_DLE, +#endif +}; + +static int bt_ipc_init(void) +{ + + int err; + + err = bt_hci_driver_register(&drv); + if (err < 0) { + LOG_ERR("Failed to register BT HIC driver (err %d)", err); + } + + return err; +} + +SYS_INIT(bt_ipc_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 9ee261ae3d5e15c..85fc875f1397972 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, @@ -159,8 +159,12 @@ void TM_EvtReceivedCb(TL_EvtPacket_t *hcievt) k_fifo_put(&ipm_rx_events_fifo, hcievt); } -static void bt_ipm_rx_thread(void) +static void bt_ipm_rx_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + while (true) { bool discardable = false; k_timeout_t timeout = K_FOREVER; @@ -554,7 +558,7 @@ static int bt_ipm_open(void) /* Start RX thread */ k_thread_create(&ipm_rx_thread_data, ipm_rx_stack, K_KERNEL_STACK_SIZEOF(ipm_rx_stack), - (k_thread_entry_t)bt_ipm_rx_thread, NULL, NULL, NULL, + bt_ipm_rx_thread, NULL, NULL, NULL, K_PRIO_COOP(CONFIG_BT_DRIVER_RX_HIGH_PRIO), 0, K_NO_WAIT); diff --git a/drivers/bluetooth/hci/rpmsg.c b/drivers/bluetooth/hci/rpmsg.c deleted file mode 100644 index b3611f5f3e2c26e..000000000000000 --- a/drivers/bluetooth/hci/rpmsg.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright (c) 2019 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#include -#include -#include - -#include -#include - -#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL -#include -LOG_MODULE_REGISTER(bt_hci_driver); - -#define RPMSG_CMD 0x01 -#define RPMSG_ACL 0x02 -#define RPMSG_SCO 0x03 -#define RPMSG_EVT 0x04 -#define RPMSG_ISO 0x05 - -#define IPC_BOUND_TIMEOUT_IN_MS K_MSEC(1000) - -static struct ipc_ept hci_ept; -static K_SEM_DEFINE(ipc_bound_sem, 0, 1); - -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; -#if defined(CONFIG_BT_EXT_ADV) - case BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT: - { - const struct bt_hci_evt_le_ext_advertising_report *ext_adv = - (void *)&evt_data[3]; - - return (ext_adv->num_reports == 1) && - ((ext_adv->adv_info[0].evt_type & - BT_HCI_LE_ADV_EVT_TYPE_LEGACY) != 0); - } -#endif - default: - return false; - } - } - default: - return false; - } -} - -static struct net_buf *bt_rpmsg_evt_recv(const uint8_t *data, size_t remaining) -{ - bool discardable; - struct bt_hci_evt_hdr hdr; - struct net_buf *buf; - size_t buf_tailroom; - - if (remaining < 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); - remaining -= sizeof(hdr); - - if (remaining != hdr.len) { - LOG_ERR("Event payload length is not correct"); - return NULL; - } - LOG_DBG("len %u", hdr.len); - - do { - buf = bt_buf_get_evt(hdr.evt, discardable, discardable ? K_NO_WAIT : K_SECONDS(10)); - if (!buf) { - if (discardable) { - LOG_DBG("Discardable buffer pool full, ignoring event"); - return buf; - } - LOG_WRN("Couldn't allocate a buffer after waiting 10 seconds."); - } - } while (!buf); - - net_buf_add_mem(buf, &hdr, sizeof(hdr)); - - buf_tailroom = net_buf_tailroom(buf); - if (buf_tailroom < remaining) { - LOG_ERR("Not enough space in buffer %zu/%zu", remaining, buf_tailroom); - net_buf_unref(buf); - return NULL; - } - - net_buf_add_mem(buf, data, remaining); - - return buf; -} - -static struct net_buf *bt_rpmsg_acl_recv(const uint8_t *data, size_t remaining) -{ - struct bt_hci_acl_hdr hdr; - struct net_buf *buf; - size_t buf_tailroom; - - if (remaining < 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); - remaining -= sizeof(hdr); - - net_buf_add_mem(buf, &hdr, sizeof(hdr)); - } else { - LOG_ERR("No available ACL buffers!"); - return NULL; - } - - if (remaining != sys_le16_to_cpu(hdr.len)) { - LOG_ERR("ACL payload length is not correct"); - net_buf_unref(buf); - return NULL; - } - - buf_tailroom = net_buf_tailroom(buf); - if (buf_tailroom < remaining) { - LOG_ERR("Not enough space in buffer %zu/%zu", remaining, buf_tailroom); - net_buf_unref(buf); - return NULL; - } - - LOG_DBG("len %u", remaining); - net_buf_add_mem(buf, data, remaining); - - return buf; -} - -static struct net_buf *bt_rpmsg_iso_recv(const uint8_t *data, size_t remaining) -{ - struct bt_hci_iso_hdr hdr; - struct net_buf *buf; - size_t buf_tailroom; - - if (remaining < 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); - remaining -= sizeof(hdr); - - net_buf_add_mem(buf, &hdr, sizeof(hdr)); - } else { - LOG_ERR("No available ISO buffers!"); - return NULL; - } - - if (remaining != bt_iso_hdr_len(sys_le16_to_cpu(hdr.len))) { - LOG_ERR("ISO payload length is not correct"); - net_buf_unref(buf); - return NULL; - } - - buf_tailroom = net_buf_tailroom(buf); - if (buf_tailroom < remaining) { - LOG_ERR("Not enough space in buffer %zu/%zu", remaining, buf_tailroom); - net_buf_unref(buf); - return NULL; - } - - LOG_DBG("len %zu", remaining); - net_buf_add_mem(buf, data, remaining); - - return buf; -} - -static void bt_rpmsg_rx(const uint8_t *data, size_t len) -{ - uint8_t pkt_indicator; - struct net_buf *buf = NULL; - size_t remaining = len; - - LOG_HEXDUMP_DBG(data, len, "RPMsg data:"); - - pkt_indicator = *data++; - remaining -= sizeof(pkt_indicator); - - switch (pkt_indicator) { - case RPMSG_EVT: - buf = bt_rpmsg_evt_recv(data, remaining); - break; - - case RPMSG_ACL: - buf = bt_rpmsg_acl_recv(data, remaining); - break; - - case RPMSG_ISO: - buf = bt_rpmsg_iso_recv(data, remaining); - break; - - default: - LOG_ERR("Unknown HCI type %u", pkt_indicator); - return; - } - - if (buf) { - LOG_DBG("Calling bt_recv(%p)", buf); - - /* The IPC service does not guarantee that the handler thread - * is cooperative. In particular, the OpenAMP implementation is - * preemtible by default. OTOH, the HCI driver interface requires - * that the bt_recv() function is called from a cooperative - * thread. - * - * Calling `k_sched lock()` has the effect of making the current - * thread cooperative. - */ - k_sched_lock(); - bt_recv(buf); - k_sched_unlock(); - - LOG_HEXDUMP_DBG(buf->data, buf->len, "RX buf payload:"); - } -} - -static int bt_rpmsg_send(struct net_buf *buf) -{ - int err; - uint8_t pkt_indicator; - - 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 = RPMSG_ACL; - break; - case BT_BUF_CMD: - pkt_indicator = RPMSG_CMD; - break; - case BT_BUF_ISO_OUT: - pkt_indicator = RPMSG_ISO; - break; - default: - LOG_ERR("Unknown type %u", bt_buf_get_type(buf)); - goto done; - } - net_buf_push_u8(buf, pkt_indicator); - - LOG_HEXDUMP_DBG(buf->data, buf->len, "Final HCI buffer:"); - err = ipc_service_send(&hci_ept, buf->data, buf->len); - if (err < 0) { - LOG_ERR("Failed to send (err %d)", err); - } - -done: - net_buf_unref(buf); - return 0; -} - -static void hci_ept_bound(void *priv) -{ - k_sem_give(&ipc_bound_sem); -} - -static void hci_ept_recv(const void *data, size_t len, void *priv) -{ - bt_rpmsg_rx(data, len); -} - -static struct ipc_ept_cfg hci_ept_cfg = { - .name = "nrf_bt_hci", - .cb = { - .bound = hci_ept_bound, - .received = hci_ept_recv, - }, -}; - -int __weak bt_hci_transport_setup(const struct device *dev) -{ - ARG_UNUSED(dev); - return 0; -} - -int __weak bt_hci_transport_teardown(const struct device *dev) -{ - ARG_UNUSED(dev); - return 0; -} - -static int bt_rpmsg_open(void) -{ - int err; - const struct device *hci_ipc_instance = - DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_hci_rpmsg_ipc)); - - err = bt_hci_transport_setup(NULL); - if (err) { - LOG_ERR("HCI transport setup failed with: %d\n", err); - return err; - } - - LOG_DBG(""); - - err = ipc_service_open_instance(hci_ipc_instance); - if (err && (err != -EALREADY)) { - LOG_ERR("IPC service instance initialization failed: %d\n", err); - return err; - } - - err = ipc_service_register_endpoint(hci_ipc_instance, &hci_ept, &hci_ept_cfg); - if (err) { - LOG_ERR("Registering endpoint failed with %d", err); - return err; - } - - err = k_sem_take(&ipc_bound_sem, IPC_BOUND_TIMEOUT_IN_MS); - if (err) { - LOG_ERR("Endpoint binding failed with %d", err); - return err; - } - - return 0; -} - -static int bt_rpmsg_close(void) -{ - int err; - - if (IS_ENABLED(CONFIG_BT_HCI_HOST)) { - err = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, NULL); - if (err) { - LOG_ERR("Sending reset command failed with: %d", err); - return err; - } - } - - err = ipc_service_deregister_endpoint(&hci_ept); - if (err) { - LOG_ERR("Deregistering HCI endpoint failed with: %d", err); - return err; - } - - const struct device *hci_ipc_instance = - DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_hci_rpmsg_ipc)); - - err = ipc_service_close_instance(hci_ipc_instance); - if (err) { - LOG_ERR("Closing IPC service failed with: %d", err); - return err; - } - - err = bt_hci_transport_teardown(NULL); - if (err) { - LOG_ERR("HCI transport teardown failed with: %d", err); - return err; - } - - return 0; -} - -static const struct bt_hci_driver drv = { - .name = "RPMsg", - .open = bt_rpmsg_open, - .close = bt_rpmsg_close, - .send = bt_rpmsg_send, - .bus = BT_HCI_DRIVER_BUS_IPM, -#if defined(CONFIG_BT_DRIVER_QUIRK_NO_AUTO_DLE) - .quirks = BT_QUIRK_NO_AUTO_DLE, -#endif -}; - -static int bt_rpmsg_init(void) -{ - - int err; - - err = bt_hci_driver_register(&drv); - if (err < 0) { - LOG_ERR("Failed to register BT HIC driver (err %d)", err); - } - - return err; -} - -SYS_INIT(bt_rpmsg_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/drivers/bluetooth/hci/slz_hci.c b/drivers/bluetooth/hci/slz_hci.c index 9fe5cb5981cb7a3..0526cb02c40549c 100644 --- a/drivers/bluetooth/hci/slz_hci.c +++ b/drivers/bluetooth/hci/slz_hci.c @@ -117,6 +117,15 @@ static int slz_bt_send(struct net_buf *buf) return rv; } +static void slz_thread_func(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + slz_ll_thread_func(); +} + static int slz_bt_open(void) { int ret; @@ -124,7 +133,7 @@ static int slz_bt_open(void) /* Start RX thread */ k_thread_create(&slz_ll_thread, slz_ll_stack, K_KERNEL_STACK_SIZEOF(slz_ll_stack), - (k_thread_entry_t)slz_ll_thread_func, NULL, NULL, NULL, + slz_thread_func, NULL, NULL, NULL, K_PRIO_COOP(CONFIG_BT_DRIVER_RX_HIGH_PRIO), 0, K_NO_WAIT); diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index b86f9ba35fb2b2c..8177e0592612370 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -36,11 +36,13 @@ 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 #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 @@ -69,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); @@ -84,62 +86,8 @@ 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_HCI_DRIVER_LOG_LEVEL_DBG) -#include -static inline void spi_dump_message(const uint8_t *pre, uint8_t *buf, - uint8_t size) -{ - uint8_t i, c; - - printk("%s (%d): ", pre, size); - for (i = 0U; i < size; i++) { - c = buf[i]; - printk("%x ", c); - if (c >= 31U && c <= 126U) { - printk("[%c] ", c); - } else { - printk("[.] "); - } - } - printk("\n"); -} -#else -static inline -void spi_dump_message(const uint8_t *pre, uint8_t *buf, uint8_t size) {} -#endif - -#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 */ - -#if defined(CONFIG_BT_SPI_BLUENRG) -/* In case of BlueNRG-MS, it is necessary to prevent SPI driver to release CS, - * and instead, let current driver manage CS release. see kick_cs()/release_cs() - * So, add SPI_HOLD_ON_CS to operation field. - */ -static const struct spi_dt_spec bus = SPI_DT_SPEC_INST_GET( - 0, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8) | SPI_HOLD_ON_CS, 0); -#else 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); -#endif static struct spi_buf spi_tx_buf; static struct spi_buf spi_rx_buf; @@ -186,116 +134,121 @@ 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 int configure_cs(void) -{ - /* Configure pin as output and set to inactive */ - return gpio_pin_configure_dt(&bus.config.cs.gpio, GPIO_OUTPUT_INACTIVE); -} - -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) -{ - gpio_pin_set_dt(&bus.config.cs.gpio, 0); -} - -static bool irq_pin_high(void) +static int bt_spi_get_header(uint8_t op, uint16_t *size) { - int pin_state; - - pin_state = gpio_pin_get_dt(&irq_gpio); - - LOG_DBG("IRQ Pin: %d", pin_state); - - return pin_state > 0; -} + 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; -static void init_irq_high_loop(void) -{ - attempts = IRQ_HIGH_MAX_READ; -} + if (!(op == SPI_READ || op == SPI_WRITE)) { + return -EINVAL; + } + if (reading) { + size_offset = STATUS_HEADER_TOREAD; + } -static bool exit_irq_high_loop(void) -{ - /* Limit attempts on BlueNRG-MS as we might */ - /* enter this loop with nothing to read */ + 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); - attempts--; + *size = (reading ? header_slave[size_offset] : SPI_MAX_MSG_LEN); - return attempts; + return ret; } -#else - -#define configure_cs(...) 0 -#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) +static struct net_buf *bt_spi_rx_buf_construct(uint8_t *msg) { - struct bluenrg_aci_cmd_ll_param *param; + bool discardable = false; + k_timeout_t timeout = K_FOREVER; + struct bt_hci_acl_hdr acl_hdr; struct net_buf *buf; + int len; - buf = bt_hci_cmd_create(BLUENRG_ACI_WRITE_CONFIG_DATA, sizeof(*param)); - if (!buf) { - return -ENOBUFS; - } - - 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; + switch (msg[PACKET_TYPE]) { + 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; + } + } - bt_hci_cmd_send(BLUENRG_ACI_WRITE_CONFIG_DATA, buf); + 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 0; + return buf; } -#endif /* CONFIG_BT_BLUENRG_ACI */ -static void bt_spi_rx_thread(void) +static void bt_spi_rx_thread(void *p1, void *p2, void *p3) { - bool discardable = false; - k_timeout_t timeout = K_FOREVER; + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + struct net_buf *buf; - uint8_t header_master[5] = { SPI_READ, 0x00, 0x00, 0x00, 0x00 }; - uint8_t header_slave[5]; - struct bt_hci_acl_hdr acl_hdr; - uint8_t size = 0U; + uint16_t size = 0U; int ret; - int len; (void)memset(&txmsg, 0xFF, SPI_MAX_MSG_LEN); while (true) { @@ -305,109 +258,51 @@ static void bt_spi_rx_thread(void) 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); - } + /* Wait for SPI bus to be available */ + k_sem_take(&sem_busy, K_FOREVER); + ret = bt_spi_get_header(SPI_READ, &size); - release_cs(); - - 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); + } - spi_dump_message("RX:ed", rxmsg, size); - - switch (rxmsg[PACKET_TYPE]) { - case HCI_EVT: - switch (rxmsg[EVT_HEADER_EVENT]) { - case BT_HCI_EVT_VENDOR: - /* Run event through interface handler */ - if (bt_spi_handle_vendor_evt(rxmsg)) { - continue; - }; - /* Event has not yet been handled */ - __fallthrough; - default: - if (rxmsg[1] == BT_HCI_EVT_LE_META_EVENT && - (rxmsg[3] == BT_HCI_EVT_LE_ADVERTISING_REPORT)) { - discardable = true; - timeout = K_NO_WAIT; - } - - buf = bt_buf_get_evt(rxmsg[EVT_HEADER_EVENT], - discardable, timeout); - if (!buf) { - LOG_DBG("Discard adv report due to insufficient " - "buf"); - continue; - } - } + k_sem_give(&sem_busy); - len = sizeof(struct bt_hci_evt_hdr) + rxmsg[EVT_HEADER_SIZE]; - if (len > net_buf_tailroom(buf)) { - LOG_ERR("Event too long: %d", len); - net_buf_unref(buf); - continue; - } - net_buf_add_mem(buf, &rxmsg[1], len); - break; - case HCI_ACL: - buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER); - memcpy(&acl_hdr, &rxmsg[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); - continue; - } - net_buf_add_mem(buf, &rxmsg[1], len); - break; - default: - LOG_ERR("Unknown BT buf type %d", rxmsg[0]); - continue; + if (ret || size == 0) { + if (ret) { + LOG_ERR("Error %d", ret); } + continue; + } - bt_recv(buf); + 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[5] = { SPI_WRITE, 0x00, 0x00, 0x00, 0x00 }; + uint16_t size; + uint8_t rx_first[1]; int ret; LOG_DBG(""); @@ -434,29 +329,32 @@ 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, 5, rxmsg, 5); + ret = bt_spi_get_header(SPI_WRITE, &size); + size = MIN(buf->len, size); - /* - * RX Header (rxmsg) 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 ((rxmsg[STATUS_HEADER_READY] != READY_NOW || - (rxmsg[1] | rxmsg[2] | rxmsg[3] | rxmsg[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 */ - do { - ret = bt_spi_transceive(buf->data, buf->len, - rxmsg, buf->len); - } while (rxmsg[0] == 0U && !ret); + while (true) { + ret = bt_spi_transceive(buf->data, size, + rx_first, 1); + if (rx_first[0] != 0U || ret) { + break; + } + /* Consider increasing controller-data-delay-us + * if this message is extremely common. + */ + LOG_DBG("Controller not ready for SPI transaction of %d bytes", size); + } } - release_cs(); - k_sem_give(&sem_busy); if (ret) { @@ -464,20 +362,8 @@ static int bt_spi_send(struct net_buf *buf) goto out; } - spi_dump_message("TX:ed", buf->data, buf->len); - -#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 */ + LOG_HEXDUMP_DBG(buf->data, buf->len, "SPI TX"); + out: net_buf_unref(buf); @@ -507,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))); @@ -516,7 +405,7 @@ static int bt_spi_open(void) /* 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, + bt_spi_rx_thread, NULL, NULL, NULL, K_PRIO_COOP(CONFIG_BT_DRIVER_RX_HIGH_PRIO), 0, K_NO_WAIT); @@ -529,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, }; @@ -544,10 +430,6 @@ static int bt_spi_init(void) return -ENODEV; } - if (configure_cs()) { - return -EIO; - } - if (!gpio_is_ready_dt(&irq_gpio)) { LOG_ERR("IRQ GPIO device not ready"); return -ENODEV; diff --git a/drivers/cache/CMakeLists.txt b/drivers/cache/CMakeLists.txt index 47c790f0a890633..23cb11afb6a2d13 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 834cc49e1813914..4dcb64f488ae97f 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 000000000000000..820445db432f485 --- /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_handlers.c b/drivers/cache/cache_handlers.c index 99d7cec501cac21..2005124136f762d 100644 --- a/drivers/cache/cache_handlers.c +++ b/drivers/cache/cache_handlers.c @@ -5,11 +5,11 @@ */ #include -#include +#include static inline int z_vrfy_sys_cache_data_flush_range(void *addr, size_t size) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(addr, size)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(addr, size)); return z_impl_sys_cache_data_flush_range(addr, size); } @@ -17,7 +17,7 @@ static inline int z_vrfy_sys_cache_data_flush_range(void *addr, size_t size) static inline int z_vrfy_sys_cache_data_invd_range(void *addr, size_t size) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(addr, size)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(addr, size)); return z_impl_sys_cache_data_invd_range(addr, size); } @@ -25,7 +25,7 @@ static inline int z_vrfy_sys_cache_data_invd_range(void *addr, size_t size) static inline int z_vrfy_sys_cache_data_flush_and_invd_range(void *addr, size_t size) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(addr, size)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(addr, size)); return z_impl_sys_cache_data_flush_and_invd_range(addr, size); } diff --git a/drivers/cache/cache_nrf.c b/drivers/cache/cache_nrf.c new file mode 100644 index 000000000000000..63d76a47d6ef88d --- /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 84367884603a815..4e6429135a9a903 100644 --- a/drivers/can/CMakeLists.txt +++ b/drivers/can/CMakeLists.txt @@ -20,22 +20,8 @@ zephyr_library_sources_ifdef(CONFIG_CAN_STM32_FDCAN can_stm32_fdcan.c) 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) - -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_NUMAKER can_numaker.c) +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 +30,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 6937900e8f9d108..056781d27b43a9f 100644 --- a/drivers/can/Kconfig +++ b/drivers/can/Kconfig @@ -25,7 +25,6 @@ config CAN_INIT_PRIORITY config CAN_SHELL bool "CAN shell" - default y depends on SHELL select POLL help @@ -55,10 +54,17 @@ 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" + bool "CAN FD" help - Enable CAN-FD support. Not all CAN controllers support CAN-FD. + Enable CAN FD support. Not all CAN controllers support CAN FD. config CAN_RX_TIMESTAMP bool "Receiving timestamps" @@ -92,8 +98,9 @@ source "drivers/can/Kconfig.mcux" source "drivers/can/Kconfig.mcp2515" 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/Kconfig.mspm0g3xxx" source "drivers/can/transceiver/Kconfig" diff --git a/drivers/can/Kconfig.mcan b/drivers/can/Kconfig.mcan index 6b25df34567e22c..83cf6ffaba084ae 100644 --- a/drivers/can/Kconfig.mcan +++ b/drivers/can/Kconfig.mcan @@ -9,7 +9,7 @@ config CAN_MCAN Enable Bosch m_can driver. This driver supports the Bosch m_can IP. This IP is built into the STM32G4, STM32G0, STM32H7, and the Microchip SAM controllers with - CAN-FD. + CAN FD. if CAN_MCAN diff --git a/drivers/can/Kconfig.mcp251xfd b/drivers/can/Kconfig.mcp251xfd index 8e6cb5ad91c3e06..128becf8e95b6e8 100644 --- a/drivers/can/Kconfig.mcp251xfd +++ b/drivers/can/Kconfig.mcp251xfd @@ -54,7 +54,7 @@ config CAN_MCP251XFD_READ_CRC_RETRIES config CAN_MAX_FILTER int "Maximum number of concurrent active filters" default 5 - range 1 31 + range 1 32 help Maximum number of filters supported by the can_add_rx_callback() API call. diff --git a/drivers/can/Kconfig.mcux b/drivers/can/Kconfig.mcux index 67ab4c26873ff7c..7df67684e8a7c7b 100644 --- a/drivers/can/Kconfig.mcux +++ b/drivers/can/Kconfig.mcux @@ -19,7 +19,7 @@ config CAN_MCUX_FLEXCAN_FD default y depends on DT_HAS_NXP_FLEXCAN_FD_ENABLED && CAN_FD_MODE help - Enable support for CAN-FD capable NXP FlexCAN devices. + Enable support for CAN FD capable NXP FlexCAN devices. config CAN_MCUX_FLEXCAN_WAIT_TIMEOUT int "Maximum number of wait loop iterations" @@ -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_S32K3_M7 - 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. @@ -42,7 +44,9 @@ config CAN_MAX_FILTER range 1 15 if SOC_SERIES_KINETIS_KE1XF || SOC_SERIES_KINETIS_K6X 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_S32K3_M7 + 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 000000000000000..54969fd7de11f91 --- /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 c6719e1de49e5f2..000000000000000 --- 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.numaker b/drivers/can/Kconfig.numaker new file mode 100644 index 000000000000000..23de8ab50ecd8e1 --- /dev/null +++ b/drivers/can/Kconfig.numaker @@ -0,0 +1,13 @@ +# NuMaker CAN(-FD) driver configuration options + +# Copyright (c) 2023 Nuvoton Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +config CAN_NUMAKER + bool "Nuvoton NuMaker CAN FD driver" + default y + select CAN_MCAN + depends on DT_HAS_NUVOTON_NUMAKER_CANFD_ENABLED + depends on SOC_SERIES_M46X + help + Enables Nuvoton NuMaker CAN FD driver, using Bosch M_CAN diff --git a/drivers/can/Kconfig.nxp_s32 b/drivers/can/Kconfig.nxp_s32 index 53c1ffc2b8bded3..09727d719efea28 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 000000000000000..2fbb5df70645657 --- /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 2fd379d00497e94..11c30a2338c4dd4 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 cdc2fd34a86dbc1..f2845bbee9b92f0 100644 --- a/drivers/can/can_fake.c +++ b/drivers/can/can_fake.c @@ -9,12 +9,20 @@ #include #include -#ifdef CONFIG_ZTEST_NEW_API +#ifdef CONFIG_ZTEST #include -#endif /* CONFIG_ZTEST_NEW_API */ +#endif /* CONFIG_ZTEST */ #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,7 +54,7 @@ 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); -#ifdef CONFIG_ZTEST_NEW_API +#ifdef CONFIG_ZTEST static void fake_can_reset_rule_before(const struct ztest_unit_test *test, void *fixture) { ARG_UNUSED(test); @@ -68,7 +76,7 @@ static void fake_can_reset_rule_before(const struct ztest_unit_test *test, void } ZTEST_RULE(fake_can_reset_rule, fake_can_reset_rule_before, NULL); -#endif /* CONFIG_ZTEST_NEW_API */ +#endif /* CONFIG_ZTEST */ static int fake_can_get_core_clock(const struct device *dev, uint32_t *rate) { @@ -79,15 +87,6 @@ static int fake_can_get_core_clock(const struct device *dev, uint32_t *rate) 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 +103,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 +137,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 e5a8d57b6aa21a4..aa0a62674cb736b 100644 --- a/drivers/can/can_handlers.c +++ b/drivers/can/can_handlers.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include static int z_vrfy_can_calc_timing(const struct device *dev, struct can_timing *res, @@ -13,11 +13,11 @@ static int z_vrfy_can_calc_timing(const struct device *dev, struct can_timing *r struct can_timing res_copy; int err; - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, get_core_clock)); - Z_OOPS(z_user_from_copy(&res_copy, res, sizeof(res_copy))); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, get_core_clock)); + K_OOPS(k_usermode_from_copy(&res_copy, res, sizeof(res_copy))); err = z_impl_can_calc_timing(dev, &res_copy, bitrate, sample_pnt); - Z_OOPS(z_user_to_copy(res, &res_copy, sizeof(*res))); + K_OOPS(k_usermode_to_copy(res, &res_copy, sizeof(*res))); return err; } @@ -28,8 +28,8 @@ static inline int z_vrfy_can_set_timing(const struct device *dev, { struct can_timing timing_copy; - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, set_timing)); - Z_OOPS(z_user_from_copy(&timing_copy, timing, sizeof(timing_copy))); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, set_timing)); + K_OOPS(k_usermode_from_copy(&timing_copy, timing, sizeof(timing_copy))); return z_impl_can_set_timing(dev, &timing_copy); } @@ -38,8 +38,8 @@ static inline int z_vrfy_can_set_timing(const struct device *dev, static inline int z_vrfy_can_get_core_clock(const struct device *dev, uint32_t *rate) { - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, get_core_clock)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(rate, sizeof(*rate))); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, get_core_clock)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(rate, sizeof(*rate))); return z_impl_can_get_core_clock(dev, rate); } @@ -48,9 +48,8 @@ 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 */ - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(max_bitrate, sizeof(*max_bitrate))); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(max_bitrate, sizeof(*max_bitrate))); return z_impl_can_get_max_bitrate(dev, max_bitrate); } @@ -58,7 +57,7 @@ static inline int z_vrfy_can_get_max_bitrate(const struct device *dev, static inline const struct can_timing *z_vrfy_can_get_timing_min(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); return z_impl_can_get_timing_min(dev); } @@ -66,7 +65,7 @@ static inline const struct can_timing *z_vrfy_can_get_timing_min(const struct de static inline const struct can_timing *z_vrfy_can_get_timing_max(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); return z_impl_can_get_timing_max(dev); } @@ -80,11 +79,11 @@ static int z_vrfy_can_calc_timing_data(const struct device *dev, struct can_timi struct can_timing res_copy; int err; - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, get_core_clock)); - Z_OOPS(z_user_from_copy(&res_copy, res, sizeof(res_copy))); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, get_core_clock)); + K_OOPS(k_usermode_from_copy(&res_copy, res, sizeof(res_copy))); err = z_impl_can_calc_timing_data(dev, &res_copy, bitrate, sample_pnt); - Z_OOPS(z_user_to_copy(res, &res_copy, sizeof(*res))); + K_OOPS(k_usermode_to_copy(res, &res_copy, sizeof(*res))); return err; } @@ -92,7 +91,7 @@ static int z_vrfy_can_calc_timing_data(const struct device *dev, struct can_timi static inline const struct can_timing *z_vrfy_can_get_timing_data_min(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); return z_impl_can_get_timing_data_min(dev); } @@ -100,7 +99,7 @@ static inline const struct can_timing *z_vrfy_can_get_timing_data_min(const stru static inline const struct can_timing *z_vrfy_can_get_timing_data_max(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); return z_impl_can_get_timing_data_max(dev); } @@ -111,8 +110,8 @@ static inline int z_vrfy_can_set_timing_data(const struct device *dev, { struct can_timing timing_data_copy; - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, set_timing_data)); - Z_OOPS(z_user_from_copy(&timing_data_copy, timing_data, sizeof(timing_data_copy))); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, set_timing_data)); + K_OOPS(k_usermode_from_copy(&timing_data_copy, timing_data, sizeof(timing_data_copy))); return z_impl_can_set_timing_data(dev, &timing_data_copy); } @@ -121,7 +120,7 @@ static inline int z_vrfy_can_set_timing_data(const struct device *dev, static inline int z_vrfy_can_set_bitrate_data(const struct device *dev, uint32_t bitrate_data) { - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, set_timing_data)); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, set_timing_data)); return z_impl_can_set_bitrate_data(dev, bitrate_data); } @@ -132,7 +131,7 @@ static inline int z_vrfy_can_set_bitrate_data(const struct device *dev, static inline int z_vrfy_can_get_max_filters(const struct device *dev, bool ide) { /* Optional API function */ - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); return z_impl_can_get_max_filters(dev, ide); } @@ -140,16 +139,24 @@ static inline int z_vrfy_can_get_max_filters(const struct device *dev, bool ide) static inline int z_vrfy_can_get_capabilities(const struct device *dev, can_mode_t *cap) { - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, get_capabilities)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(cap, sizeof(*cap))); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, get_capabilities)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(cap, sizeof(*cap))); return z_impl_can_get_capabilities(dev, cap); } #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) { - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, start)); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, start)); return z_impl_can_start(dev); } @@ -157,7 +164,7 @@ static inline int z_vrfy_can_start(const struct device *dev) static inline int z_vrfy_can_stop(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, stop)); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, stop)); return z_impl_can_stop(dev); } @@ -165,15 +172,23 @@ static inline int z_vrfy_can_stop(const struct device *dev) static inline int z_vrfy_can_set_mode(const struct device *dev, can_mode_t mode) { - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, set_mode)); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, set_mode)); return z_impl_can_set_mode(dev, 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) { - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, set_timing)); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, set_timing)); return z_impl_can_set_bitrate(dev, bitrate); } @@ -187,9 +202,9 @@ static inline int z_vrfy_can_send(const struct device *dev, { struct can_frame frame_copy; - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, send)); - Z_OOPS(z_user_from_copy(&frame_copy, frame, sizeof(frame_copy))); - Z_OOPS(Z_SYSCALL_VERIFY_MSG(callback == NULL, "callbacks may not be set from user mode")); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, send)); + K_OOPS(k_usermode_from_copy(&frame_copy, frame, sizeof(frame_copy))); + K_OOPS(K_SYSCALL_VERIFY_MSG(callback == NULL, "callbacks may not be set from user mode")); return z_impl_can_send(dev, &frame_copy, timeout, callback, user_data); } @@ -201,9 +216,9 @@ static inline int z_vrfy_can_add_rx_filter_msgq(const struct device *dev, { struct can_filter filter_copy; - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, add_rx_filter)); - Z_OOPS(Z_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); - Z_OOPS(z_user_from_copy(&filter_copy, filter, sizeof(filter_copy))); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, add_rx_filter)); + K_OOPS(K_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); + K_OOPS(k_usermode_from_copy(&filter_copy, filter, sizeof(filter_copy))); return z_impl_can_add_rx_filter_msgq(dev, msgq, &filter_copy); } @@ -211,7 +226,7 @@ static inline int z_vrfy_can_add_rx_filter_msgq(const struct device *dev, static inline void z_vrfy_can_remove_rx_filter(const struct device *dev, int filter_id) { - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, remove_rx_filter)); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, remove_rx_filter)); z_impl_can_remove_rx_filter(dev, filter_id); } @@ -220,14 +235,14 @@ static inline void z_vrfy_can_remove_rx_filter(const struct device *dev, int fil static inline int z_vrfy_can_get_state(const struct device *dev, enum can_state *state, struct can_bus_err_cnt *err_cnt) { - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, get_state)); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, get_state)); if (state != NULL) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(state, sizeof(*state))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(state, sizeof(*state))); } if (err_cnt != NULL) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(err_cnt, sizeof(*err_cnt))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(err_cnt, sizeof(*err_cnt))); } return z_impl_can_get_state(dev, state, err_cnt); @@ -237,9 +252,77 @@ static inline int z_vrfy_can_get_state(const struct device *dev, enum can_state #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY static inline int z_vrfy_can_recover(const struct device *dev, k_timeout_t timeout) { - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, recover)); + K_OOPS(K_SYSCALL_DRIVER_CAN(dev, recover)); return z_impl_can_recover(dev, timeout); } #include #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ + +#ifdef CONFIG_CAN_STATS + +static inline uint32_t z_vrfy_can_stats_get_bit_errors(const struct device *dev) +{ + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + + return z_impl_can_stats_get_bit_errors(dev); +} +#include + +static inline uint32_t z_vrfy_can_stats_get_bit0_errors(const struct device *dev) +{ + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + + return z_impl_can_stats_get_bit0_errors(dev); +} +#include + +static inline uint32_t z_vrfy_can_stats_get_bit1_errors(const struct device *dev) +{ + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + + return z_impl_can_stats_get_bit1_errors(dev); +} +#include + +static inline uint32_t z_vrfy_can_stats_get_stuff_errors(const struct device *dev) +{ + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + + return z_impl_can_stats_get_stuff_errors(dev); +} +#include + +static inline uint32_t z_vrfy_can_stats_get_crc_errors(const struct device *dev) +{ + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + + return z_impl_can_stats_get_crc_errors(dev); +} +#include + +static inline uint32_t z_vrfy_can_stats_get_form_errors(const struct device *dev) +{ + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + + return z_impl_can_stats_get_form_errors(dev); +} +#include + +static inline uint32_t z_vrfy_can_stats_get_ack_errors(const struct device *dev) +{ + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + + return z_impl_can_stats_get_ack_errors(dev); +} +#include + +static inline uint32_t z_vrfy_can_stats_get_rx_overruns(const struct device *dev) +{ + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + + return z_impl_can_stats_get_rx_overruns(dev); +} +#include + +#endif /* CONFIG_CAN_STATS */ diff --git a/drivers/can/can_kvaser_pci.c b/drivers/can/can_kvaser_pci.c index 2aa002efd8ceb44..909b29a0a34b78c 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 8eb4074cc450f93..ffab53b315eed60 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; } @@ -211,7 +212,7 @@ static void can_loopback_remove_rx_filter(const struct device *dev, int filter_i { struct can_loopback_data *data = dev->data; - if (filter_id >= ARRAY_SIZE(data->filters)) { + if (filter_id < 0 || filter_id >= ARRAY_SIZE(data->filters)) { LOG_ERR("filter ID %d out-of-bounds", filter_id); return; } @@ -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 550f29b2334d7bb..886f959b29a52d1 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,8 +857,9 @@ 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)) { - LOG_ERR("CAN-FD format not supported in non-FD mode"); + 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; } #else /* CONFIG_CAN_FD_MODE */ @@ -900,7 +877,7 @@ int can_mcan_send(const struct device *dev, const struct can_frame *frame, k_tim if ((frame->flags & CAN_FRAME_FDF) != 0U) { if (frame->dlc > CANFD_MAX_DLC) { - LOG_ERR("DLC of %d for CAN-FD format frame", frame->dlc); + LOG_ERR("DLC of %d for CAN FD format frame", frame->dlc); return -EINVAL; } } else { @@ -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; } @@ -1149,12 +1119,17 @@ void can_mcan_remove_rx_filter(const struct device *dev, int filter_id) struct can_mcan_data *data = dev->data; int err; + if (filter_id < 0) { + LOG_ERR("filter ID %d out of bounds", filter_id); + return; + } + k_mutex_lock(&data->lock, K_FOREVER); if (filter_id >= cbs->num_std) { filter_id -= cbs->num_std; if (filter_id >= cbs->num_ext) { - LOG_ERR("Wrong filter id"); + LOG_ERR("filter ID %d out of bounds", filter_id); k_mutex_unlock(&data->lock); return; } @@ -1188,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 @@ -1349,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; } @@ -1439,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; @@ -1459,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; @@ -1479,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 703aeb1543dd94b..750273fc7154ff9 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,30 +430,32 @@ 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; } } + CAN_STATS_RESET(dev); + k_mutex_lock(&dev_data->mutex, K_FOREVER); ret = mcp2515_set_mode_int(dev, dev_data->mcp2515_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); @@ -477,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; } @@ -502,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); @@ -510,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; @@ -525,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; } @@ -544,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; } @@ -572,7 +567,7 @@ static int mcp2515_send(const struct device *dev, return -ENOTSUP; } - if (!dev_data->started) { + if (!dev_data->common.started) { return -ENETDOWN; } @@ -627,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; } @@ -661,6 +656,11 @@ static void mcp2515_remove_rx_filter(const struct device *dev, int filter_id) { struct mcp2515_data *dev_data = dev->data; + if (filter_id < 0 || filter_id >= CONFIG_CAN_MAX_FILTER) { + LOG_ERR("filter ID %d out of bounds", filter_id); + return; + } + k_mutex_lock(&dev_data->mutex, K_FOREVER); dev_data->filter_usage &= ~BIT(filter_id); k_mutex_unlock(&dev_data->mutex); @@ -672,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, @@ -684,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++) { @@ -737,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; @@ -762,14 +768,28 @@ static int mcp2515_get_state(const struct device *dev, enum can_state *state, err_cnt->rx_err_cnt = err_cnt_buf[1]; } +#ifdef CONFIG_CAN_STATS + if ((eflg & (MCP2515_EFLG_RX0OVR | MCP2515_EFLG_RX1OVR)) != 0U) { + CAN_STATS_RX_OVERRUN_INC(dev); + + ret = mcp2515_cmd_bit_modify(dev, MCP2515_ADDR_EFLG, + eflg & (MCP2515_EFLG_RX0OVR | MCP2515_EFLG_RX1OVR), + 0U); + if (ret < 0) { + LOG_ERR("Failed to clear RX overrun flags [%d]", ret); + return -EIO; + } + } +#endif /* CONFIG_CAN_STATS */ + return 0; } 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; @@ -793,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; } @@ -868,8 +888,12 @@ static void mcp2515_handle_interrupts(const struct device *dev) } } -static void mcp2515_int_thread(const struct device *dev) +static void mcp2515_int_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; struct mcp2515_data *dev_data = dev->data; while (1) { @@ -903,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, @@ -933,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; } @@ -977,7 +1000,7 @@ static int mcp2515_init(const struct device *dev) tid = k_thread_create(&dev_data->int_thread, dev_data->int_thread_stack, dev_cfg->int_thread_stack_size, - (k_thread_entry_t) mcp2515_int_thread, (void *)dev, + mcp2515_int_thread, (void *)dev, NULL, NULL, K_PRIO_COOP(dev_cfg->int_thread_priority), 0, K_NO_WAIT); (void)k_thread_name_set(tid, "mcp2515"); @@ -986,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; @@ -1001,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); } @@ -1030,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, \ @@ -1038,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 f8e2921ba63903e..2582e19daa3c2f9 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 3f94ed52319bac2..81d2820f1f74722 100644 --- a/drivers/can/can_mcp251xfd.c +++ b/drivers/can/can_mcp251xfd.c @@ -191,8 +191,10 @@ static int mcp251xfd_fifo_write(const struct device *dev, int mailbox_idx, txobj = mcp251xfd_get_spi_buf_ptr(dev); mcp251xfd_canframe_to_txobj(msg, mailbox_idx, txobj); - tx_len = MCP251XFD_OBJ_HEADER_SIZE + - ROUND_UP(can_dlc_to_bytes(msg->dlc), MCP251XFD_RAM_ALIGNMENT); + tx_len = MCP251XFD_OBJ_HEADER_SIZE; + if ((msg->flags & CAN_FRAME_RTR) == 0) { + tx_len += ROUND_UP(can_dlc_to_bytes(msg->dlc), MCP251XFD_RAM_ALIGNMENT); + } ret = mcp251xfd_write(dev, address, tx_len); if (ret < 0) { @@ -295,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)) { @@ -304,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); } @@ -377,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; } @@ -406,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; } @@ -415,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) { @@ -450,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; } @@ -464,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); @@ -500,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; } @@ -513,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; } @@ -556,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; @@ -574,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); @@ -598,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) { @@ -676,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, @@ -685,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); @@ -695,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; @@ -745,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) { @@ -761,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; } @@ -917,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); @@ -939,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: @@ -971,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); } @@ -1035,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; @@ -1167,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; @@ -1187,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); @@ -1207,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; } @@ -1241,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; @@ -1264,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); @@ -1295,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; } @@ -1321,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); } @@ -1333,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); } @@ -1349,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) { @@ -1372,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 @@ -1381,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); } @@ -1396,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); } @@ -1408,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); } @@ -1420,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); } @@ -1435,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); @@ -1455,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); } @@ -1556,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 @@ -1676,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, @@ -1715,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) @@ -1742,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), \ \ @@ -1752,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, \ @@ -1767,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 f0414103bedf3b1..475f91583c2bd8f 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 */ @@ -496,20 +496,17 @@ struct mcp251xfd_data { struct mcp251xfd_mailbox mailbox[CONFIG_CAN_MCP251XFD_MAX_TX_QUEUE]; /* Filter Data */ - uint64_t filter_usage; + uint32_t filter_usage; struct can_filter filter[CONFIG_CAN_MAX_FILTER]; can_rx_callback_t rx_cb[CONFIG_CAN_MAX_FILTER]; void *cb_arg[CONFIG_CAN_MAX_FILTER]; 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 a80204e28c5e4d2..cf09ef23ec7ac4a 100644 --- a/drivers/can/can_mcux_flexcan.c +++ b/drivers/can/can_mcux_flexcan.c @@ -7,7 +7,7 @@ /* Base driver compatible */ #define DT_DRV_COMPAT nxp_flexcan -/* CAN-FD extension compatible */ +/* CAN FD extension compatible */ #define FLEXCAN_FD_DRV_COMPAT nxp_flexcan_fd #include @@ -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; } @@ -443,7 +423,7 @@ static int mcux_flexcan_set_mode(const struct device *dev, can_mode_t mode) } if ((mode & CAN_MODE_FD) != 0 && (mode & CAN_MODE_3_SAMPLES) != 0) { - LOG_ERR("triple samling is not supported in CAN-FD mode"); + LOG_ERR("triple samling is not supported in CAN FD mode"); return -ENOTSUP; } @@ -479,9 +459,8 @@ static int mcux_flexcan_set_mode(const struct device *dev, can_mode_t mode) #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD if (config->flexcan_fd) { if ((mode & CAN_MODE_FD) != 0) { - /* Enable CAN-FD mode */ + /* 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) { @@ -490,9 +469,8 @@ static int mcux_flexcan_set_mode(const struct device *dev, can_mode_t mode) config->base->FDCTRL |= CAN_FDCTRL_TDCEN_MASK; } } else { - /* Disable CAN-FD mode */ + /* 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) { + /* Defer starting FlexCAN FD MBs unless 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; } @@ -922,9 +888,8 @@ static void mcux_flexcan_remove_rx_filter(const struct device *dev, int filter_i { struct mcux_flexcan_data *data = dev->data; - if (filter_id >= MCUX_FLEXCAN_MAX_RX) { - LOG_ERR("Detach: Filter id >= MAX_RX (%d >= %d)", filter_id, - MCUX_FLEXCAN_MAX_RX); + if (filter_id < 0 || filter_id >= MCUX_FLEXCAN_MAX_RX) { + LOG_ERR("filter ID %d out of bounds", filter_id); return; } @@ -934,8 +899,8 @@ static void mcux_flexcan_remove_rx_filter(const struct device *dev, int filter_i #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD const struct mcux_flexcan_config *config = dev->config; - /* Stop FlexCAN-FD MBs unless already in stopped mode */ - if (!config->flexcan_fd || data->started) { + /* Stop FlexCAN FD MBs unless already in stopped mode */ + 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 @@ -956,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; @@ -1006,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 { @@ -1062,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, @@ -1126,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 */ @@ -1169,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; } @@ -1187,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; @@ -1203,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); } @@ -1219,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; @@ -1235,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); } @@ -1339,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. @@ -1383,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 @@ -1470,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 eb382c952929d78..28a709a023c0a38 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 000000000000000..940123bdd92f8d2 --- /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 000000000000000..1ec6f399e07fec3 --- /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 000000000000000..8d19b34a198519f --- /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 d03ca78841e2adc..000000000000000 --- a/drivers/can/can_native_posix_linux.c +++ /dev/null @@ -1,496 +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)) { - 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 56295a8f8438d93..000000000000000 --- 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 76db602af989573..000000000000000 --- 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 new file mode 100644 index 000000000000000..ba51b8b82fd3a60 --- /dev/null +++ b/drivers/can/can_numaker.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_numaker_canfd + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(can_numaker, CONFIG_CAN_LOG_LEVEL); + +/* CANFD Clock Source Selection */ +#define NUMAKER_CANFD_CLKSEL_HXT 0 +#define NUMAKER_CANFD_CLKSEL_PLL_DIV2 1 +#define NUMAKER_CANFD_CLKSEL_HCLK 2 +#define NUMAKER_CANFD_CLKSEL_HIRC 3 + +/* Implementation notes + * 1. Use Bosch M_CAN driver (m_can) as backend + * 2. Need to modify can_numaker_get_core_clock() for new SOC support + */ + +struct can_numaker_config { + mm_reg_t canfd_base; + mem_addr_t mrba; + mem_addr_t mram; + const struct reset_dt_spec reset; + uint32_t clk_modidx; + uint32_t clk_src; + uint32_t clk_div; + const struct device *clk_dev; + void (*irq_config_func)(const struct device *dev); + const struct pinctrl_dev_config *pincfg; +}; + +static int can_numaker_get_core_clock(const struct device *dev, uint32_t *rate) +{ + const struct can_mcan_config *mcan_config = dev->config; + const struct can_numaker_config *config = mcan_config->custom; + uint32_t clksrc_rate_idx; + uint32_t clkdiv_divider; + + /* Module clock source rate */ + clksrc_rate_idx = CLK_GetModuleClockSource(config->clk_modidx); + /* Module clock divider */ + clkdiv_divider = CLK_GetModuleClockDivider(config->clk_modidx) + 1; + + switch (clksrc_rate_idx) { + case NUMAKER_CANFD_CLKSEL_HXT: + *rate = __HXT / clkdiv_divider; + break; + case NUMAKER_CANFD_CLKSEL_PLL_DIV2: + *rate = (CLK_GetPLLClockFreq() / 2) / clkdiv_divider; + break; + case NUMAKER_CANFD_CLKSEL_HCLK: + *rate = CLK_GetHCLKFreq() / clkdiv_divider; + break; + case NUMAKER_CANFD_CLKSEL_HIRC: + *rate = __HIRC / clkdiv_divider; + break; + default: + LOG_ERR("Invalid clock source rate index"); + return -EIO; + } + + LOG_DBG("Clock rate index/divider: %d/%d", clksrc_rate_idx, clkdiv_divider); + + return 0; +} + +static inline int can_numaker_init_unlocked(const struct device *dev) +{ + const struct can_mcan_config *mcan_config = dev->config; + const struct can_numaker_config *config = mcan_config->custom; + struct numaker_scc_subsys scc_subsys; + int rc; + + 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; + + /* To enable clock */ + rc = clock_control_on(config->clk_dev, (clock_control_subsys_t) &scc_subsys); + if (rc < 0) { + return rc; + } + /* To set module clock */ + rc = clock_control_configure(config->clk_dev, (clock_control_subsys_t)&scc_subsys, NULL); + if (rc < 0) { + return rc; + } + + /* Configure pinmux (NuMaker's SYS MFP) */ + rc = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (rc < 0) { + return rc; + } + + /* Reset CAN to default state, same as BSP's SYS_ResetModule(id_rst) */ + reset_line_toggle_dt(&config->reset); + + config->irq_config_func(dev); + + rc = can_mcan_configure_mram(dev, config->mrba, config->mram); + if (rc != 0) { + return rc; + } + + rc = can_mcan_init(dev); + if (rc < 0) { + LOG_ERR("Failed to initialize mcan: %d", rc); + return rc; + } + +#if CONFIG_CAN_LOG_LEVEL >= LOG_LEVEL_DBG + uint32_t rate; + + rc = can_numaker_get_core_clock(dev, &rate); + if (rc < 0) { + return rc; + } + + LOG_DBG("CAN core clock: %d", rate); +#endif + + return rc; +} + +static int can_numaker_init(const struct device *dev) +{ + const struct can_mcan_config *mcan_config = dev->config; + const struct can_numaker_config *config = mcan_config->custom; + int rc; + + if (!device_is_ready(config->reset.dev)) { + LOG_ERR("reset controller not ready"); + return -ENODEV; + } + + if (!device_is_ready(config->clk_dev)) { + LOG_ERR("clock controller not ready"); + return -ENODEV; + } + + SYS_UnlockReg(); + rc = can_numaker_init_unlocked(dev); + SYS_LockReg(); + + return rc; +} + +static const struct can_driver_api can_numaker_driver_api = { + .get_capabilities = can_mcan_get_capabilities, + .start = can_mcan_start, + .stop = can_mcan_stop, + .set_mode = can_mcan_set_mode, + .set_timing = can_mcan_set_timing, + .send = can_mcan_send, + .add_rx_filter = can_mcan_add_rx_filter, + .remove_rx_filter = can_mcan_remove_rx_filter, +#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY + .recover = can_mcan_recover, +#endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ + .get_state = can_mcan_get_state, + .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, + .timing_min = CAN_MCAN_TIMING_MIN_INITIALIZER, + .timing_max = CAN_MCAN_TIMING_MAX_INITIALIZER, +#ifdef CONFIG_CAN_FD_MODE + .set_timing_data = can_mcan_set_timing_data, + .timing_data_min = CAN_MCAN_TIMING_DATA_MIN_INITIALIZER, + .timing_data_max = CAN_MCAN_TIMING_DATA_MAX_INITIALIZER, +#endif /* CONFIG_CAN_FD_MODE */ +}; + +static int can_numaker_read_reg(const struct device *dev, uint16_t reg, uint32_t *val) +{ + const struct can_mcan_config *mcan_cfg = dev->config; + const struct can_numaker_config *numaker_cfg = mcan_cfg->custom; + + return can_mcan_sys_read_reg(numaker_cfg->canfd_base, reg, val); +} + +static int can_numaker_write_reg(const struct device *dev, uint16_t reg, uint32_t val) +{ + const struct can_mcan_config *mcan_cfg = dev->config; + const struct can_numaker_config *numaker_cfg = mcan_cfg->custom; + + return can_mcan_sys_write_reg(numaker_cfg->canfd_base, reg, val); +} + +static int can_numaker_read_mram(const struct device *dev, uint16_t offset, void *dst, size_t len) +{ + const struct can_mcan_config *mcan_cfg = dev->config; + const struct can_numaker_config *numaker_cfg = mcan_cfg->custom; + + return can_mcan_sys_read_mram(numaker_cfg->mram, offset, dst, len); +} + +static int can_numaker_write_mram(const struct device *dev, uint16_t offset, const void *src, + size_t len) +{ + const struct can_mcan_config *mcan_cfg = dev->config; + const struct can_numaker_config *numaker_cfg = mcan_cfg->custom; + + return can_mcan_sys_write_mram(numaker_cfg->mram, offset, src, len); +} + +static int can_numaker_clear_mram(const struct device *dev, uint16_t offset, size_t len) +{ + const struct can_mcan_config *mcan_cfg = dev->config; + const struct can_numaker_config *numaker_cfg = mcan_cfg->custom; + + return can_mcan_sys_clear_mram(numaker_cfg->mram, offset, len); +} + +static const struct can_mcan_ops can_numaker_ops = { + .read_reg = can_numaker_read_reg, + .write_reg = can_numaker_write_reg, + .read_mram = can_numaker_read_mram, + .write_mram = can_numaker_write_mram, + .clear_mram = can_numaker_clear_mram, +}; + +#define NUMAKER_CLKCTRL_DEV_INIT(inst) \ + .clk_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(inst))), + +#define NUMAKER_PINCTRL_DEFINE(inst) \ + PINCTRL_DT_INST_DEFINE(inst); +#define NUMAKER_PINCTRL_INIT(inst) \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), + +#define CAN_NUMAKER_INIT(inst) \ + NUMAKER_PINCTRL_DEFINE(inst); \ + CAN_MCAN_DT_INST_CALLBACKS_DEFINE(inst, can_numaker_cbs_##inst); \ + \ + static void can_numaker_irq_config_func_##inst(const struct device *dev) \ + { \ + 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, 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, int1, irq)); \ + } \ + \ + static const struct can_numaker_config can_numaker_config_##inst = { \ + .canfd_base = CAN_MCAN_DT_INST_MCAN_ADDR(inst), \ + .mrba = CAN_MCAN_DT_INST_MRBA(inst), \ + .mram = CAN_MCAN_DT_INST_MRAM_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), \ + NUMAKER_CLKCTRL_DEV_INIT(inst) \ + .irq_config_func = can_numaker_irq_config_func_##inst, \ + NUMAKER_PINCTRL_INIT(inst) \ + }; \ + \ + static const struct can_mcan_config can_mcan_config_##inst = \ + CAN_MCAN_DT_CONFIG_INST_GET(inst, \ + &can_numaker_config_##inst, \ + &can_numaker_ops, \ + &can_numaker_cbs_##inst); \ + \ + static uint32_t can_numaker_data_##inst; \ + \ + static struct can_mcan_data can_mcan_data_##inst = \ + CAN_MCAN_DATA_INITIALIZER(&can_numaker_data_ ## inst); \ + \ + CAN_DEVICE_DT_INST_DEFINE(inst, \ + can_numaker_init, \ + NULL, \ + &can_mcan_data_##inst, \ + &can_mcan_config_##inst, \ + POST_KERNEL, \ + CONFIG_CAN_INIT_PRIORITY, \ + &can_numaker_driver_api); \ + +DT_INST_FOREACH_STATUS_OKAY(CAN_NUMAKER_INIT); diff --git a/drivers/can/can_nxp_s32_canxl.c b/drivers/can/can_nxp_s32_canxl.c index a4ab50838cbdc9e..2076429e2792de8 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; } @@ -396,14 +456,28 @@ static void can_nxp_s32_remove_rx_filter(const struct device *dev, int filter_id struct can_nxp_s32_data *data = dev->data; int mb_indx = ALLOC_IDX_TO_RXMB_IDX(filter_id); - __ASSERT_NO_MSG(filter_id >= 0 && filter_id < CONFIG_CAN_NXP_S32_MAX_RX); + if (filter_id < 0 || filter_id >= CONFIG_CAN_NXP_S32_MAX_RX) { + LOG_ERR("filter ID %d out of bounds", filter_id); + return; + } 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; @@ -427,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; } @@ -455,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); @@ -480,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); @@ -503,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; @@ -511,13 +601,13 @@ static int can_nxp_s32_send(const struct device *dev, if ((frame->flags & CAN_FRAME_FDF) != 0 && (config->base_sic->BCFG2 & CANXL_SIC_BCFG2_FDEN_MASK) == 0) { - LOG_ERR("CAN-FD format not supported in non-FD mode"); + LOG_ERR("CAN FD format not supported in non-FD mode"); return -ENOTSUP; } if ((frame->flags & CAN_FRAME_BRS) != 0 && ~(config->base_sic->BCFG1 & CANXL_SIC_BCFG1_FDRSDIS_MASK) == 0) { - LOG_ERR("CAN-FD BRS not supported in non-FD mode"); + LOG_ERR("CAN FD BRS not supported in non-FD mode"); return -ENOTSUP; } #else @@ -538,16 +628,16 @@ 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); + LOG_ERR("DLC of %d for CAN FD format frame", frame->dlc); return -EINVAL; } #endif } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -627,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; } @@ -639,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) { @@ -647,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; } @@ -669,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; @@ -700,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); } } @@ -772,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) { @@ -783,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; @@ -802,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 } } @@ -824,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; } @@ -856,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; @@ -870,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; @@ -895,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 @@ -922,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(); @@ -930,6 +1053,20 @@ static int can_nxp_s32_init(const struct device *dev) return 0; } +static void can_nxp_s32_isr_rx_tx(const struct device *dev) +{ + const struct can_nxp_s32_config *config = dev->config; + + Canexcel_Ip_RxTxIRQHandler(config->instance); +} + +static void can_nxp_s32_isr_error(const struct device *dev) +{ + const struct can_nxp_s32_config *config = dev->config; + + Canexcel_Ip_ErrIRQHandler(config->instance); +} + static const struct can_driver_api can_nxp_s32_driver_api = { .get_capabilities = can_nxp_s32_get_capabilities, .start = can_nxp_s32_start, @@ -946,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, @@ -961,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, @@ -980,19 +1116,13 @@ static const struct can_driver_api can_nxp_s32_driver_api = { #endif }; -#define CAN_NXP_S32_NODE(n) DT_NODELABEL(can##n) - -#define CAN_NXP_S32_IRQ_HANDLER(n, irq_name) DT_CAT5(CANXL, n, _, irq_name, Handler) - -#define _CAN_NXP_S32_IRQ_CONFIG(node_id, prop, idx, n) \ +#define _CAN_NXP_S32_IRQ_CONFIG(node_id, prop, idx) \ do { \ - extern void (CAN_NXP_S32_IRQ_HANDLER(n, \ - DT_STRING_TOKEN_BY_IDX(node_id, prop, idx)))(void); \ IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, idx, irq), \ DT_IRQ_BY_IDX(node_id, idx, priority), \ - CAN_NXP_S32_IRQ_HANDLER(n, \ + UTIL_CAT(can_nxp_s32_isr_, \ DT_STRING_TOKEN_BY_IDX(node_id, prop, idx)), \ - NULL, \ + DEVICE_DT_GET(node_id), \ DT_IRQ_BY_IDX(node_id, idx, flags)); \ irq_enable(DT_IRQ_BY_IDX(node_id, idx, irq)); \ } while (false); @@ -1000,15 +1130,14 @@ static const struct can_driver_api can_nxp_s32_driver_api = { #define CAN_NXP_S32_IRQ_CONFIG(n) \ static void can_irq_config_##n(void) \ { \ - DT_FOREACH_PROP_ELEM_VARGS(CAN_NXP_S32_NODE(n), interrupt_names, \ - _CAN_NXP_S32_IRQ_CONFIG, n); \ + DT_INST_FOREACH_PROP_ELEM(n, interrupt_names, _CAN_NXP_S32_IRQ_CONFIG); \ } #define CAN_NXP_S32_ERR_CALLBACK(n) \ void nxp_s32_can_##n##_err_callback(uint8 instance, Canexcel_Ip_EventType eventType,\ uint32 u32SysStatus, const Canexcel_Ip_StateType *canexcelState) \ { \ - const struct device *dev = DEVICE_DT_GET(CAN_NXP_S32_NODE(n)); \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ can_nxp_s32_err_callback(dev, eventType, u32SysStatus, canexcelState); \ } @@ -1016,23 +1145,19 @@ static const struct can_driver_api can_nxp_s32_driver_api = { void nxp_s32_can_##n##_ctrl_callback(uint8 instance, Canexcel_Ip_EventType eventType,\ uint32 buffIdx, const Canexcel_Ip_StateType *canexcelState) \ { \ - const struct device *dev = DEVICE_DT_GET(CAN_NXP_S32_NODE(n)); \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ 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_PROP(CAN_NXP_S32_NODE(n), bus_speed_data), \ - .sjw_data = DT_PROP(CAN_NXP_S32_NODE(n), sjw_data), \ - .prop_seg_data = DT_PROP_OR(CAN_NXP_S32_NODE(n), prop_seg_data, 0), \ - .phase_seg1_data = DT_PROP_OR(CAN_NXP_S32_NODE(n), phase_seg1_data, 0), \ - .phase_seg2_data = DT_PROP_OR(CAN_NXP_S32_NODE(n), phase_seg2_data, 0), \ - .sample_point_data = DT_PROP_OR(CAN_NXP_S32_NODE(n), sample_point_data, 0), -#define CAN_NXP_S32_FD_MODE 1 + .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), #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 @@ -1042,51 +1167,79 @@ static const struct can_driver_api can_nxp_s32_driver_api = { #define CAN_NXP_S32_CTRL_OPTIONS 0 #endif +#define CAN_NXP_S32_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_CANXL_##i##__SIC_BASE) ? i : 0) + +#define CAN_NXP_S32_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET CANXL_SIC_INSTANCE_COUNT, CAN_NXP_S32_HW_INSTANCE_CHECK, (|), n) + #define CAN_NXP_S32_INIT_DEVICE(n) \ CAN_NXP_S32_CTRL_CALLBACK(n) \ CAN_NXP_S32_ERR_CALLBACK(n) \ CAN_NXP_S32_IRQ_CONFIG(n) \ - PINCTRL_DT_DEFINE(CAN_NXP_S32_NODE(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 = { \ - .base_sic = (CANXL_SIC_Type *) \ - DT_REG_ADDR_BY_NAME(CAN_NXP_S32_NODE(n), sic), \ + .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_REG_ADDR_BY_NAME(CAN_NXP_S32_NODE(n), grp_ctrl), \ + DT_INST_REG_ADDR_BY_NAME(n, grp_ctrl), \ .base_dsc_ctrl = (CANXL_DSC_CONTROL_Type *) \ - DT_REG_ADDR_BY_NAME(CAN_NXP_S32_NODE(n), dsc_ctrl), \ - .instance = n, \ - .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(CAN_NXP_S32_NODE(n))), \ + 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_CLOCKS_CELL(CAN_NXP_S32_NODE(n), name), \ - .bitrate = DT_PROP(CAN_NXP_S32_NODE(n), bus_speed), \ - .sjw = DT_PROP(CAN_NXP_S32_NODE(n), sjw), \ - .prop_seg = DT_PROP_OR(CAN_NXP_S32_NODE(n), prop_seg, 0), \ - .phase_seg1 = DT_PROP_OR(CAN_NXP_S32_NODE(n), phase_seg1, 0), \ - .phase_seg2 = DT_PROP_OR(CAN_NXP_S32_NODE(n), phase_seg2, 0), \ - .sample_point = DT_PROP_OR(CAN_NXP_S32_NODE(n), sample_point, 0), \ + DT_INST_CLOCKS_CELL(n, name), \ + .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), \ CAN_NXP_S32_TIMING_DATA_CONFIG(n) \ - .max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(CAN_NXP_S32_NODE(n), \ - CAN_NXP_S32_MAX_BITRATE), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(CAN_NXP_S32_NODE(n), phys)), \ - .pin_cfg = PINCTRL_DT_DEV_CONFIG_GET(CAN_NXP_S32_NODE(n)), \ + .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 \ }; \ @@ -1094,19 +1247,13 @@ static const struct can_driver_api can_nxp_s32_driver_api = { { \ return can_nxp_s32_init(dev); \ } \ - CAN_DEVICE_DT_DEFINE(CAN_NXP_S32_NODE(n), \ - can_nxp_s32_##n##_init, \ - NULL, \ - &can_nxp_s32_data_##n, \ - &can_nxp_s32_config_##n, \ - POST_KERNEL, \ - CONFIG_CAN_INIT_PRIORITY, \ - &can_nxp_s32_driver_api); - -#if DT_NODE_HAS_STATUS(CAN_NXP_S32_NODE(0), okay) -CAN_NXP_S32_INIT_DEVICE(0) -#endif - -#if DT_NODE_HAS_STATUS(CAN_NXP_S32_NODE(1), okay) -CAN_NXP_S32_INIT_DEVICE(1) -#endif + CAN_DEVICE_DT_INST_DEFINE(n, \ + can_nxp_s32_##n##_init, \ + NULL, \ + &can_nxp_s32_data_##n, \ + &can_nxp_s32_config_##n, \ + POST_KERNEL, \ + CONFIG_CAN_INIT_PRIORITY, \ + &can_nxp_s32_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(CAN_NXP_S32_INIT_DEVICE) diff --git a/drivers/can/can_rcar.c b/drivers/can/can_rcar.c index 1dfaf715414c334..55bbdb981d9d0d5 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; } @@ -975,7 +978,8 @@ static void can_rcar_remove_rx_filter(const struct device *dev, int filter_id) { struct can_rcar_data *data = dev->data; - if (filter_id >= CONFIG_CAN_RCAR_MAX_FILTER) { + if (filter_id < 0 || filter_id >= CONFIG_CAN_RCAR_MAX_FILTER) { + LOG_ERR("filter ID %d out of bounds", filter_id); return; } @@ -1003,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; } @@ -1055,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; @@ -1070,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); } @@ -1142,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, @@ -1167,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, @@ -1189,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, \ @@ -1202,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 e081e57c7947326..4f0f32bce914b48 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 ac322fe936e3f21..0a8bacda05c8686 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 e07de338952facb..3bb74f9552c2b41 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,21 @@ 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)); + shell_print(sh, " bit0 errors: %u", can_stats_get_bit0_errors(dev)); + shell_print(sh, " bit1 errors: %u", can_stats_get_bit1_errors(dev)); + shell_print(sh, " stuff errors: %u", can_stats_get_stuff_errors(dev)); + shell_print(sh, " crc errors: %u", can_stats_get_crc_errors(dev)); + shell_print(sh, " form errors: %u", can_stats_get_form_errors(dev)); + shell_print(sh, " ack errors: %u", can_stats_get_ack_errors(dev)); + shell_print(sh, " rx overruns: %u", can_stats_get_rx_overruns(dev)); +#endif /* CONFIG_CAN_STATS */ + return 0; } @@ -507,6 +527,102 @@ static int cmd_can_dbitrate_set(const struct shell *sh, size_t argc, char **argv return 0; } +static int can_shell_parse_timing(const struct shell *sh, size_t argc, char **argv, + struct can_timing *timing) +{ + char *endptr; + + timing->sjw = (uint32_t)strtoul(argv[2], &endptr, 10); + if (*endptr != '\0') { + shell_error(sh, "failed to parse sjw"); + return -EINVAL; + } + + timing->prop_seg = (uint32_t)strtoul(argv[3], &endptr, 10); + if (*endptr != '\0') { + shell_error(sh, "failed to parse prop_seg"); + return -EINVAL; + } + + timing->phase_seg1 = (uint32_t)strtoul(argv[4], &endptr, 10); + if (*endptr != '\0') { + shell_error(sh, "failed to parse phase_seg1"); + return -EINVAL; + } + + timing->phase_seg2 = (uint32_t)strtoul(argv[5], &endptr, 10); + if (*endptr != '\0') { + shell_error(sh, "failed to parse phase_seg2"); + return -EINVAL; + } + + timing->prescaler = (uint32_t)strtoul(argv[6], &endptr, 10); + if (*endptr != '\0') { + shell_error(sh, "failed to parse prescaler"); + return -EINVAL; + } + + return 0; +} + +static int cmd_can_timing_set(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev = device_get_binding(argv[1]); + struct can_timing timing = { 0 }; + int err; + + if (!device_is_ready(dev)) { + shell_error(sh, "device %s not ready", argv[1]); + return -ENODEV; + } + + err = can_shell_parse_timing(sh, argc, argv, &timing); + if (err < 0) { + return err; + } + + shell_print(sh, "setting timing to sjw %u, prop_seg %u, phase_seg1 %u, phase_seg2 %u, " + "prescaler %u", timing.sjw, timing.prop_seg, timing.phase_seg1, + timing.phase_seg2, timing.prescaler); + + err = can_set_timing(dev, &timing); + if (err != 0) { + shell_error(sh, "failed to set timing (err %d)", err); + return err; + } + + return 0; +} + +static int cmd_can_dtiming_set(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev = device_get_binding(argv[1]); + struct can_timing timing = { 0 }; + int err; + + if (!device_is_ready(dev)) { + shell_error(sh, "device %s not ready", argv[1]); + return -ENODEV; + } + + err = can_shell_parse_timing(sh, argc, argv, &timing); + if (err < 0) { + return err; + } + + shell_print(sh, "setting data phase timing to sjw %u, prop_seg %u, phase_seg1 %u, " + "phase_seg2 %u, prescaler %u", timing.sjw, timing.prop_seg, timing.phase_seg1, + timing.phase_seg2, timing.prescaler); + + err = can_set_timing_data(dev, &timing); + if (err != 0) { + shell_error(sh, "failed to set data phase timing (err %d)", err); + return err; + } + + return 0; +} + static int cmd_can_mode_set(const struct shell *sh, size_t argc, char **argv) { const struct device *dev = device_get_binding(argv[1]); @@ -658,7 +774,7 @@ static int cmd_can_send(const struct shell *sh, size_t argc, char **argv) frame_no = frame_counter++; shell_print(sh, "enqueuing CAN frame #%u with %s (%d-bit) CAN ID 0x%0*x, " - "RTR %d, CAN-FD %d, BRS %d, DLC %d", frame_no, + "RTR %d, CAN FD %d, BRS %d, DLC %d", frame_no, (frame.flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard", (frame.flags & CAN_FRAME_IDE) != 0 ? 29 : 11, (frame.flags & CAN_FRAME_IDE) != 0 ? 8 : 3, frame.id, @@ -693,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) { @@ -704,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); @@ -769,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) { @@ -895,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 ", @@ -930,6 +1029,15 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_can_cmds, "Set CAN controller data phase bitrate (sample point and SJW optional)\n" "Usage: can dbitrate [sample point] [sjw]", cmd_can_dbitrate_set, 3, 2), + SHELL_CMD_ARG(timing, &dsub_can_device_name, + "Set CAN controller timing\n" + "Usage: can timing ", + cmd_can_timing_set, 7, 0), + SHELL_COND_CMD_ARG(CONFIG_CAN_FD_MODE, + dtiming, &dsub_can_device_name, + "Set CAN controller data phase timing\n" + "Usage: can dtiming ", + cmd_can_dtiming_set, 7, 0), SHELL_CMD_ARG(mode, &dsub_can_device_name_mode, "Set CAN controller mode\n" "Usage: can mode [mode] [mode] [...]", @@ -939,8 +1047,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_can_cmds, "Usage: can send [-e] [-r] [-f] [-b] [data] [...]\n" "-e use extended (29-bit) CAN ID\n" "-r send Remote Transmission Request (RTR) frame\n" - "-f use CAN-FD frame format\n" - "-b use CAN-FD Bit Rate Switching (BRS)", + "-f use CAN FD frame format\n" + "-b use CAN FD Bit Rate Switching (BRS)", cmd_can_send, 3, SHELL_OPT_ARG_CHECK_SKIP), SHELL_CMD(filter, &sub_can_filter_cmds, "CAN rx filter commands\n" diff --git a/drivers/can/can_sja1000.c b/drivers/can/can_sja1000.c index 9212778ad9d681f..c764251f6284451 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; @@ -163,18 +163,19 @@ int can_sja1000_start(const struct device *dev) } can_sja1000_clear_errors(dev); + CAN_STATS_RESET(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; } @@ -185,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; } @@ -195,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); @@ -222,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; } @@ -254,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); @@ -380,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; } @@ -404,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; } @@ -426,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; } @@ -471,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; } @@ -516,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; @@ -536,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) @@ -548,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; @@ -568,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); @@ -599,6 +597,59 @@ static void can_sja1000_handle_transmit_irq(const struct device *dev) can_sja1000_tx_done(dev, status); } +#ifdef CONFIG_CAN_STATS +static void can_sja1000_handle_data_overrun_irq(const struct device *dev) +{ + /* See NXP SJA1000 Application Note AN97076 (figure 18) for data overrun details */ + + CAN_STATS_RX_OVERRUN_INC(dev); + + can_sja1000_write_reg(dev, CAN_SJA1000_CMR, CAN_SJA1000_CMR_CDO); +} + +static void can_sja1000_handle_bus_error_irq(const struct device *dev) +{ + /* See NXP SJA1000 Application Note AN97076 (tables 6 and 7) for ECC details */ + uint8_t ecc; + + /* Read the Error Code Capture register to re-activate it */ + ecc = can_sja1000_read_reg(dev, CAN_SJA1000_ECC); + + if (ecc == (CAN_SJA1000_ECC_ERRC_OTHER_ERROR | CAN_SJA1000_ECC_DIR_TX | + CAN_SJA1000_ECC_SEG_ACK_SLOT)) { + /* Missing ACK is reported as a TX "other" error in the ACK slot */ + CAN_STATS_ACK_ERROR_INC(dev); + return; + } + + if (ecc == (CAN_SJA1000_ECC_ERRC_FORM_ERROR | CAN_SJA1000_ECC_DIR_RX | + CAN_SJA1000_ECC_SEG_ACK_DELIM)) { + /* CRC error is reported as a RX "form" error in the ACK delimiter */ + CAN_STATS_CRC_ERROR_INC(dev); + return; + } + + switch (ecc & CAN_SJA1000_ECC_ERRC_MASK) { + case CAN_SJA1000_ECC_ERRC_BIT_ERROR: + CAN_STATS_BIT_ERROR_INC(dev); + break; + + case CAN_SJA1000_ECC_ERRC_FORM_ERROR: + CAN_STATS_FORM_ERROR_INC(dev); + break; + case CAN_SJA1000_ECC_ERRC_STUFF_ERROR: + CAN_STATS_STUFF_ERROR_INC(dev); + break; + + case CAN_SJA1000_ECC_ERRC_OTHER_ERROR: + __fallthrough; + default: + /* Other error not currently reported in CAN statistics */ + break; + } +} +#endif /* CONFIG_CAN_STATS */ + static void can_sja1000_handle_error_warning_irq(const struct device *dev) { struct can_sja1000_data *data = dev->data; @@ -609,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 */ @@ -634,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; @@ -650,6 +701,16 @@ void can_sja1000_isr(const struct device *dev) can_sja1000_handle_receive_irq(dev); } +#ifdef CONFIG_CAN_STATS + if ((ir & CAN_SJA1000_IR_DOI) != 0) { + can_sja1000_handle_data_overrun_irq(dev); + } + + if ((ir & CAN_SJA1000_IR_BEI) != 0) { + can_sja1000_handle_bus_error_irq(dev); + } +#endif /* CONFIG_CAN_STATS */ + if ((ir & CAN_SJA1000_IR_EI) != 0) { can_sja1000_handle_error_warning_irq(dev); } @@ -675,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; } @@ -709,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; @@ -723,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); } @@ -746,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; @@ -754,6 +816,9 @@ int can_sja1000_init(const struct device *dev) /* Enable interrupts */ can_sja1000_write_reg(dev, CAN_SJA1000_IER, +#ifdef CONFIG_CAN_STATS + CAN_SJA1000_IER_BEIE | CAN_SJA1000_IER_DOIE | +#endif /* CONFIG_CAN_STATS */ CAN_SJA1000_IER_RIE | CAN_SJA1000_IER_TIE | CAN_SJA1000_IER_EIE | CAN_SJA1000_IER_EPIE); diff --git a/drivers/can/can_sja1000_priv.h b/drivers/can/can_sja1000_priv.h index 03d5dbf0f0dadd9..4a02b734a82f3f4 100644 --- a/drivers/can/can_sja1000_priv.h +++ b/drivers/can/can_sja1000_priv.h @@ -108,9 +108,37 @@ /* Error Code Capture register (ECC) bits */ #define CAN_SJA1000_ECC_SEG_MASK GENMASK(4, 0) -#define CAN_SJA1000_ECC_DIR BIT(5) +#define CAN_SJA1000_ECC_DIR_MASK BIT(5) #define CAN_SJA1000_ECC_ERRC_MASK GENMASK(7, 6) +#define CAN_SJA1000_ECC_SEG_SOF FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 3U) +#define CAN_SJA1000_ECC_SEG_ID28_TO_ID21 FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 2U) +#define CAN_SJA1000_ECC_SEG_ID20_TO_ID18 FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 6U) +#define CAN_SJA1000_ECC_SEG_SRTR FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 4U) +#define CAN_SJA1000_ECC_SEG_IDE FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 5U) +#define CAN_SJA1000_ECC_SEG_ID17_TO_ID13 FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 7U) +#define CAN_SJA1000_ECC_SEG_ID12_TO_ID5 FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 15U) +#define CAN_SJA1000_ECC_SEG_ID4_TO_ID0 FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 14U) +#define CAN_SJA1000_ECC_SEG_RTR FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 12U) +#define CAN_SJA1000_ECC_SEG_RES1 FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 13U) +#define CAN_SJA1000_ECC_SEG_RES0 FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 9U) +#define CAN_SJA1000_ECC_SEG_DLC FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 11U) +#define CAN_SJA1000_ECC_SEG_DATA FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 10U) +#define CAN_SJA1000_ECC_SEG_CRC_SEQ FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 8U) +#define CAN_SJA1000_ECC_SEG_CRC_DELIM FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 24U) +#define CAN_SJA1000_ECC_SEG_ACK_SLOT FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 25U) +#define CAN_SJA1000_ECC_SEG_ACK_DELIM FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 27U) +#define CAN_SJA1000_ECC_SEG_EOF FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 26U) +#define CAN_SJA1000_ECC_SEG_INTERMISSION FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 18U) +#define CAN_SJA1000_ECC_SEG_ACTIVE_ERROR_FLAG FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 17U) +#define CAN_SJA1000_ECC_SEG_PASSIVE_ERROR_FLAG FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 22U) +#define CAN_SJA1000_ECC_SEG_TOLERATE_DOM_BITS FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 19U) +#define CAN_SJA1000_ECC_SEG_ERROR_DELIM FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 23U) +#define CAN_SJA1000_ECC_SEG_OVERLOAD_FLAG FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 28U) + +#define CAN_SJA1000_ECC_DIR_TX FIELD_PREP(CAN_SJA1000_ECC_DIR_MASK, 0U) +#define CAN_SJA1000_ECC_DIR_RX FIELD_PREP(CAN_SJA1000_ECC_DIR_MASK, 1U) + #define CAN_SJA1000_ECC_ERRC_BIT_ERROR FIELD_PREP(CAN_SJA1000_ECC_ERRC_MASK, 0U) #define CAN_SJA1000_ECC_ERRC_FORM_ERROR FIELD_PREP(CAN_SJA1000_ECC_ERRC_MASK, 1U) #define CAN_SJA1000_ECC_ERRC_STUFF_ERROR FIELD_PREP(CAN_SJA1000_ECC_ERRC_MASK, 2U) diff --git a/drivers/can/can_stm32_bxcan.c b/drivers/can/can_stm32_bxcan.c index d7eab7aea352433..557079e2e3c7593 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; } @@ -1035,7 +1017,10 @@ static void can_stm32_remove_rx_filter(const struct device *dev, int filter_id) int bank_num; bool bank_unused; - __ASSERT_NO_MSG(filter_id >= 0 && filter_id < CAN_STM32_MAX_FILTER_ID); + if (filter_id < 0 || filter_id >= CAN_STM32_MAX_FILTER_ID) { + LOG_ERR("filter ID %d out of bounds", filter_id); + return; + } k_mutex_lock(&filter_mutex, K_FOREVER); k_mutex_lock(&data->inst_mutex, K_FOREVER); @@ -1104,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, @@ -1164,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), \ @@ -1179,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 e17fce0e1b96e8f..fffd291778df2b3 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 291bcfe80916a4f..e4965f32a929dba 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 2d77ce746c3d6d5..8d8a1a612ad319a 100644 --- a/drivers/can/can_tcan4x5x.c +++ b/drivers/can/can_tcan4x5x.c @@ -408,8 +408,12 @@ static void tcan4x5x_int_gpio_callback_handler(const struct device *port, struct k_sem_give(&tcan_data->int_sem); } -static void tcan4x5x_int_thread(const struct device *dev) +static void tcan4x5x_int_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; struct can_mcan_data *mcan_data = dev->data; struct tcan4x5x_data *tcan_data = mcan_data->custom; uint32_t status; @@ -637,7 +641,7 @@ static int tcan4x5x_init(const struct device *dev) tid = k_thread_create(&tcan_data->int_thread, tcan_data->int_stack, K_KERNEL_STACK_SIZEOF(tcan_data->int_stack), - (k_thread_entry_t)tcan4x5x_int_thread, (void *)dev, NULL, NULL, + tcan4x5x_int_thread, (void *)dev, NULL, NULL, CONFIG_CAN_TCAN4X5X_THREAD_PRIO, 0, K_NO_WAIT); k_thread_name_set(tid, "tcan4x5x"); @@ -725,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 000000000000000..b6c578595eae634 --- /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 9f036599f31f809..e6aaacc8c34eb51 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 6b4b36ae61a68dd..60b80b0ed25cd4f 100644 --- a/drivers/charger/CMakeLists.txt +++ b/drivers/charger/CMakeLists.txt @@ -3,6 +3,9 @@ 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) zephyr_library_sources_ifdef(CONFIG_EMUL_SBS_CHARGER emul_sbs_charger.c) diff --git a/drivers/charger/Kconfig b/drivers/charger/Kconfig index 532a0a4545de6d8..ce2c3d8b8d39c4f 100644 --- a/drivers/charger/Kconfig +++ b/drivers/charger/Kconfig @@ -20,5 +20,8 @@ config CHARGER_INIT_PRIORITY Battery charger initialization 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.bq24190 b/drivers/charger/Kconfig.bq24190 new file mode 100644 index 000000000000000..be3e29727a21baa --- /dev/null +++ b/drivers/charger/Kconfig.bq24190 @@ -0,0 +1,10 @@ +# Copyright 2023 Cirrus Logic, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config CHARGER_BQ24190 + bool "BQ24190 Battery Charger" + default y + depends on DT_HAS_TI_BQ24190_ENABLED + select I2C + help + Enable I2C-based driver for the TI BQ24190 Battery Charger. diff --git a/drivers/charger/Kconfig.bq25180 b/drivers/charger/Kconfig.bq25180 new file mode 100644 index 000000000000000..44bdc9b32ee495c --- /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/Kconfig.max20335 b/drivers/charger/Kconfig.max20335 new file mode 100644 index 000000000000000..7104e5daab67f71 --- /dev/null +++ b/drivers/charger/Kconfig.max20335 @@ -0,0 +1,11 @@ +# Copyright 2023 Grinn +# SPDX-License-Identifier: Apache-2.0 + +config CHARGER_MAX20335 + bool "MAX20335 battery charger driver" + default y + depends on DT_HAS_MAXIM_MAX20335_CHARGER_ENABLED + select I2C + select MFD + help + Enable the MAX20335 battery charger driver. diff --git a/drivers/charger/bq24190.h b/drivers/charger/bq24190.h new file mode 100644 index 000000000000000..06d5d3ba2996ec1 --- /dev/null +++ b/drivers/charger/bq24190.h @@ -0,0 +1,167 @@ +/* + * Copyright 2023 Cirrus Logic, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_CHARGER_BQ24190_H_ +#define ZEPHYR_DRIVERS_CHARGER_BQ24190_H_ + +/* Input Source Control */ +#define BQ24190_REG_ISC 0x00 +#define BQ24190_REG_ISC_EN_HIZ_MASK BIT(7) +#define BQ24190_REG_ISC_EN_HIZ_SHIFT 7 +#define BQ24190_REG_ISC_VINDPM_MASK GENMASK(6, 3) +#define BQ24190_REG_ISC_VINDPM_SHIFT 3 +#define BQ24190_REG_ISC_IINLIM_MASK GENMASK(2, 0) + +/* Power-On Configuration */ +#define BQ24190_REG_POC 0x01 +#define BQ24190_REG_POC_RESET_MASK BIT(7) +#define BQ24190_REG_POC_RESET_SHIFT 7 +#define BQ24190_RESET_MAX_TRIES 100 +#define BQ24190_REG_POC_WDT_RESET_MASK BIT(6) +#define BQ24190_REG_POC_WDT_RESET_SHIFT 6 +#define BQ24190_REG_POC_CHG_CONFIG_MASK GENMASK(5, 4) +#define BQ24190_REG_POC_CHG_CONFIG_SHIFT 4 +#define BQ24190_REG_POC_CHG_CONFIG_DISABLE 0x0 +#define BQ24190_REG_POC_CHG_CONFIG_CHARGE 0x1 +#define BQ24190_REG_POC_CHG_CONFIG_OTG 0x2 +#define BQ24190_REG_POC_CHG_CONFIG_OTG_ALT 0x3 +#define BQ24190_REG_POC_SYS_MIN_MASK GENMASK(3, 1) +#define BQ24190_REG_POC_SYS_MIN_SHIFT 1 +#define BQ24190_REG_POC_SYS_MIN_MIN_UV 3000000 +#define BQ24190_REG_POC_SYS_MIN_MAX_UV 3700000 +#define BQ24190_REG_POC_BOOST_LIM_MASK BIT(0) +#define BQ24190_REG_POC_BOOST_LIM_SHIFT 0 + +/* Charge Current Control */ +#define BQ24190_REG_CCC 0x02 +#define BQ24190_REG_CCC_ICHG_MASK GENMASK(7, 2) +#define BQ24190_REG_CCC_ICHG_SHIFT 2 +#define BQ24190_REG_CCC_ICHG_STEP_UA 64000 +#define BQ24190_REG_CCC_ICHG_OFFSET_UA 512000 +#define BQ24190_REG_CCC_ICHG_MIN_UA BQ24190_REG_CCC_ICHG_OFFSET_UA +#define BQ24190_REG_CCC_ICHG_MAX_UA 4544000 +#define BQ24190_REG_CCC_FORCE_20PCT_MASK BIT(0) +#define BQ24190_REG_CCC_FORCE_20PCT_SHIFT 0 + +/* Pre-charge/Termination Current Cntl */ +#define BQ24190_REG_PCTCC 0x03 +#define BQ24190_REG_PCTCC_IPRECHG_MASK GENMASK(7, 4) +#define BQ24190_REG_PCTCC_IPRECHG_SHIFT 4 +#define BQ24190_REG_PCTCC_IPRECHG_STEP_UA 128000 +#define BQ24190_REG_PCTCC_IPRECHG_OFFSET_UA 128000 +#define BQ24190_REG_PCTCC_IPRECHG_MIN_UA BQ24190_REG_PCTCC_IPRECHG_OFFSET_UA +#define BQ24190_REG_PCTCC_IPRECHG_MAX_UA 2048000 +#define BQ24190_REG_PCTCC_ITERM_MASK GENMASK(3, 0) +#define BQ24190_REG_PCTCC_ITERM_SHIFT 0 +#define BQ24190_REG_PCTCC_ITERM_STEP_UA 128000 +#define BQ24190_REG_PCTCC_ITERM_OFFSET_UA 128000 +#define BQ24190_REG_PCTCC_ITERM_MIN_UA BQ24190_REG_PCTCC_ITERM_OFFSET_UA +#define BQ24190_REG_PCTCC_ITERM_MAX_UA 2048000 + +/* Charge Voltage Control */ +#define BQ24190_REG_CVC 0x04 +#define BQ24190_REG_CVC_VREG_MASK GENMASK(7, 2) +#define BQ24190_REG_CVC_VREG_SHIFT 2 +#define BQ24190_REG_CVC_VREG_STEP_UV 16000 +#define BQ24190_REG_CVC_VREG_OFFSET_UV 3504000 +#define BQ24190_REG_CVC_VREG_MIN_UV BQ24190_REG_CVC_VREG_OFFSET_UV +#define BQ24190_REG_CVC_VREG_MAX_UV 4400000 +#define BQ24190_REG_CVC_BATLOWV_MASK BIT(1) +#define BQ24190_REG_CVC_BATLOWV_SHIFT 1 +#define BQ24190_REG_CVC_VRECHG_MASK BIT(0) +#define BQ24190_REG_CVC_VRECHG_SHIFT 0 + +/* Charge Term/Timer Control */ +#define BQ24190_REG_CTTC 0x05 +#define BQ24190_REG_CTTC_EN_TERM_MASK BIT(7) +#define BQ24190_REG_CTTC_EN_TERM_SHIFT 7 +#define BQ24190_REG_CTTC_TERM_STAT_MASK BIT(6) +#define BQ24190_REG_CTTC_TERM_STAT_SHIFT 6 +#define BQ24190_REG_CTTC_WATCHDOG_MASK GENMASK(5, 4) +#define BQ24190_REG_CTTC_WATCHDOG_SHIFT 4 +#define BQ24190_REG_CTTC_EN_TIMER_MASK BIT(3) +#define BQ24190_REG_CTTC_EN_TIMER_SHIFT 3 +#define BQ24190_REG_CTTC_CHG_TIMER_MASK GENMASK(2, 1) +#define BQ24190_REG_CTTC_CHG_TIMER_SHIFT 1 +#define BQ24190_REG_CTTC_JEITA_ISET_MASK BIT(0) +#define BQ24190_REG_CTTC_JEITA_ISET_SHIFT 0 + +/* IR Comp/Thermal Regulation Control */ +#define BQ24190_REG_ICTRC 0x06 +#define BQ24190_REG_ICTRC_BAT_COMP_MASK GENMASK(7, 5) +#define BQ24190_REG_ICTRC_BAT_COMP_SHIFT 5 +#define BQ24190_REG_ICTRC_VCLAMP_MASK GENMASK(4, 2) +#define BQ24190_REG_ICTRC_VCLAMP_SHIFT 2 +#define BQ24190_REG_ICTRC_TREG_MASK GENMASK(1, 0) +#define BQ24190_REG_ICTRC_TREG_SHIFT 0 + +/* Misc. Operation Control */ +#define BQ24190_REG_MOC 0x07 +#define BQ24190_REG_MOC_DPDM_EN_MASK BIT(7) +#define BQ24190_REG_MOC_DPDM_EN_SHIFT 7 +#define BQ24190_REG_MOC_TMR2X_EN_MASK BIT(6) +#define BQ24190_REG_MOC_TMR2X_EN_SHIFT 6 +#define BQ24190_REG_MOC_BATFET_DISABLE_MASK BIT(5) +#define BQ24190_REG_MOC_BATFET_DISABLE_SHIFT 5 +#define BQ24190_REG_MOC_JEITA_VSET_MASK BIT(4) +#define BQ24190_REG_MOC_JEITA_VSET_SHIFT 4 +#define BQ24190_REG_MOC_INT_MASK_MASK GENMASK(1, 0) +#define BQ24190_REG_MOC_INT_MASK_SHIFT 0 + +/* System Status */ +#define BQ24190_REG_SS 0x08 +#define BQ24190_REG_SS_VBUS_STAT_MASK GENMASK(7, 6) +#define BQ24190_REG_SS_VBUS_STAT_SHIFT 6 +#define BQ24190_REG_SS_CHRG_STAT_MASK GENMASK(5, 4) +#define BQ24190_REG_SS_CHRG_STAT_SHIFT 4 +#define BQ24190_CHRG_STAT_NOT_CHRGING 0x0 +#define BQ24190_CHRG_STAT_PRECHRG 0x1 +#define BQ24190_CHRG_STAT_FAST_CHRG 0x2 +#define BQ24190_CHRG_STAT_CHRG_TERM 0x3 +#define BQ24190_REG_SS_DPM_STAT_MASK BIT(3) +#define BQ24190_REG_SS_DPM_STAT_SHIFT 3 +#define BQ24190_REG_SS_PG_STAT_MASK BIT(2) +#define BQ24190_REG_SS_PG_STAT_SHIFT 2 +#define BQ24190_REG_SS_THERM_STAT_MASK BIT(1) +#define BQ24190_REG_SS_THERM_STAT_SHIFT 1 +#define BQ24190_REG_SS_VSYS_STAT_MASK BIT(0) +#define BQ24190_REG_SS_VSYS_STAT_SHIFT 0 + +/* Fault */ +#define BQ24190_REG_F 0x09 +#define BQ24190_REG_F_WATCHDOG_FAULT_MASK BIT(7) +#define BQ24190_REG_F_WATCHDOG_FAULT_SHIFT 7 +#define BQ24190_REG_F_BOOST_FAULT_MASK BIT(6) +#define BQ24190_REG_F_BOOST_FAULT_SHIFT 6 +#define BQ24190_REG_F_CHRG_FAULT_MASK GENMASK(5, 4) +#define BQ24190_REG_F_CHRG_FAULT_SHIFT 4 +#define BQ24190_CHRG_FAULT_INPUT_FAULT 0x1 +#define BQ24190_CHRG_FAULT_TSHUT 0x2 +#define BQ24190_CHRG_SAFETY_TIMER 0x3 +#define BQ24190_REG_F_BAT_FAULT_MASK BIT(3) +#define BQ24190_REG_F_BAT_FAULT_SHIFT 3 +#define BQ24190_REG_F_NTC_FAULT_MASK GENMASK(2, 0) +#define BQ24190_REG_F_NTC_FAULT_SHIFT 0 +#define BQ24190_NTC_FAULT_TS1_COLD 0x1 +#define BQ24190_NTC_FAULT_TS1_HOT 0x2 +#define BQ24190_NTC_FAULT_TS2_COLD 0x3 +#define BQ24190_NTC_FAULT_TS2_HOT 0x4 +#define BQ24190_NTC_FAULT_TS1_TS2_COLD 0x5 +#define BQ24190_NTC_FAULT_TS1_TS2_HOT 0x6 + +/* Vendor/Part/Revision Status */ +#define BQ24190_REG_VPRS 0x0A +#define BQ24190_REG_VPRS_PN_MASK GENMASK(5, 3) +#define BQ24190_REG_VPRS_PN_SHIFT 3 +#define BQ24190_REG_VPRS_PN_24190 0x4 +#define BQ24190_REG_VPRS_PN_24192 0x5 /* Also 24193, 24196 */ +#define BQ24190_REG_VPRS_PN_24192I 0x3 +#define BQ24190_REG_VPRS_TS_PROFILE_MASK BIT(2) +#define BQ24190_REG_VPRS_TS_PROFILE_SHIFT 2 +#define BQ24190_REG_VPRS_DEV_REG_MASK GENMASK(1, 0) +#define BQ24190_REG_VPRS_DEV_REG_SHIFT 0 + +#endif diff --git a/drivers/charger/charger_bq24190.c b/drivers/charger/charger_bq24190.c new file mode 100644 index 000000000000000..9b313136fefe998 --- /dev/null +++ b/drivers/charger/charger_bq24190.c @@ -0,0 +1,493 @@ +/* + * Copyright 2023 Cirrus Logic, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_bq24190 + +#include + +#include "bq24190.h" + +#include "zephyr/device.h" +#include "zephyr/drivers/charger.h" +#include "zephyr/drivers/i2c.h" +#include "zephyr/kernel.h" +#include "zephyr/sys/util.h" +#include "zephyr/logging/log.h" +#include + +LOG_MODULE_REGISTER(ti_bq24190); + +struct bq24190_config { + struct i2c_dt_spec i2c; + struct gpio_dt_spec ce_gpio; +}; + +struct bq24190_data { + uint8_t ss_reg; + unsigned int ichg_ua; + unsigned int vreg_uv; + enum charger_status state; + enum charger_online online; +}; + +static int bq24190_register_reset(const struct device *dev) +{ + const struct bq24190_config *const config = dev->config; + int ret, limit = BQ24190_RESET_MAX_TRIES; + uint8_t val; + + ret = i2c_reg_update_byte_dt(&config->i2c, BQ24190_REG_POC, BQ24190_REG_POC_RESET_MASK, + BQ24190_REG_POC_RESET_MASK); + if (ret) { + return ret; + } + + /* + * No explicit reset timing characteristcs are provided in the datasheet. + * Instead, poll every 100µs for 100 attempts to see if the reset request + * bit has cleared. + */ + do { + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_POC, &val); + if (ret) { + return ret; + } + + if (!(val & BQ24190_REG_POC_RESET_MASK)) { + return 0; + } + + k_usleep(100); + } while (--limit); + + return -EIO; +} + +static int bq24190_charger_get_charge_type(const struct device *dev, + enum charger_charge_type *charge_type) +{ + const struct bq24190_config *const config = dev->config; + uint8_t v; + int ret; + + *charge_type = CHARGER_CHARGE_TYPE_UNKNOWN; + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_POC, &v); + if (ret) { + return ret; + } + + v = FIELD_GET(BQ24190_REG_POC_CHG_CONFIG_MASK, v); + + if (!v) { + *charge_type = CHARGER_CHARGE_TYPE_NONE; + } else { + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_CCC, &v); + if (ret) { + return ret; + } + + v = FIELD_GET(BQ24190_REG_CCC_FORCE_20PCT_MASK, v); + + if (v) { + *charge_type = CHARGER_CHARGE_TYPE_TRICKLE; + } else { + *charge_type = CHARGER_CHARGE_TYPE_FAST; + } + } + + return 0; +} + +static int bq24190_charger_get_health(const struct device *dev, enum charger_health *health) +{ + const struct bq24190_config *const config = dev->config; + uint8_t v; + int ret; + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_F, &v); + if (ret) { + return ret; + } + + if (v & BQ24190_REG_F_NTC_FAULT_MASK) { + switch (v >> BQ24190_REG_F_NTC_FAULT_SHIFT & 0x7) { + case BQ24190_NTC_FAULT_TS1_COLD: + case BQ24190_NTC_FAULT_TS2_COLD: + case BQ24190_NTC_FAULT_TS1_TS2_COLD: + *health = CHARGER_HEALTH_COLD; + break; + case BQ24190_NTC_FAULT_TS1_HOT: + case BQ24190_NTC_FAULT_TS2_HOT: + case BQ24190_NTC_FAULT_TS1_TS2_HOT: + *health = CHARGER_HEALTH_HOT; + break; + default: + *health = CHARGER_HEALTH_UNKNOWN; + } + } else if (v & BQ24190_REG_F_BAT_FAULT_MASK) { + *health = CHARGER_HEALTH_OVERVOLTAGE; + } else if (v & BQ24190_REG_F_CHRG_FAULT_MASK) { + switch (v >> BQ24190_REG_F_CHRG_FAULT_SHIFT & 0x3) { + case BQ24190_CHRG_FAULT_INPUT_FAULT: + /* + * This could be over-voltage or under-voltage + * and there's no way to tell which. Instead + * of looking foolish and returning 'OVERVOLTAGE' + * when its really under-voltage, just return + * 'UNSPEC_FAILURE'. + */ + *health = CHARGER_HEALTH_UNSPEC_FAILURE; + break; + case BQ24190_CHRG_FAULT_TSHUT: + *health = CHARGER_HEALTH_OVERHEAT; + break; + case BQ24190_CHRG_SAFETY_TIMER: + *health = CHARGER_HEALTH_SAFETY_TIMER_EXPIRE; + break; + default: /* prevent compiler warning */ + *health = CHARGER_HEALTH_UNKNOWN; + } + } else if (v & BQ24190_REG_F_BOOST_FAULT_MASK) { + /* + * This could be over-current or over-voltage but there's + * no way to tell which. Return 'OVERVOLTAGE' since there + * isn't an 'OVERCURRENT' value defined that we can return + * even if it was over-current. + */ + *health = CHARGER_HEALTH_OVERVOLTAGE; + } else { + *health = CHARGER_HEALTH_GOOD; + } + + return 0; +} + +static int bq24190_charger_get_online(const struct device *dev, enum charger_online *online) +{ + const struct bq24190_config *const config = dev->config; + uint8_t pg_stat, batfet_disable; + int ret; + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_SS, &pg_stat); + if (ret) { + return ret; + } + + pg_stat = FIELD_GET(BQ24190_REG_SS_PG_STAT_MASK, pg_stat); + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_MOC, &batfet_disable); + if (ret) { + return ret; + } + + batfet_disable = FIELD_GET(BQ24190_REG_MOC_BATFET_DISABLE_MASK, batfet_disable); + + if (pg_stat && !batfet_disable) { + *online = CHARGER_ONLINE_FIXED; + } else { + *online = CHARGER_ONLINE_OFFLINE; + } + + return 0; +} + +static int bq24190_charger_get_status(const struct device *dev, enum charger_status *status) +{ + const struct bq24190_config *const config = dev->config; + uint8_t ss_reg, chrg_fault; + int ret; + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_F, &chrg_fault); + if (ret) { + return ret; + } + + chrg_fault = FIELD_GET(BQ24190_REG_F_CHRG_FAULT_MASK, chrg_fault); + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_SS, &ss_reg); + if (ret) { + return ret; + } + + /* + * The battery must be discharging when any of these are true: + * - there is no good power source; + * - there is a charge fault. + * Could also be discharging when in "supplement mode" but + * there is no way to tell when its in that mode. + */ + if (!(ss_reg & BQ24190_REG_SS_PG_STAT_MASK) || chrg_fault) { + *status = CHARGER_STATUS_DISCHARGING; + } else { + ss_reg = FIELD_GET(BQ24190_REG_SS_CHRG_STAT_MASK, ss_reg); + + switch (ss_reg) { + case BQ24190_CHRG_STAT_NOT_CHRGING: + *status = CHARGER_STATUS_NOT_CHARGING; + break; + case BQ24190_CHRG_STAT_PRECHRG: + case BQ24190_CHRG_STAT_FAST_CHRG: + *status = CHARGER_STATUS_CHARGING; + break; + case BQ24190_CHRG_STAT_CHRG_TERM: + *status = CHARGER_STATUS_FULL; + break; + default: + return -EIO; + } + } + + return 0; +} + +static int bq24190_charger_get_constant_charge_current(const struct device *dev, + uint32_t *current_ua) +{ + const struct bq24190_config *const config = dev->config; + bool frc_20pct; + uint8_t v; + int ret; + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_CCC, &v); + if (ret) { + return ret; + } + + frc_20pct = v & BQ24190_REG_CCC_FORCE_20PCT_MASK; + + v = FIELD_GET(BQ24190_REG_CCC_ICHG_MASK, v); + + *current_ua = (v * BQ24190_REG_CCC_ICHG_STEP_UA) + BQ24190_REG_CCC_ICHG_OFFSET_UA; + + if (frc_20pct) { + *current_ua /= 5; + } + + return 0; +} + +static int bq24190_charger_get_precharge_current(const struct device *dev, uint32_t *current_ua) +{ + const struct bq24190_config *const config = dev->config; + bool frc_20pct; + uint8_t v; + int ret; + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_CCC, &v); + if (ret) { + return ret; + } + + frc_20pct = v & BQ24190_REG_CCC_FORCE_20PCT_MASK; + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_PCTCC, &v); + if (ret) { + return ret; + } + + v = FIELD_GET(BQ24190_REG_PCTCC_IPRECHG_MASK, v); + + *current_ua = (v * BQ24190_REG_PCTCC_IPRECHG_STEP_UA) + BQ24190_REG_PCTCC_IPRECHG_OFFSET_UA; + + if (frc_20pct) { + *current_ua /= 2; + } + + return 0; +} + +static int bq24190_charger_get_charge_term_current(const struct device *dev, uint32_t *current_ua) +{ + const struct bq24190_config *const config = dev->config; + uint8_t v; + int ret; + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_PCTCC, &v); + if (ret) { + return ret; + } + + v = FIELD_GET(BQ24190_REG_PCTCC_ITERM_MASK, v); + + *current_ua = (v * BQ24190_REG_PCTCC_ITERM_STEP_UA) + BQ24190_REG_PCTCC_ITERM_OFFSET_UA; + + return 0; +} + +static int bq24190_get_constant_charge_voltage(const struct device *dev, uint32_t *voltage_uv) +{ + const struct bq24190_config *const config = dev->config; + uint8_t v; + int ret; + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_CVC, &v); + if (ret < 0) { + return ret; + } + + v = FIELD_GET(BQ24190_REG_CVC_VREG_MASK, v); + + *voltage_uv = (v * BQ24190_REG_CVC_VREG_STEP_UV) + BQ24190_REG_CVC_VREG_OFFSET_UV; + + return 0; +} + +static int bq24190_set_constant_charge_current(const struct device *dev, uint32_t current_ua) +{ + const struct bq24190_config *const config = dev->config; + uint8_t v; + int ret; + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_CCC, &v); + if (ret < 0) { + return ret; + } + + v &= BQ24190_REG_CCC_FORCE_20PCT_MASK; + + if (v) { + current_ua *= 5; + } + + current_ua = CLAMP(current_ua, BQ24190_REG_CCC_ICHG_MIN_UA, BQ24190_REG_CCC_ICHG_MAX_UA); + + v = (current_ua - BQ24190_REG_CCC_ICHG_OFFSET_UA) / BQ24190_REG_CCC_ICHG_STEP_UA; + + v = FIELD_PREP(BQ24190_REG_CCC_ICHG_MASK, v); + + return i2c_reg_update_byte_dt(&config->i2c, BQ24190_REG_CCC, BQ24190_REG_CCC_ICHG_MASK, v); +} + +static int bq24190_set_constant_charge_voltage(const struct device *dev, uint32_t voltage_uv) +{ + const struct bq24190_config *const config = dev->config; + uint8_t v; + + voltage_uv = CLAMP(voltage_uv, BQ24190_REG_CVC_VREG_MIN_UV, BQ24190_REG_CVC_VREG_MAX_UV); + + v = (voltage_uv - BQ24190_REG_CVC_VREG_OFFSET_UV) / BQ24190_REG_CVC_VREG_STEP_UV; + + v = FIELD_PREP(BQ24190_REG_CVC_VREG_MASK, v); + + return i2c_reg_update_byte_dt(&config->i2c, BQ24190_REG_CVC, BQ24190_REG_CVC_VREG_MASK, v); +} + +static int bq24190_set_config(const struct device *dev) +{ + struct bq24190_data *data = dev->data; + union charger_propval val; + int ret; + + val.const_charge_current_ua = data->ichg_ua; + + ret = bq24190_set_constant_charge_current(dev, val.const_charge_current_ua); + if (ret < 0) { + return ret; + } + + val.const_charge_voltage_uv = data->vreg_uv; + + return bq24190_set_constant_charge_voltage(dev, val.const_charge_voltage_uv); +} + +static int bq24190_get_prop(const struct device *dev, charger_prop_t prop, + union charger_propval *val) +{ + switch (prop) { + case CHARGER_PROP_ONLINE: + return bq24190_charger_get_online(dev, &val->online); + case CHARGER_PROP_CHARGE_TYPE: + return bq24190_charger_get_charge_type(dev, &val->charge_type); + case CHARGER_PROP_HEALTH: + return bq24190_charger_get_health(dev, &val->health); + case CHARGER_PROP_STATUS: + return bq24190_charger_get_status(dev, &val->status); + case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: + return bq24190_charger_get_constant_charge_current(dev, + &val->const_charge_current_ua); + case CHARGER_PROP_CONSTANT_CHARGE_VOLTAGE_UV: + return bq24190_get_constant_charge_voltage(dev, &val->const_charge_voltage_uv); + case CHARGER_PROP_PRECHARGE_CURRENT_UA: + return bq24190_charger_get_precharge_current(dev, &val->precharge_current_ua); + case CHARGER_PROP_CHARGE_TERM_CURRENT_UA: + return bq24190_charger_get_charge_term_current(dev, &val->charge_term_current_ua); + default: + return -ENOTSUP; + } +} + +static int bq24190_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 bq24190_set_constant_charge_current(dev, val->const_charge_current_ua); + case CHARGER_PROP_CONSTANT_CHARGE_VOLTAGE_UV: + return bq24190_set_constant_charge_voltage(dev, val->const_charge_voltage_uv); + default: + return -ENOTSUP; + } +} + +static int bq24190_init(const struct device *dev) +{ + const struct bq24190_config *const config = dev->config; + struct bq24190_data *data = dev->data; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_VPRS, &val); + if (ret) { + return ret; + } + + val = FIELD_GET(BQ24190_REG_VPRS_PN_MASK, val); + + switch (val) { + case BQ24190_REG_VPRS_PN_24190: + case BQ24190_REG_VPRS_PN_24192: + case BQ24190_REG_VPRS_PN_24192I: + break; + default: + LOG_ERR("Error unknown model: 0x%02x\n", val); + return -ENODEV; + } + + ret = bq24190_register_reset(dev); + if (ret) { + return ret; + } + + ret = bq24190_set_config(dev); + if (ret) { + return ret; + } + + return i2c_reg_read_byte_dt(&config->i2c, BQ24190_REG_SS, &data->ss_reg); +} + +static const struct charger_driver_api bq24190_driver_api = { + .get_property = bq24190_get_prop, + .set_property = bq24190_set_prop, +}; + +#define BQ24190_INIT(inst) \ + \ + static const struct bq24190_config bq24190_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + \ + static struct bq24190_data bq24190_data_##inst = { \ + .ichg_ua = DT_INST_PROP(inst, constant_charge_current_max_microamp), \ + .vreg_uv = DT_INST_PROP(inst, constant_charge_voltage_max_microvolt), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, bq24190_init, NULL, &bq24190_data_##inst, \ + &bq24190_config_##inst, POST_KERNEL, CONFIG_CHARGER_INIT_PRIORITY, \ + &bq24190_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(BQ24190_INIT) diff --git a/drivers/charger/charger_bq25180.c b/drivers/charger/charger_bq25180.c new file mode 100644 index 000000000000000..7063377c5893b4f --- /dev/null +++ b/drivers/charger/charger_bq25180.c @@ -0,0 +1,218 @@ +/* + * 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_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_prop(const struct device *dev, charger_prop_t prop, + union charger_propval *val) +{ + switch (prop) { + 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) { + ret = bq25180_ma_to_ichg(cfg->initial_current_microamp / 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; +} + +#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 7b658249a8472eb..4fdf6ca7140e511 100644 --- a/drivers/charger/charger_handlers.c +++ b/drivers/charger/charger_handlers.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include static inline int z_vrfy_charger_get_prop(const struct device *dev, const charger_prop_t prop, @@ -12,11 +12,11 @@ static inline int z_vrfy_charger_get_prop(const struct device *dev, const charge { union charger_propval k_val; - Z_OOPS(Z_SYSCALL_DRIVER_CHARGER(dev, get_property)); + K_OOPS(K_SYSCALL_DRIVER_CHARGER(dev, get_property)); int ret = z_impl_charger_get_prop(dev, prop, &k_val); - Z_OOPS(z_user_to_copy(val, &k_val, sizeof(union charger_propval))); + K_OOPS(k_usermode_to_copy(val, &k_val, sizeof(union charger_propval))); return ret; } @@ -28,11 +28,20 @@ static inline int z_vrfy_charger_set_prop(const struct device *dev, const charge { union charger_propval k_val; - Z_OOPS(Z_SYSCALL_DRIVER_CHARGER(dev, set_property)); + K_OOPS(K_SYSCALL_DRIVER_CHARGER(dev, set_property)); - Z_OOPS(z_user_from_copy(&k_val, val, sizeof(union charger_propval))); + K_OOPS(k_usermode_from_copy(&k_val, val, sizeof(union charger_propval))); return z_impl_charger_set_prop(dev, prop, &k_val); } #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 new file mode 100644 index 000000000000000..b4f98de69f2af33 --- /dev/null +++ b/drivers/charger/charger_max20335.c @@ -0,0 +1,278 @@ +/* + * Copyright 2023 Grinn + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT maxim_max20335_charger + +#include +#include +#include +#include +#include +#include + +#include "zephyr/logging/log.h" +LOG_MODULE_REGISTER(max20335_charger); + +#define MAX20335_REG_STATUS_A 0x02 +#define MAX20335_REG_ILIMCNTL 0x09 +#define MAX20335_REG_CHG_CNTL_A 0x0A +#define MAX20335_CHGCNTLA_BAT_REG_CFG_MASK GENMASK(4, 1) +#define MAX20335_ILIMCNTL_MASK GENMASK(1, 0) +#define MAX20335_STATUS_A_CHG_STAT_MASK GENMASK(2, 0) +#define MAX20335_CHRG_EN_MASK BIT(0) +#define MAX20335_CHRG_EN BIT(0) +#define MAX20335_REG_CVC_VREG_MIN_UV 4050000U +#define MAX20335_REG_CVC_VREG_STEP_UV 50000U +#define MAX20335_REG_CVC_VREG_MIN_IDX 0x0U +#define MAX20335_REG_CVC_VREG_MAX_IDX 0x0CU + +struct charger_max20335_config { + struct i2c_dt_spec bus; + uint32_t max_ichg_ua; + uint32_t max_vreg_uv; +}; + +enum { + MAX20335_CHARGER_OFF, + MAX20335_CHARGING_SUSPENDED_DUE_TO_TEMPERATURE, + MAX20335_PRE_CHARGE_IN_PROGRESS, + MAX20335_FAST_CHARGE_IN_PROGRESS_1, + MAX20335_FAST_CHARGE_IN_PROGRESS_2, + MAX20335_MAINTAIN_CHARGE_IN_PROGRESS, + MAX20335_MAIN_CHARGER_TIMER_DONE, + MAX20335_CHARGER_FAULT_CONDITION, +}; + +static const struct linear_range charger_uv_range = + LINEAR_RANGE_INIT(MAX20335_REG_CVC_VREG_MIN_UV, + MAX20335_REG_CVC_VREG_STEP_UV, + MAX20335_REG_CVC_VREG_MIN_IDX, + MAX20335_REG_CVC_VREG_MAX_IDX); + +static int max20335_get_status(const struct device *dev, enum charger_status *status) +{ + const struct charger_max20335_config *const config = dev->config; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&config->bus, MAX20335_REG_STATUS_A, &val); + if (ret) { + return ret; + } + + val = FIELD_GET(MAX20335_STATUS_A_CHG_STAT_MASK, val); + + switch (val) { + case MAX20335_CHARGER_OFF: + __fallthrough; + case MAX20335_CHARGING_SUSPENDED_DUE_TO_TEMPERATURE: + __fallthrough; + case MAX20335_CHARGER_FAULT_CONDITION: + *status = CHARGER_STATUS_NOT_CHARGING; + break; + case MAX20335_PRE_CHARGE_IN_PROGRESS: + __fallthrough; + case MAX20335_FAST_CHARGE_IN_PROGRESS_1: + __fallthrough; + case MAX20335_FAST_CHARGE_IN_PROGRESS_2: + __fallthrough; + case MAX20335_MAINTAIN_CHARGE_IN_PROGRESS: + *status = CHARGER_STATUS_CHARGING; + break; + case MAX20335_MAIN_CHARGER_TIMER_DONE: + *status = CHARGER_STATUS_FULL; + break; + default: + *status = CHARGER_STATUS_UNKNOWN; + break; + }; + + return 0; +} + +static int max20335_set_constant_charge_voltage(const struct device *dev, + uint32_t voltage_uv) +{ + const struct charger_max20335_config *const config = dev->config; + uint16_t idx; + uint8_t val; + int ret; + + if (voltage_uv > config->max_vreg_uv) { + LOG_WRN("Exceeded max constant charge voltage!"); + return -EINVAL; + } + + ret = linear_range_get_index(&charger_uv_range, voltage_uv, &idx); + if (ret == -EINVAL) { + return ret; + } + + val = FIELD_PREP(MAX20335_CHGCNTLA_BAT_REG_CFG_MASK, idx); + + return i2c_reg_update_byte_dt(&config->bus, + MAX20335_REG_CHG_CNTL_A, + MAX20335_CHGCNTLA_BAT_REG_CFG_MASK, + val); +} + +static int max20335_set_constant_charge_current(const struct device *dev, + uint32_t current_ua) +{ + const struct charger_max20335_config *const config = dev->config; + uint8_t val; + + if (current_ua > config->max_ichg_ua) { + LOG_WRN("Exceeded max constant charge current!"); + return -EINVAL; + } + + switch (current_ua) { + case 0: + val = 0x00; + break; + case 100000: + val = 0x01; + break; + case 500000: + val = 0x02; + break; + case 1000000: + val = 0x03; + break; + default: + return -ENOTSUP; + }; + + val = FIELD_PREP(MAX20335_ILIMCNTL_MASK, val); + + return i2c_reg_update_byte_dt(&config->bus, + MAX20335_REG_ILIMCNTL, + MAX20335_ILIMCNTL_MASK, + val); +} + +static int max20335_get_constant_charge_current(const struct device *dev, + uint32_t *current_ua) +{ + const struct charger_max20335_config *const config = dev->config; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&config->bus, MAX20335_REG_ILIMCNTL, &val); + if (ret) { + return ret; + } + + switch (val) { + case 0x00: + *current_ua = 0; + break; + case 0x01: + *current_ua = 100000; + break; + case 0x02: + *current_ua = 500000; + break; + case 0x03: + *current_ua = 1000000; + break; + default: + return -ENOTSUP; + }; + + return 0; +} + +static int max20335_get_constant_charge_voltage(const struct device *dev, + uint32_t *current_uv) +{ + const struct charger_max20335_config *const config = dev->config; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&config->bus, MAX20335_REG_CHG_CNTL_A, &val); + if (ret) { + return ret; + } + + val = FIELD_GET(MAX20335_CHGCNTLA_BAT_REG_CFG_MASK, val); + + return linear_range_get_value(&charger_uv_range, val, current_uv); +} + +static int max20335_set_enabled(const struct device *dev, bool enable) +{ + const struct charger_max20335_config *const config = dev->config; + + return i2c_reg_update_byte_dt(&config->bus, + MAX20335_REG_CHG_CNTL_A, + MAX20335_CHRG_EN_MASK, + enable ? MAX20335_CHRG_EN : 0); +} + +static int max20335_get_prop(const struct device *dev, charger_prop_t prop, + union charger_propval *val) +{ + switch (prop) { + case CHARGER_PROP_STATUS: + return max20335_get_status(dev, &val->status); + case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: + return max20335_get_constant_charge_current(dev, + &val->const_charge_current_ua); + case CHARGER_PROP_CONSTANT_CHARGE_VOLTAGE_UV: + return max20335_get_constant_charge_voltage(dev, + &val->const_charge_voltage_uv); + default: + return -ENOTSUP; + } +} + +static int max20335_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 max20335_set_constant_charge_current(dev, + val->const_charge_current_ua); + case CHARGER_PROP_CONSTANT_CHARGE_VOLTAGE_UV: + return max20335_set_constant_charge_voltage(dev, + val->const_charge_voltage_uv); + default: + return -ENOTSUP; + } +} + +static int max20335_init(const struct device *dev) +{ + const struct charger_max20335_config *config = dev->config; + + if (!i2c_is_ready_dt(&config->bus)) { + return -ENODEV; + } + + return 0; +} + +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) \ + static const struct charger_max20335_config charger_max20335_config_##inst = { \ + .bus = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \ + .max_ichg_ua = DT_INST_PROP(inst, constant_charge_current_max_microamp), \ + .max_vreg_uv = DT_INST_PROP(inst, constant_charge_voltage_max_microvolt), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, &max20335_init, NULL, NULL, \ + &charger_max20335_config_##inst, \ + POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ + &max20335_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MAX20335_DEFINE) diff --git a/drivers/charger/emul_sbs_charger.c b/drivers/charger/emul_sbs_charger.c index 34d432c8fbbb7bd..90c64b908ab3d6a 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 7cdc99b2a735a54..9017e1e60b8471d 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 8a8d7fbb61a8745..596b07676e03532 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -26,6 +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_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) @@ -68,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 f4647930ae3c9e4..b0c6cf8de48c7d8 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -80,4 +80,12 @@ source "drivers/clock_control/Kconfig.nxp_s32" source "drivers/clock_control/Kconfig.agilex5" +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.ambiq b/drivers/clock_control/Kconfig.ambiq new file mode 100644 index 000000000000000..ca0a4c1bce59d40 --- /dev/null +++ b/drivers/clock_control/Kconfig.ambiq @@ -0,0 +1,14 @@ +# Ambiq Clock Control Driver configuration options +# +# Copyright (c) 2023 Ambiq Micro Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +config CLOCK_CONTROL_AMBIQ + bool "AMBIQ clock control driver" + default y + depends on DT_HAS_AMBIQ_CLKCTRL_ENABLED + select AMBIQ_HAL + help + Enable driver for Ambiq clock control. diff --git a/drivers/clock_control/Kconfig.npcx b/drivers/clock_control/Kconfig.npcx index b4b91d5f8d3b392..76e5acf985a4326 100644 --- a/drivers/clock_control/Kconfig.npcx +++ b/drivers/clock_control/Kconfig.npcx @@ -18,3 +18,15 @@ config CLOCK_CONTROL_NPCX_EXTERNAL_SRC is generated by the on-chip Crystal Oscillator (XTOSC). This includes an on-chip oscillator, to which an external crystal and the related passive components are connected. + +config CLOCK_CONTROL_NPCX_SUPP_APB4 + bool "Indicates that the clock controller supports APB4 bus" + default y if !SOC_SERIES_NPCX7 + help + Selected if NPCX series supports APB4 bus. + +config CLOCK_CONTROL_NPCX_SUPP_FIU1 + bool "Indicates that the clock controller supports FIU1 bus" + default y if SOC_SERIES_NPCX4 + help + Selected if NPCX series supports FIU1 bus. diff --git a/drivers/clock_control/Kconfig.nrf b/drivers/clock_control/Kconfig.nrf index 64e31b1ad162e00..453aac5b5d074b4 100644 --- a/drivers/clock_control/Kconfig.nrf +++ b/drivers/clock_control/Kconfig.nrf @@ -25,7 +25,6 @@ if CLOCK_CONTROL_NRF config CLOCK_CONTROL_NRF_SHELL bool "Shell commands" depends on SHELL - default y if SHELL choice CLOCK_CONTROL_NRF_SOURCE prompt "32KHz clock source" diff --git a/drivers/clock_control/Kconfig.pwm b/drivers/clock_control/Kconfig.pwm new file mode 100644 index 000000000000000..eed5a91c17bb190 --- /dev/null +++ b/drivers/clock_control/Kconfig.pwm @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Andriy Gelman +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_PWM + bool "Generic PWM clock" + default y + depends on DT_HAS_PWM_CLOCK_ENABLED + select PWM + help + Enable generic PWM clock. + +config CLOCK_CONTROL_PWM_INIT_PRIORITY + int "Initialization priority of the pwm clock device" + default 51 + depends on CLOCK_CONTROL_PWM + help + Initialization priority of the PWM clock device. Must be + lower priority than PWM. diff --git a/drivers/clock_control/Kconfig.rcar b/drivers/clock_control/Kconfig.rcar index b4a69a47e355e22..0caa072355456c6 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 000000000000000..5a14f593f9b40d3 --- /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 000000000000000..3c7c87121fda065 --- /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 8d7890d1fdf8810..cccbe5e2e74a9d0 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_ambiq.c b/drivers/clock_control/clock_control_ambiq.c new file mode 100644 index 000000000000000..a64030c2a2df7cd --- /dev/null +++ b/drivers/clock_control/clock_control_ambiq.c @@ -0,0 +1,138 @@ +/* + * Copyright 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ambiq_clkctrl + +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(clock_control_ambiq, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +struct ambiq_clock_config { + uint32_t clock_freq; + const struct pinctrl_dev_config *pcfg; +}; + +static int ambiq_clock_on(const struct device *dev, clock_control_subsys_t sub_system) +{ + ARG_UNUSED(dev); + + int ret; + uint32_t clock_name = (uint32_t)sub_system; + am_hal_mcuctrl_control_arg_t arg = { + .b_arg_hfxtal_in_use = true, + .b_arg_apply_ext_source = false, + .b_arg_force_update = false, + }; + + if (clock_name >= CLOCK_CONTROL_AMBIQ_TYPE_MAX) { + return -EINVAL; + } + + switch (clock_name) { + case CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE: + arg.ui32_arg_hfxtal_user_mask = BIT(AM_HAL_HFXTAL_BLE_CONTROLLER_EN); + arg.b_arg_enable_HfXtalClockout = true; + ret = am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_EXTCLK32M_KICK_START, &arg); + break; + case CLOCK_CONTROL_AMBIQ_TYPE_LFXTAL: + ret = am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_EXTCLK32K_ENABLE, 0); + default: + ret = -ENOTSUP; + break; + } + + return ret; +} + +static int ambiq_clock_off(const struct device *dev, clock_control_subsys_t sub_system) +{ + ARG_UNUSED(dev); + + int ret; + uint32_t clock_name = (uint32_t)sub_system; + am_hal_mcuctrl_control_arg_t arg = { + .b_arg_hfxtal_in_use = true, + .b_arg_apply_ext_source = false, + .b_arg_force_update = false, + }; + + if (clock_name >= CLOCK_CONTROL_AMBIQ_TYPE_MAX) { + return -EINVAL; + } + + switch (clock_name) { + case CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE: + arg.ui32_arg_hfxtal_user_mask = BIT(AM_HAL_HFXTAL_BLE_CONTROLLER_EN); + arg.b_arg_enable_HfXtalClockout = true; + ret = am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_EXTCLK32M_DISABLE, &arg); + break; + case CLOCK_CONTROL_AMBIQ_TYPE_LFXTAL: + ret = am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_EXTCLK32K_DISABLE, 0); + break; + default: + ret = -ENOTSUP; + break; + } + + return ret; +} + +static inline int ambiq_clock_get_rate(const struct device *dev, clock_control_subsys_t sub_system, + uint32_t *rate) +{ + ARG_UNUSED(sub_system); + + const struct ambiq_clock_config *cfg = dev->config; + *rate = cfg->clock_freq; + + return 0; +} + +static inline int ambiq_clock_configure(const struct device *dev, clock_control_subsys_t sub_system, + void *data) +{ + ARG_UNUSED(sub_system); + ARG_UNUSED(data); + + const struct ambiq_clock_config *cfg = dev->config; + int ret; + + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + + return ret; +} + +static int ambiq_clock_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* Nothing to do.*/ + return 0; +} + +static const struct clock_control_driver_api ambiq_clock_driver_api = { + .on = ambiq_clock_on, + .off = ambiq_clock_off, + .get_rate = ambiq_clock_get_rate, + .configure = ambiq_clock_configure, +}; + +#define AMBIQ_CLOCK_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + static const struct ambiq_clock_config ambiq_clock_config##n = { \ + .clock_freq = DT_INST_PROP(n, clock_frequency), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n)}; \ + DEVICE_DT_INST_DEFINE(n, ambiq_clock_init, NULL, NULL, &ambiq_clock_config##n, \ + POST_KERNEL, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \ + &ambiq_clock_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(AMBIQ_CLOCK_INIT) diff --git a/drivers/clock_control/clock_control_esp32.c b/drivers/clock_control/clock_control_esp32.c index fba7091b871a557..4b8b01f521e6d38 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 b2d04a3cc929561..2eb0c6b358981fb 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 93a495b9daea121..355f85dfc3e14dd 100644 --- a/drivers/clock_control/clock_control_mcux_ccm.c +++ b/drivers/clock_control/clock_control_mcux_ccm.c @@ -12,6 +12,10 @@ #include #include +#if defined(CONFIG_SOC_MIMX8QM_ADSP) || defined(CONFIG_SOC_MIMX8QXP_ADSP) +#include
    +#endif + #define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL #include LOG_MODULE_REGISTER(clock_control); @@ -39,18 +43,34 @@ static const clock_ip_name_t uart_clocks[] = { kCLOCK_Uart4, }; #endif -#if defined(CONFIG_UART_MCUX_LPUART) && defined(CONFIG_SOC_MIMX93_A55) -static const clock_root_t lpuart_clk_root[] = { - kCLOCK_Root_Lpuart1, - kCLOCK_Root_Lpuart2, - kCLOCK_Root_Lpuart3, - kCLOCK_Root_Lpuart4, - kCLOCK_Root_Lpuart5, - kCLOCK_Root_Lpuart6, - kCLOCK_Root_Lpuart7, - kCLOCK_Root_Lpuart8, + +#ifdef CONFIG_UART_MCUX_LPUART + +#ifdef CONFIG_SOC_MIMX8QM_ADSP +static const clock_ip_name_t lpuart_clocks[] = { + kCLOCK_DMA_Lpuart0, + kCLOCK_DMA_Lpuart1, + kCLOCK_DMA_Lpuart2, + kCLOCK_DMA_Lpuart3, + kCLOCK_DMA_Lpuart4, }; -#endif + +static const uint32_t lpuart_rate = MHZ(80); +#endif /* CONFIG_SOC_MIMX8QM_ADSP */ + +#ifdef CONFIG_SOC_MIMX8QXP_ADSP +static const clock_ip_name_t lpuart_clocks[] = { + kCLOCK_DMA_Lpuart0, + kCLOCK_DMA_Lpuart1, + kCLOCK_DMA_Lpuart2, + kCLOCK_DMA_Lpuart3, +}; + +static const uint32_t lpuart_rate = MHZ(80); +#endif /* CONFIG_SOC_MIMX8QXP_ADSP */ + +#endif /* CONFIG_UART_MCUX_LPUART */ + static int mcux_ccm_on(const struct device *dev, clock_control_subsys_t sub_system) @@ -67,6 +87,31 @@ static int mcux_ccm_on(const struct device *dev, CLOCK_EnableClock(uart_clocks[instance]); return 0; #endif + +#if defined(CONFIG_UART_MCUX_LPUART) && defined(CONFIG_SOC_MIMX8QM_ADSP) + case IMX_CCM_LPUART1_CLK: + case IMX_CCM_LPUART2_CLK: + case IMX_CCM_LPUART3_CLK: + case IMX_CCM_LPUART4_CLK: + case IMX_CCM_LPUART5_CLK: + CLOCK_EnableClock(lpuart_clocks[instance]); + return 0; +#endif + +#if defined(CONFIG_UART_MCUX_LPUART) && defined(CONFIG_SOC_MIMX8QXP_ADSP) + case IMX_CCM_LPUART1_CLK: + case IMX_CCM_LPUART2_CLK: + case IMX_CCM_LPUART3_CLK: + case IMX_CCM_LPUART4_CLK: + 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; @@ -128,27 +173,29 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, #endif #ifdef CONFIG_UART_MCUX_LPUART -#ifdef CONFIG_SOC_MIMX93_A55 + +#if defined(CONFIG_SOC_MIMX8QM_ADSP) case IMX_CCM_LPUART1_CLK: case IMX_CCM_LPUART2_CLK: case IMX_CCM_LPUART3_CLK: case IMX_CCM_LPUART4_CLK: case IMX_CCM_LPUART5_CLK: - case IMX_CCM_LPUART6_CLK: - case IMX_CCM_LPUART7_CLK: - case IMX_CCM_LPUART8_CLK: - { uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK; - clock_root_t clk_root = lpuart_clk_root[instance]; - uint32_t uart_mux = CLOCK_GetRootClockMux(clk_root); - uint32_t divider = CLOCK_GetRootClockDiv(clk_root); - if (uart_mux == 0) - *rate = MHZ(24) / divider; - else - LOG_ERR("LPUART Clock is not supported\r\n"); + CLOCK_SetIpFreq(lpuart_clocks[instance], lpuart_rate); + *rate = CLOCK_GetIpFreq(lpuart_clocks[instance]); + break; - } break; +#elif defined(CONFIG_SOC_MIMX8QXP_ADSP) + case IMX_CCM_LPUART1_CLK: + case IMX_CCM_LPUART2_CLK: + case IMX_CCM_LPUART3_CLK: + case IMX_CCM_LPUART4_CLK: + uint32_t instance = clock_name & IMX_CCM_INSTANCE_MASK; + + CLOCK_SetIpFreq(lpuart_clocks[instance], lpuart_rate); + *rate = CLOCK_GetIpFreq(lpuart_clocks[instance]); + break; #else case IMX_CCM_LPUART_CLK: @@ -190,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: @@ -270,6 +328,22 @@ static const struct clock_control_driver_api mcux_ccm_driver_api = { .get_rate = mcux_ccm_get_subsys_rate, }; -DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, +static int mcux_ccm_init(const struct device *dev) +{ +#if defined(CONFIG_SOC_MIMX8QM_ADSP) || defined(CONFIG_SOC_MIMX8QXP_ADSP) + sc_ipc_t ipc_handle; + int ret; + + ret = sc_ipc_open(&ipc_handle, DT_REG_ADDR(DT_NODELABEL(scu_mu))); + if (ret != SC_ERR_NONE) { + return -ENODEV; + } + + CLOCK_Init(ipc_handle); +#endif + return 0; +} + +DEVICE_DT_INST_DEFINE(0, mcux_ccm_init, NULL, NULL, NULL, PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &mcux_ccm_driver_api); diff --git a/drivers/clock_control/clock_control_mcux_ccm_rev2.c b/drivers/clock_control/clock_control_mcux_ccm_rev2.c index 626402d73dff8df..8edb33e3798c9b8 100644 --- a/drivers/clock_control/clock_control_mcux_ccm_rev2.c +++ b/drivers/clock_control/clock_control_mcux_ccm_rev2.c @@ -6,7 +6,6 @@ #define DT_DRV_COMPAT nxp_imx_ccm_rev2 #include -#include #include #include #include @@ -18,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; } @@ -31,7 +35,7 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, clock_control_subsys_t sub_system, uint32_t *rate) { - uint32_t clock_name = (uint32_t) sub_system; + uint32_t clock_name = (size_t) sub_system; uint32_t clock_root, peripheral, instance; peripheral = (clock_name & IMX_CCM_PERIPHERAL_MASK); @@ -51,6 +55,7 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, #ifdef CONFIG_UART_MCUX_LPUART case IMX_CCM_LPUART1_CLK: + case IMX_CCM_LPUART2_CLK: clock_root = kCLOCK_Root_Lpuart1 + instance; break; #endif @@ -103,11 +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 default: return -EINVAL; } - +#ifdef CONFIG_SOC_MIMX93_A55 + *rate = CLOCK_GetIpFreq(clock_root); +#else *rate = CLOCK_GetRootClockFreq(clock_root); +#endif return 0; } diff --git a/drivers/clock_control/clock_control_mcux_sim.c b/drivers/clock_control/clock_control_mcux_sim.c index ce589c9a6bf477d..ed74ff941f51973 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 2349be21711bbb1..a0a7db57d2813b3 100644 --- a/drivers/clock_control/clock_control_mcux_syscon.c +++ b/drivers/clock_control/clock_control_mcux_syscon.c @@ -19,12 +19,19 @@ static int mcux_lpc_syscon_clock_control_on(const struct device *dev, clock_control_subsys_t sub_system) { #if defined(CONFIG_CAN_MCUX_MCAN) - uint32_t clock_name = (uint32_t)sub_system; - - if (clock_name == MCUX_MCAN_CLK) { + if ((uint32_t)sub_system == MCUX_MCAN_CLK) { CLOCK_EnableClock(kCLOCK_Mcan); } #endif /* defined(CONFIG_CAN_MCUX_MCAN) */ +#if defined(CONFIG_COUNTER_NXP_MRT) + if ((uint32_t)sub_system == MCUX_MRT_CLK) { +#if defined(CONFIG_SOC_FAMILY_LPC) + CLOCK_EnableClock(kCLOCK_Mrt); +#elif defined(CONFIG_SOC_FAMILY_IMX) + CLOCK_EnableClock(kCLOCK_Mrt0); +#endif + } +#endif /* defined(CONFIG_COUNTER_NXP_MRT) */ return 0; } @@ -145,6 +152,9 @@ static int mcux_lpc_syscon_clock_control_get_subsys_rate( break; #endif +#if defined(CONFIG_COUNTER_NXP_MRT) + case MCUX_MRT_CLK: +#endif #if defined(CONFIG_PWM_MCUX_SCTIMER) case MCUX_SCTIMER_CLK: #endif @@ -168,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_pwm.c b/drivers/clock_control/clock_control_pwm.c new file mode 100644 index 000000000000000..1936e3ab6cce25e --- /dev/null +++ b/drivers/clock_control/clock_control_pwm.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2023 Andriy Gelman + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT pwm_clock + +#include + +#include +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL +#include +LOG_MODULE_REGISTER(clock_control_pwm); + +BUILD_ASSERT(CONFIG_CLOCK_CONTROL_PWM_INIT_PRIORITY > CONFIG_PWM_INIT_PRIORITY, + "PWM must have a higher priority than PWM clock control"); + +#define NUM_PWM_CLOCKS 1 + +struct clock_control_pwm_config { + const struct pwm_dt_spec pwm_dt; + const uint16_t pwm_on_delay; +}; + +struct clock_control_pwm_data { + uint32_t clock_frequency; + bool is_enabled; +}; + +static int clock_control_pwm_on(const struct device *dev, clock_control_subsys_t sys) +{ + struct clock_control_pwm_data *data = dev->data; + const struct clock_control_pwm_config *config = dev->config; + const struct pwm_dt_spec *spec; + int id = (int)sys; + int ret; + + if (id >= NUM_PWM_CLOCKS) { + return -EINVAL; + } + + spec = &config->pwm_dt; + if (data->clock_frequency == 0) { + ret = pwm_set_dt(spec, spec->period, spec->period / 2); + } else { + uint64_t cycles_per_sec; + uint32_t period_cycles; + + ret = pwm_get_cycles_per_sec(spec->dev, spec->channel, &cycles_per_sec); + if (ret) { + return ret; + } + + if (cycles_per_sec % data->clock_frequency > 0) { + LOG_WRN("Target clock frequency cannot be expressed in PWM clock ticks"); + } + + period_cycles = cycles_per_sec / data->clock_frequency; + ret = pwm_set_cycles(spec->dev, spec->channel, period_cycles, period_cycles / 2, + spec->flags); + } + + if (ret) { + return ret; + } + + k_busy_wait(config->pwm_on_delay); + + data->is_enabled = true; + + return 0; +} + +static int clock_control_pwm_get_rate(const struct device *dev, clock_control_subsys_t sys, + uint32_t *rate) +{ + struct clock_control_pwm_data *data = dev->data; + const struct clock_control_pwm_config *config = dev->config; + int id = (int)sys; + + if (id >= NUM_PWM_CLOCKS) { + return -EINVAL; + } + + if (data->clock_frequency > 0) { + *rate = data->clock_frequency; + } else { + *rate = NSEC_PER_SEC / config->pwm_dt.period; + } + + return 0; +} + +static int clock_control_pwm_set_rate(const struct device *dev, clock_control_subsys_rate_t sys, + clock_control_subsys_rate_t rate) +{ + struct clock_control_pwm_data *data = dev->data; + uint32_t rate_hz = (uint32_t)rate; + int id = (int)sys; + + if (id >= NUM_PWM_CLOCKS) { + return -EINVAL; + } + + if (data->clock_frequency == rate_hz && data->is_enabled) { + return -EALREADY; + } + + data->clock_frequency = rate_hz; + + return clock_control_pwm_on(dev, sys); +} + +static int clock_control_pwm_init(const struct device *dev) +{ + const struct clock_control_pwm_config *config = dev->config; + + if (!device_is_ready(config->pwm_dt.dev)) { + return -ENODEV; + } + + return 0; +} + +static struct clock_control_driver_api clock_control_pwm_api = { + .on = clock_control_pwm_on, + .get_rate = clock_control_pwm_get_rate, + .set_rate = clock_control_pwm_set_rate, +}; + +#define PWM_CLOCK_INIT(i) \ + \ + BUILD_ASSERT(DT_INST_PROP_LEN(i, pwms) <= 1, \ + "One PWM per clock control node is supported"); \ + \ + BUILD_ASSERT(DT_INST_PROP(i, pwm_on_delay) <= UINT16_MAX, \ + "Maximum pwm-on-delay is 65535 usec"); \ + \ + static const struct clock_control_pwm_config clock_control_pwm_config_##i = { \ + .pwm_dt = PWM_DT_SPEC_INST_GET(i), \ + .pwm_on_delay = DT_INST_PROP(i, pwm_on_delay), \ + }; \ + \ + static struct clock_control_pwm_data clock_control_pwm_data_##i = { \ + .clock_frequency = DT_INST_PROP_OR(i, clock_frequency, 0), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(i, clock_control_pwm_init, NULL, &clock_control_pwm_data_##i, \ + &clock_control_pwm_config_##i, POST_KERNEL, \ + CONFIG_CLOCK_CONTROL_PWM_INIT_PRIORITY, &clock_control_pwm_api); + +DT_INST_FOREACH_STATUS_OKAY(PWM_CLOCK_INIT) diff --git a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c index 26b0b1959c6fb35..a796c6efc6c53cc 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 000000000000000..c0d9f15cd581c27 --- /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_renesas_cpg_mssr.h b/drivers/clock_control/clock_control_renesas_cpg_mssr.h index 13d3cbeeb4e468c..6829d5a96b6cd85 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 000000000000000..382625c2a2f23aa --- /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 000000000000000..4deec67423b3f63 --- /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 c5ce8a77f229f8f..60c98f8668a0fc6 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 ba5ba2e4673515b..d3adbe62535d75a 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 a5a6a055f440593..f6f0bbb003314bc 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 c95d8ab1294fe88..9d76004c92fdf45 100644 --- a/drivers/clock_control/clock_stm32_ll_h7.c +++ b/drivers/clock_control/clock_stm32_ll_h7.c @@ -107,6 +107,7 @@ #define AHB_FREQ_MAX 275000000UL #define APBx_FREQ_MAX 137500000UL #elif defined(CONFIG_SOC_STM32H7A3XX) || defined(CONFIG_SOC_STM32H7A3XXQ) ||\ + defined(CONFIG_SOC_STM32H7B0XX) || defined(CONFIG_SOC_STM32H7B0XXQ) ||\ defined(CONFIG_SOC_STM32H7B3XX) || defined(CONFIG_SOC_STM32H7B3XXQ) #define SYSCLK_FREQ_MAX 280000000UL #define AHB_FREQ_MAX 280000000UL @@ -585,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)) { @@ -818,17 +824,17 @@ 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) || \ + defined(CONFIG_SOC_STM32H7B0XX) || defined(CONFIG_SOC_STM32H7B0XXQ) || \ defined(CONFIG_SOC_STM32H7B3XX) || defined(CONFIG_SOC_STM32H7B3XXQ) LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_HSEM); #else @@ -910,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 46b834c52e9f4d8..5cc3b8651c77416 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, }; @@ -287,7 +313,7 @@ static int get_vco_input_range(uint32_t m_div, uint32_t *range) static void set_regu_voltage(uint32_t hclk_freq) { - if (hclk_freq < MHZ(16)) { + if (hclk_freq <= MHZ(16)) { LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2); } else { LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); @@ -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 6131fcd4c0672e7..a10fede688704b1 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/clock_control/clock_stm32g0.c b/drivers/clock_control/clock_stm32g0.c index 50558350141b88e..5f7a3bfb1ad4dd3 100644 --- a/drivers/clock_control/clock_stm32g0.c +++ b/drivers/clock_control/clock_stm32g0.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -74,4 +75,18 @@ void config_enable_default_clocks(void) { /* Enable the power interface clock */ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR); + +#if defined(CRS) + if (IS_ENABLED(STM32_HSI48_CRS_USB_SOF)) { + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_CRS); + /* + * After reset the CRS configuration register + * (CRS_CFGR) value corresponds to an USB SOF + * synchronization. FIXME: write it anyway. + */ + LL_CRS_EnableAutoTrimming(); + LL_CRS_EnableFreqErrorCounter(); + } +#endif /* defined(CRS) */ + } diff --git a/drivers/console/Kconfig b/drivers/console/Kconfig index 606ce1fe6d6822d..28dcf9fbc16bada 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 378bbe91ff3897e..5e5e10963f0c4b5 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; } @@ -474,7 +473,7 @@ static void uart_console_isr(const struct device *unused, void *user_data) * The input hook indicates that no further processing * should be done by this handler. */ - return; + continue; } #endif @@ -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 30b0c7be7180a9a..2b068e6810c4b05 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/uart_mux.c b/drivers/console/uart_mux.c index ba882b038eeec8d..ca445a1f5b711ad 100644 --- a/drivers/console/uart_mux.c +++ b/drivers/console/uart_mux.c @@ -10,7 +10,7 @@ LOG_MODULE_REGISTER(uart_mux, CONFIG_UART_MUX_LOG_LEVEL); #include #include #include -#include +#include #include #include #include diff --git a/drivers/console/xtensa_sim_console.c b/drivers/console/xtensa_sim_console.c index 16e48eeee484fdc..316162ddc0c1afd 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/CMakeLists.txt b/drivers/counter/CMakeLists.txt index 3a59312da249b22..50a1ffad44193e7 100644 --- a/drivers/counter/CMakeLists.txt +++ b/drivers/counter/CMakeLists.txt @@ -44,7 +44,8 @@ zephyr_library_sources_ifdef(CONFIG_COUNTER_INFINEON_CAT1 counter_ifx_cat1 zephyr_library_sources_ifdef(CONFIG_ACE_V1X_ART_COUNTER counter_ace_v1x_art.c) zephyr_library_sources_ifdef(CONFIG_ACE_V1X_RTC_COUNTER counter_ace_v1x_rtc.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_NXP_S32_SYS_TIMER counter_nxp_s32_sys_timer.c) -zephyr_library_sources_ifdef(CONFIG_COUNTER_TIMER_GD32 counter_gd32_timer.c) +zephyr_library_sources_ifdef(CONFIG_COUNTER_TIMER_GD32 counter_gd32_timer.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_SNPS_DW counter_dw_timer.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_SHELL counter_timer_shell.c) -zephyr_library_sources_ifdef(CONFIG_COUNTER_TIMER_RPI_PICO counter_rpi_pico_timer.c) +zephyr_library_sources_ifdef(CONFIG_COUNTER_TIMER_RPI_PICO counter_rpi_pico_timer.c) +zephyr_library_sources_ifdef(CONFIG_COUNTER_NXP_MRT counter_nxp_mrt.c) diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index 956c5d59f642ab6..16adaee75b2728a 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -94,4 +94,6 @@ source "drivers/counter/Kconfig.dw" source "drivers/counter/Kconfig.rpi_pico" +source "drivers/counter/Kconfig.nxp_mrt" + endif # COUNTER diff --git a/drivers/counter/Kconfig.gd32 b/drivers/counter/Kconfig.gd32 index eb5d5897af26c1d..fcb8913434e4d6c 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 bd012db822c1de4..49f063116d5f5f4 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/Kconfig.native_posix b/drivers/counter/Kconfig.native_posix index 362eb00da1c7b36..a342ed07a3069a4 100644 --- a/drivers/counter/Kconfig.native_posix +++ b/drivers/counter/Kconfig.native_posix @@ -10,3 +10,8 @@ config COUNTER_NATIVE_POSIX_FREQUENCY int "native_posix counter frequency in Hz" default 1000 depends on COUNTER_NATIVE_POSIX + +config COUNTER_NATIVE_POSIX_NBR_CHANNELS + int "native counter, number of channels" + default 4 + depends on COUNTER_NATIVE_POSIX diff --git a/drivers/counter/Kconfig.nxp_mrt b/drivers/counter/Kconfig.nxp_mrt new file mode 100644 index 000000000000000..a395ada36b459b6 --- /dev/null +++ b/drivers/counter/Kconfig.nxp_mrt @@ -0,0 +1,9 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config COUNTER_NXP_MRT + bool "NXP MRT driver" + default y if DT_HAS_NXP_MRT_CHANNEL_ENABLED && \ + DT_HAS_NXP_MRT_ENABLED + help + Enable driver for the NXP Multirate Timer (MRT). diff --git a/drivers/counter/counter_ambiq_timer.c b/drivers/counter/counter_ambiq_timer.c index 94549d6568576c4..67df6c5647f6906 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_handlers.c b/drivers/counter/counter_handlers.c index a493ea0c765040e..15cd0cb588163a3 100644 --- a/drivers/counter/counter_handlers.c +++ b/drivers/counter/counter_handlers.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include /* For those APIs that just take one argument which is a counter driver @@ -13,7 +13,7 @@ #define COUNTER_HANDLER(name) \ static inline int z_vrfy_counter_##name(const struct device *dev) \ { \ - Z_OOPS(Z_SYSCALL_DRIVER_COUNTER(dev, name)); \ + K_OOPS(K_SYSCALL_DRIVER_COUNTER(dev, name)); \ return z_impl_counter_ ## name((const struct device *)dev); \ } @@ -27,21 +27,21 @@ COUNTER_HANDLER(start) static inline bool z_vrfy_counter_is_counting_up(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); return z_impl_counter_is_counting_up((const struct device *)dev); } #include static inline uint8_t z_vrfy_counter_get_num_of_channels(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); return z_impl_counter_get_num_of_channels((const struct device *)dev); } #include static inline uint32_t z_vrfy_counter_get_frequency(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); return z_impl_counter_get_frequency((const struct device *)dev); } #include @@ -49,7 +49,7 @@ static inline uint32_t z_vrfy_counter_get_frequency(const struct device *dev) static inline uint32_t z_vrfy_counter_us_to_ticks(const struct device *dev, uint64_t us) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); return z_impl_counter_us_to_ticks((const struct device *)dev, (uint64_t)us); } @@ -58,7 +58,7 @@ static inline uint32_t z_vrfy_counter_us_to_ticks(const struct device *dev, static inline uint64_t z_vrfy_counter_ticks_to_us(const struct device *dev, uint32_t ticks) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); return z_impl_counter_ticks_to_us((const struct device *)dev, (uint32_t)ticks); } @@ -67,16 +67,16 @@ static inline uint64_t z_vrfy_counter_ticks_to_us(const struct device *dev, static inline int z_vrfy_counter_get_value(const struct device *dev, uint32_t *ticks) { - Z_OOPS(Z_SYSCALL_DRIVER_COUNTER(dev, get_value)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(ticks, sizeof(*ticks))); + K_OOPS(K_SYSCALL_DRIVER_COUNTER(dev, get_value)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(ticks, sizeof(*ticks))); return z_impl_counter_get_value((const struct device *)dev, ticks); } static inline int z_vrfy_counter_get_value_64(const struct device *dev, uint64_t *ticks) { - Z_OOPS(Z_SYSCALL_DRIVER_COUNTER(dev, get_value_64)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(ticks, sizeof(*ticks))); + K_OOPS(K_SYSCALL_DRIVER_COUNTER(dev, get_value_64)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(ticks, sizeof(*ticks))); return z_impl_counter_get_value_64((const struct device *)dev, ticks); } @@ -88,9 +88,9 @@ static inline int z_vrfy_counter_set_channel_alarm(const struct device *dev, { struct counter_alarm_cfg cfg_copy; - Z_OOPS(Z_SYSCALL_DRIVER_COUNTER(dev, set_alarm)); - Z_OOPS(z_user_from_copy(&cfg_copy, alarm_cfg, sizeof(cfg_copy))); - Z_OOPS(Z_SYSCALL_VERIFY_MSG(cfg_copy.callback == NULL, + K_OOPS(K_SYSCALL_DRIVER_COUNTER(dev, set_alarm)); + K_OOPS(k_usermode_from_copy(&cfg_copy, alarm_cfg, sizeof(cfg_copy))); + K_OOPS(K_SYSCALL_VERIFY_MSG(cfg_copy.callback == NULL, "callbacks may not be set from user mode")); return z_impl_counter_set_channel_alarm((const struct device *)dev, (uint8_t)chan_id, @@ -102,7 +102,7 @@ static inline int z_vrfy_counter_set_channel_alarm(const struct device *dev, static inline int z_vrfy_counter_cancel_channel_alarm(const struct device *dev, uint8_t chan_id) { - Z_OOPS(Z_SYSCALL_DRIVER_COUNTER(dev, cancel_alarm)); + K_OOPS(K_SYSCALL_DRIVER_COUNTER(dev, cancel_alarm)); return z_impl_counter_cancel_channel_alarm((const struct device *)dev, (uint8_t)chan_id); } @@ -114,9 +114,9 @@ static inline int z_vrfy_counter_set_top_value(const struct device *dev, { struct counter_top_cfg cfg_copy; - Z_OOPS(Z_SYSCALL_DRIVER_COUNTER(dev, set_top_value)); - Z_OOPS(z_user_from_copy(&cfg_copy, cfg, sizeof(cfg_copy))); - Z_OOPS(Z_SYSCALL_VERIFY_MSG(cfg_copy.callback == NULL, + K_OOPS(K_SYSCALL_DRIVER_COUNTER(dev, set_top_value)); + K_OOPS(k_usermode_from_copy(&cfg_copy, cfg, sizeof(cfg_copy))); + K_OOPS(K_SYSCALL_VERIFY_MSG(cfg_copy.callback == NULL, "callbacks may not be set from user mode")); return z_impl_counter_set_top_value((const struct device *)dev, (const struct counter_top_cfg *) @@ -126,14 +126,14 @@ static inline int z_vrfy_counter_set_top_value(const struct device *dev, static inline uint32_t z_vrfy_counter_get_top_value(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_COUNTER(dev, get_top_value)); + K_OOPS(K_SYSCALL_DRIVER_COUNTER(dev, get_top_value)); return z_impl_counter_get_top_value((const struct device *)dev); } #include static inline uint32_t z_vrfy_counter_get_max_top_value(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); return z_impl_counter_get_max_top_value((const struct device *)dev); } #include @@ -141,7 +141,7 @@ static inline uint32_t z_vrfy_counter_get_max_top_value(const struct device *dev static inline uint32_t z_vrfy_counter_get_guard_period(const struct device *dev, uint32_t flags) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); return z_impl_counter_get_guard_period((const struct device *)dev, flags); } @@ -150,7 +150,7 @@ static inline uint32_t z_vrfy_counter_get_guard_period(const struct device *dev, static inline int z_vrfy_counter_set_guard_period(const struct device *dev, uint32_t ticks, uint32_t flags) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_COUNTER)); return z_impl_counter_set_guard_period((const struct device *)dev, ticks, flags); diff --git a/drivers/counter/counter_ll_stm32_rtc.c b/drivers/counter/counter_ll_stm32_rtc.c index bb8a119409b682e..317bd367391a017 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 @@ -184,11 +185,22 @@ static void rtc_stm32_irq_config(const struct device *dev); static int rtc_stm32_start(const struct device *dev) { +#if defined(CONFIG_SOC_SERIES_STM32WBAX) + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + const struct rtc_stm32_config *cfg = dev->config; + + /* 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; + } +#else ARG_UNUSED(dev); z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); LL_RCC_EnableRTC(); z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); +#endif return 0; } @@ -196,11 +208,22 @@ static int rtc_stm32_start(const struct device *dev) static int rtc_stm32_stop(const struct device *dev) { +#if defined(CONFIG_SOC_SERIES_STM32WBAX) + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + const struct rtc_stm32_config *cfg = dev->config; + + /* 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; + } +#else ARG_UNUSED(dev); z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); LL_RCC_DisableRTC(); z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); +#endif return 0; } @@ -504,7 +527,7 @@ void rtc_stm32_isr(const struct device *dev) || defined(CONFIG_SOC_SERIES_STM32L5X) \ || defined(CONFIG_SOC_SERIES_STM32H5X) LL_EXTI_ClearRisingFlag_0_31(RTC_EXTI_LINE); -#elif defined(CONFIG_SOC_SERIES_STM32U5X) +#elif defined(CONFIG_SOC_SERIES_STM32U5X) || defined(CONFIG_SOC_SERIES_STM32WBAX) /* in STM32U5 family RTC is not connected to EXTI */ #else LL_EXTI_ClearFlag_0_31(RTC_EXTI_LINE); @@ -546,7 +569,9 @@ static int rtc_stm32_init(const struct device *dev) return -EIO; } +#if !defined(CONFIG_SOC_SERIES_STM32WBAX) LL_RCC_EnableRTC(); +#endif z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); @@ -570,7 +595,7 @@ static int rtc_stm32_init(const struct device *dev) #if defined(CONFIG_SOC_SERIES_STM32H7X) && defined(CONFIG_CPU_CORTEX_M4) LL_C2_EXTI_EnableIT_0_31(RTC_EXTI_LINE); LL_EXTI_EnableRisingTrig_0_31(RTC_EXTI_LINE); -#elif defined(CONFIG_SOC_SERIES_STM32U5X) +#elif defined(CONFIG_SOC_SERIES_STM32U5X) || defined(CONFIG_SOC_SERIES_STM32WBAX) /* in STM32U5 family RTC is not connected to EXTI */ #else LL_EXTI_EnableIT_0_31(RTC_EXTI_LINE); @@ -624,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, @@ -639,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 3c7d561db0f3640..2c012d31c40248c 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 18cafe1272da47b..433fef0683cd0d2 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 @@ -19,23 +17,76 @@ struct mcux_lpc_rtc_data { 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; const struct mcux_lpc_rtc_config *config = CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); - RTC_StartTimer(config->base); + RTC_EnableTimer(config->base, true); return 0; } @@ -46,7 +97,7 @@ static int mcux_lpc_rtc_stop(const struct device *dev) const struct mcux_lpc_rtc_config *config = CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); - RTC_StopTimer(config->base); + RTC_EnableTimer(config->base, false); /* clear out any set alarms */ RTC_SetSecondsTimerMatch(config->base, 0); @@ -128,26 +179,7 @@ static int mcux_lpc_rtc_cancel_alarm(const struct device *dev, uint8_t chan_id) static int mcux_lpc_rtc_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->ticks != info->max_top_value) { - LOG_ERR("Wrap can only be set to 0x%x.", info->max_top_value); - return -ENOTSUP; - } - - if (!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) { - RTC_StopTimer(config->base); - RTC_SetSecondsTimerCount(config->base, 0); - RTC_StartTimer(config->base); - } - - data->top_callback = cfg->callback; - data->top_user_data = cfg->user_data; - - return 0; + return -ENOTSUP; } static uint32_t mcux_lpc_rtc_get_pending_int(const struct device *dev) @@ -166,42 +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); - - - 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 - */ - RTC_StopTimer(config->base); - if (RTC_GetStatusFlags(config->base) & RTC_CTRL_ALARM1HZ_MASK) { - RTC_ClearStatusFlags(config->base, kRTC_AlarmFlag); - } - RTC_StartTimer(config->base); -} - static int mcux_lpc_rtc_init(const struct device *dev) { const struct counter_config_info *info = dev->config; @@ -210,6 +206,9 @@ static int mcux_lpc_rtc_init(const struct device *dev) 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) { @@ -231,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, \ @@ -246,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) \ @@ -261,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_native_posix.c b/drivers/counter/counter_native_posix.c index aa221a11fdc472f..d03517b1b866dec 100644 --- a/drivers/counter/counter_native_posix.c +++ b/drivers/counter/counter_native_posix.c @@ -6,6 +6,7 @@ #define DT_DRV_COMPAT zephyr_native_posix_counter +#include #include #include #include @@ -14,38 +15,80 @@ #include #define DRIVER_CONFIG_INFO_FLAGS (COUNTER_CONFIG_INFO_COUNT_UP) -#define DRIVER_CONFIG_INFO_CHANNELS 1 +#define DRIVER_CONFIG_INFO_CHANNELS CONFIG_COUNTER_NATIVE_POSIX_NBR_CHANNELS #define COUNTER_NATIVE_POSIX_IRQ_FLAGS (0) #define COUNTER_NATIVE_POSIX_IRQ_PRIORITY (2) #define COUNTER_PERIOD (USEC_PER_SEC / CONFIG_COUNTER_NATIVE_POSIX_FREQUENCY) #define TOP_VALUE (UINT_MAX) -static struct counter_alarm_cfg pending_alarm; -static bool is_alarm_pending; +static struct counter_alarm_cfg pending_alarm[DRIVER_CONFIG_INFO_CHANNELS]; +static bool is_alarm_pending[DRIVER_CONFIG_INFO_CHANNELS]; +static struct counter_top_cfg top; +static bool is_top_set; static const struct device *device; +static void schedule_next_isr(void) +{ + int64_t current_value = hw_counter_get_value(); + uint32_t next_time = top.ticks; /* top.ticks is TOP_VALUE if is_top_set == false */ + + if (current_value == top.ticks) { + current_value = -1; + } + + for (int i = 0; i < DRIVER_CONFIG_INFO_CHANNELS; i++) { + if (is_alarm_pending[i]) { + if (pending_alarm[i].ticks > current_value) { + /* If the alarm is not after a wrap */ + next_time = MIN(pending_alarm[i].ticks, next_time); + } + } + } + + /* We will at least get an interrupt at top.ticks even if is_top_set == false, + * which is fine. We may use that to set the next alarm if needed + */ + hw_counter_set_target(next_time); +} + static void counter_isr(const void *arg) { ARG_UNUSED(arg); uint32_t current_value = hw_counter_get_value(); - if (is_alarm_pending) { - is_alarm_pending = false; - pending_alarm.callback(device, 0, current_value, - pending_alarm.user_data); + for (int i = 0; i < DRIVER_CONFIG_INFO_CHANNELS; i++) { + if (is_alarm_pending[i] && (current_value == pending_alarm[i].ticks)) { + is_alarm_pending[i] = false; + if (pending_alarm[i].callback) { + pending_alarm[i].callback(device, i, current_value, + pending_alarm[i].user_data); + } + } + } + + if (is_top_set && (current_value == top.ticks)) { + if (top.callback) { + top.callback(device, top.user_data); + } } + + schedule_next_isr(); } static int ctr_init(const struct device *dev) { device = dev; - is_alarm_pending = false; + memset(is_alarm_pending, 0, sizeof(is_alarm_pending)); + is_top_set = false; + top.ticks = TOP_VALUE; IRQ_CONNECT(COUNTER_EVENT_IRQ, COUNTER_NATIVE_POSIX_IRQ_PRIORITY, counter_isr, NULL, COUNTER_NATIVE_POSIX_IRQ_FLAGS); + irq_enable(COUNTER_EVENT_IRQ); hw_counter_set_period(COUNTER_PERIOD); - hw_counter_set_target(TOP_VALUE); + hw_counter_set_wrap_value((uint64_t)top.ticks + 1); + hw_counter_reset(); return 0; } @@ -54,6 +97,7 @@ static int ctr_start(const struct device *dev) { ARG_UNUSED(dev); + schedule_next_isr(); hw_counter_start(); return 0; } @@ -80,19 +124,56 @@ static uint32_t ctr_get_pending_int(const struct device *dev) return 0; } +static bool is_any_alarm_pending(void) +{ + for (int i = 0; i < DRIVER_CONFIG_INFO_CHANNELS; i++) { + if (is_alarm_pending[i]) { + return true; + } + } + return false; +} + static int ctr_set_top_value(const struct device *dev, const struct counter_top_cfg *cfg) { ARG_UNUSED(dev); - ARG_UNUSED(cfg); - posix_print_warning("%s not supported\n", __func__); - return -ENOTSUP; + if (is_any_alarm_pending()) { + posix_print_warning("Can't set top value while alarm is active\n"); + return -EBUSY; + } + + uint32_t current_value = hw_counter_get_value(); + + if (cfg->flags & COUNTER_TOP_CFG_DONT_RESET) { + if (current_value >= cfg->ticks) { + if (cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE) { + hw_counter_reset(); + } + return -ETIME; + } + } else { + hw_counter_reset(); + } + + top = *cfg; + hw_counter_set_wrap_value((uint64_t)top.ticks + 1); + + if ((cfg->ticks == TOP_VALUE) && !cfg->callback) { + is_top_set = false; + } else { + is_top_set = true; + } + + schedule_next_isr(); + + return 0; } static uint32_t ctr_get_top_value(const struct device *dev) { - return TOP_VALUE; + return top.ticks; } static int ctr_set_alarm(const struct device *dev, uint8_t chan_id, @@ -100,21 +181,31 @@ static int ctr_set_alarm(const struct device *dev, uint8_t chan_id, { ARG_UNUSED(dev); - if (chan_id >= DRIVER_CONFIG_INFO_CHANNELS) { - posix_print_warning("channel %u is not supported\n", chan_id); - return -ENOTSUP; - } + if (is_alarm_pending[chan_id]) + return -EBUSY; - pending_alarm = *alarm_cfg; - is_alarm_pending = true; + uint32_t ticks = alarm_cfg->ticks; + + if (ticks > top.ticks) { + posix_print_warning("Alarm ticks %u exceed top ticks %u\n", ticks, + top.ticks); + return -EINVAL; + } if (!(alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE)) { - pending_alarm.ticks = - hw_counter_get_value() + pending_alarm.ticks; + uint32_t current_value = hw_counter_get_value(); + + ticks += current_value; + if (ticks > top.ticks) { /* Handle wrap arounds */ + ticks -= (top.ticks + 1); /* The count period is top.ticks + 1 */ + } } - hw_counter_set_target(pending_alarm.ticks); - irq_enable(COUNTER_EVENT_IRQ); + pending_alarm[chan_id] = *alarm_cfg; + pending_alarm[chan_id].ticks = ticks; + is_alarm_pending[chan_id] = true; + + schedule_next_isr(); return 0; } @@ -123,12 +214,14 @@ static int ctr_cancel_alarm(const struct device *dev, uint8_t chan_id) { ARG_UNUSED(dev); - if (chan_id >= DRIVER_CONFIG_INFO_CHANNELS) { - posix_print_warning("channel %u is not supported\n", chan_id); + if (!hw_counter_is_started()) { + posix_print_warning("Counter not started\n"); return -ENOTSUP; } - is_alarm_pending = false; + is_alarm_pending[chan_id] = false; + + schedule_next_isr(); return 0; } diff --git a/drivers/counter/counter_nrfx_rtc.c b/drivers/counter/counter_nrfx_rtc.c index af35564a158756d..398921f2bd61df5 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 df5b617525739b1..47537b16d7d44a7 100644 --- a/drivers/counter/counter_nrfx_timer.c +++ b/drivers/counter/counter_nrfx_timer.c @@ -253,6 +253,7 @@ static int set_top_value(const struct device *dev, nrf_timer_int_disable(timer, COUNTER_TOP_INT_MASK); nrf_timer_cc_set(timer, TOP_CH, cfg->ticks); + nrf_timer_event_clear(timer, COUNTER_TOP_EVT); nrf_timer_shorts_enable(timer, COUNTER_OVERFLOW_SHORT); data->top_cb = cfg->callback; @@ -363,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++) { @@ -436,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_nxp_mrt.c b/drivers/counter/counter_nxp_mrt.c new file mode 100644 index 000000000000000..741e7b34d40c99f --- /dev/null +++ b/drivers/counter/counter_nxp_mrt.c @@ -0,0 +1,341 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * MRT (Multirate timer) is a lightweight timer with multiple independent channels, each capable + * of signalling the shared interrupt with a different period. This driver treats all the channels + * as separate devices adhering to the counter API. The parent device is responsible for the + * initialization, interrupt handling, and any other module-wide tasks. The current implementation + * of this driver prioritizes minimizing image size over speed, because it is not expected for the + * functions to be called very often, and this IP is mostly present on low memory devices. + */ + +#define DT_DRV_COMPAT nxp_mrt + +#include +#include +#include +#include +#include +#include + +#define LOG_MODULE_NAME counter_mrt +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_COUNTER_LOG_LEVEL); + +/* Device holds a pointer to pointer to data */ +#define MRT_CHANNEL_DATA(dev) \ + (*(struct nxp_mrt_channel_data *const *const)dev->data) + +/* Device config->data is an array of data pointers ordered by channel number, + * dev->data is a pointer to one of these pointers in that array, + * so the value of the dev->data - dev->config->data is the channel index + */ +#define MRT_CHANNEL_ID(dev) \ + (((struct nxp_mrt_channel_data *const *)dev->data) - \ + ((const struct nxp_mrt_config *)dev->config)->data) + +/* Specific for each channel */ +struct nxp_mrt_channel_data { + uint32_t top; + counter_top_callback_t cb; + void *user_data; +}; + +/* Shared between all channels */ +struct nxp_mrt_config { + struct counter_config_info info; + MRT_Type *base; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; + void (*irq_config_func)(const struct device *dev); + struct nxp_mrt_channel_data *const *data; + const struct device *const *channels; +}; + +static int nxp_mrt_stop(const struct device *dev) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + int channel_id = MRT_CHANNEL_ID(dev); + + LOG_DBG("MRT@%p channel %d stopped", base, channel_id); + LOG_WRN("MRT channel resets upon stopping"); + + /* LOAD bit and 0 ivalue allows us to forcibly stop the timer */ + base->CHANNEL[channel_id].INTVAL = MRT_CHANNEL_INTVAL_LOAD(1); + + return 0; +} + +static int nxp_mrt_start(const struct device *dev) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + struct nxp_mrt_channel_data *data = MRT_CHANNEL_DATA(dev); + int channel_id = MRT_CHANNEL_ID(dev); + + if (data->top <= 1) { + /* Zephyr API says default should be max top value */ + LOG_INF("\"Started\" MRT@%p channel %d with default value %d", + base, channel_id, config->info.max_top_value); + data->top = config->info.max_top_value; + } + + /* Start with previously configured top value (if already running this has no effect) */ + base->CHANNEL[channel_id].INTVAL = data->top; + + LOG_DBG("MRT@%p channel %d started with top value %d", base, channel_id, data->top); + + return 0; +} + +static int nxp_mrt_get_value(const struct device *dev, uint32_t *ticks) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + int channel_id = MRT_CHANNEL_ID(dev); + + *ticks = base->CHANNEL[channel_id].TIMER & MRT_CHANNEL_TIMER_VALUE_MASK; + + return 0; +} + + +static int nxp_mrt_set_top_value(const struct device *dev, const struct counter_top_cfg *cfg) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + struct nxp_mrt_channel_data *data = MRT_CHANNEL_DATA(dev); + int channel_id = MRT_CHANNEL_ID(dev); + /* By default in Zephyr API, the counter resets on changing top value */ + bool reset = !(cfg->flags & COUNTER_TOP_CFG_DONT_RESET); + bool active = base->CHANNEL[channel_id].STAT & MRT_CHANNEL_STAT_RUN_MASK; + uint32_t current_val = base->CHANNEL[channel_id].TIMER & MRT_CHANNEL_TIMER_VALUE_MASK; + int ret = 0; + + /* Store for use by counter_start */ + data->top = cfg->ticks; + + /* Used by ISR */ + data->cb = cfg->callback; + data->user_data = cfg->user_data; + + + /* If not yet started, wait for counter_start because setting reg value starts timer */ + if (!active) { + LOG_DBG("Set MRT@%p channel %d top value to %d", base, channel_id, data->top); + return ret; + } + + /* Otherwise if currently running, need to check for lateness */ + if (cfg->ticks < current_val) { + LOG_WRN("MRT@%p channel %d received requested top value %d which is " + "smaller than current count %d", + base, channel_id, cfg->ticks, current_val); + /* Zephyr API says return this error in case of lateness + * when COUNTER_TOP_CFG_DONT_RESET is set but can still set period + */ + ret = reset ? 0 : -ETIME; + /* If user said not to reset, they can also clarify exception for lateness */ + reset |= cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE; + } + + /* Sets the top value. If we need to reset, LOAD bit does this */ + base->CHANNEL[channel_id].INTVAL = MRT_CHANNEL_INTVAL_IVALUE(cfg->ticks) | + MRT_CHANNEL_INTVAL_LOAD(reset ? 1 : 0); + + LOG_DBG("Changed MRT@%p channel %d top value while active to %d", + base, channel_id, + base->CHANNEL[channel_id].INTVAL & MRT_CHANNEL_INTVAL_IVALUE_MASK); + + return ret; +} + +static uint32_t nxp_mrt_get_top_value(const struct device *dev) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + int channel_id = MRT_CHANNEL_ID(dev); + + return base->CHANNEL[channel_id].INTVAL & MRT_CHANNEL_INTVAL_IVALUE_MASK; +} + +static uint32_t nxp_mrt_get_pending_int(const struct device *dev) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + int channel_id = MRT_CHANNEL_ID(dev); + + return base->CHANNEL[channel_id].STAT & MRT_CHANNEL_STAT_INTFLAG_MASK; +} + +static inline int nxp_mrt_set_alarm(const struct device *dev, + uint8_t chan_id, + const struct counter_alarm_cfg *alarm_cfg) +{ + ARG_UNUSED(dev); + ARG_UNUSED(chan_id); + ARG_UNUSED(alarm_cfg); + + LOG_ERR("MRT does not support alarms"); + return -ENOTSUP; +} + +static inline int nxp_mrt_cancel_alarm(const struct device *dev, uint8_t chan_id) +{ + ARG_UNUSED(dev); + ARG_UNUSED(chan_id); + + LOG_ERR("MRT does not support alarms"); + return -ENOTSUP; +} + +uint32_t nxp_mrt_get_freq(const struct device *dev) +{ + const struct nxp_mrt_config *config = dev->config; + uint32_t freq; + + clock_control_get_rate(config->clock_dev, config->clock_subsys, &freq); + + return freq; +} + +static int nxp_mrt_init(const struct device *dev) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + uint32_t num_channels = (base->MODCFG & MRT_MODCFG_NOC_MASK) >> MRT_MODCFG_NOC_SHIFT; + + clock_control_on(config->clock_dev, config->clock_subsys); + + config->irq_config_func(dev); + + /* Enable interrupts for all the channels that have devices */ + for (int i = 0; i < num_channels; i++) { + if (config->channels[i]) { + base->CHANNEL[i].CTRL = MRT_CHANNEL_CTRL_INTEN_MASK; + } + } + + return 0; +} + +static void nxp_mrt_isr(const struct device *dev) +{ + const struct nxp_mrt_config *config = dev->config; + MRT_Type *base = config->base; + uint32_t irq_pends = base->IRQ_FLAG; + uint32_t num_channels = (base->MODCFG & MRT_MODCFG_NOC_MASK) >> MRT_MODCFG_NOC_SHIFT; + + for (int i = 0; i < num_channels; i++) { + /* Channel IRQ pending flags lowest order bits in IRQ_FLAG register */ + if (!(irq_pends & (0x1 << i))) { + continue; + } + + LOG_DBG("Handling interrupt for MRT%p channel %d", base, i); + + /* W1C interrupt flag */ + base->CHANNEL[i].STAT |= MRT_CHANNEL_STAT_INTFLAG_MASK; + + /* Channel devs & pointer path to channel cbs is in shared config */ + if (config->data[i]->cb) { + config->data[i]->cb(config->channels[i], config->data[i]->user_data); + } + } +} + +struct counter_driver_api nxp_mrt_api = { + .get_value = nxp_mrt_get_value, + .start = nxp_mrt_start, + .stop = nxp_mrt_stop, + .set_top_value = nxp_mrt_set_top_value, + .get_top_value = nxp_mrt_get_top_value, + .get_pending_int = nxp_mrt_get_pending_int, + .set_alarm = nxp_mrt_set_alarm, + .cancel_alarm = nxp_mrt_cancel_alarm, + .get_freq = nxp_mrt_get_freq, +}; + +/* Creates a device for a channel (needed for counter API) */ +#define NXP_MRT_CHANNEL_DEV_INIT(node, mrt_inst) \ + DEVICE_DT_DEFINE(node, NULL, NULL, \ + (void *) \ + &nxp_mrt_##mrt_inst##_channel_datas[DT_REG_ADDR(node)], \ + &nxp_mrt_##mrt_inst##_config, \ + POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY, \ + &nxp_mrt_api); \ + +/* Creates a data struct for a channel device */ +#define NXP_MRT_CHANNEL_DATA_INIT(node) \ + static struct nxp_mrt_channel_data \ + nxp_mrt_channel_data_##node; \ + +/* Initializes an element of the channel data pointer array */ +#define NXP_MRT_CHANNEL_DATA_ARRAY_INIT(node) \ + [DT_REG_ADDR(node)] = \ + &nxp_mrt_channel_data_##node, + +/* Initializes an element of the channel device pointer array */ +#define NXP_MRT_CHANNEL_DEV_ARRAY_INIT(node) \ + [DT_REG_ADDR(node)] = DEVICE_DT_GET(node), + +#define NXP_MRT_INIT(n) \ + /* ISR is shared between all channels */ \ + static void nxp_mrt_##n##_irq_config_func(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ + nxp_mrt_isr, DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } \ + \ + /* Initialize all the data structs for active channels */ \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, NXP_MRT_CHANNEL_DATA_INIT) \ + \ + /* Create an array of const pointers to the data structs */ \ + static struct nxp_mrt_channel_data *const nxp_mrt_##n##_channel_datas \ + [DT_INST_PROP(n, num_channels)] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, \ + NXP_MRT_CHANNEL_DATA_ARRAY_INIT) \ + }; \ + \ + /* Forward declaration */ \ + const static struct nxp_mrt_config nxp_mrt_##n##_config; \ + \ + /* Create all the channel/counter devices */ \ + DT_INST_FOREACH_CHILD_STATUS_OKAY_VARGS(n, NXP_MRT_CHANNEL_DEV_INIT, n) \ + \ + /* This channel device array is needed by the module device ISR */ \ + const struct device *const nxp_mrt_##n##_channels \ + [DT_INST_PROP(n, num_channels)] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, \ + NXP_MRT_CHANNEL_DEV_ARRAY_INIT) \ + }; \ + \ + /* This config struct is shared by all the channels and parent device */\ + const static struct nxp_mrt_config nxp_mrt_##n##_config = { \ + .info = { \ + .max_top_value = \ + GENMASK(DT_INST_PROP(n, num_bits) - 1, 0), \ + .channels = 0, \ + }, \ + .base = (MRT_Type *)DT_INST_REG_ADDR(n), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (clock_control_subsys_t) \ + DT_INST_CLOCKS_CELL(n, name), \ + .irq_config_func = nxp_mrt_##n##_irq_config_func, \ + .data = nxp_mrt_##n##_channel_datas, \ + .channels = nxp_mrt_##n##_channels, \ + }; \ + \ + /* Init parent device in order to handle ISR and init. */ \ + DEVICE_DT_INST_DEFINE(n, &nxp_mrt_init, NULL, NULL, \ + &nxp_mrt_##n##_config, \ + POST_KERNEL, \ + CONFIG_COUNTER_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(NXP_MRT_INIT) diff --git a/drivers/counter/counter_nxp_s32_sys_timer.c b/drivers/counter/counter_nxp_s32_sys_timer.c index 1c25039aab299e3..47c1d0e3c3eeae7 100644 --- a/drivers/counter/counter_nxp_s32_sys_timer.c +++ b/drivers/counter/counter_nxp_s32_sys_timer.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_sys_timer + #include #include #include @@ -14,13 +16,8 @@ LOG_MODULE_REGISTER(nxp_s32_sys_timer, CONFIG_COUNTER_LOG_LEVEL); -#define SYS_TIMER_NODE(n) DT_NODELABEL(stm##n) #define SYS_TIMER_MAX_VALUE 0xFFFFFFFFU #define SYS_TIMER_NUM_CHANNELS 4 -#define SYS_TIMER_INSTANCE_ID(n) (n + 3 + CONFIG_NXP_S32_RTU_INDEX * 4) - -#define _SYS_TIMER_ISR(r, n) RTU##r##_STM_##n##_ISR -#define SYS_TIMER_ISR(r, n) _SYS_TIMER_ISR(r, n) struct nxp_s32_sys_timer_chan_data { counter_alarm_callback_t callback; @@ -119,7 +116,7 @@ static uint32_t nxp_s32_sys_timer_get_pending_int(const struct device *dev) uint8_t i; for (i = 0; i < counter_get_num_of_channels(dev); i++) { - flags = Stm_Ip_GetInterruptFlag(config->instance, i); + flags = Stm_Ip_GetInterruptStatusFlag(config->instance, i); if (flags) { break; } @@ -209,15 +206,24 @@ static const struct counter_driver_api nxp_s32_sys_timer_driver_api = { .channelMode = STM_IP_CH_MODE_ONESHOT, \ } +#define _SYS_TIMER_ISR(r, n) RTU##r##_STM_##n##_ISR +#define SYS_TIMER_ISR(r, n) _SYS_TIMER_ISR(r, n) + #define SYS_TIMER_ISR_DECLARE(n) \ extern void SYS_TIMER_ISR(CONFIG_NXP_S32_RTU_INDEX, n)(void) +#define SYS_TIMER_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_STM_##i##_BASE) ? i : 0) + +#define SYS_TIMER_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET STM_INSTANCE_COUNT, SYS_TIMER_HW_INSTANCE_CHECK, (|), n) + #define SYS_TIMER_INIT_DEVICE(n) \ SYS_TIMER_ISR_DECLARE(n); \ \ void nxp_s32_sys_timer_##n##_callback(uint8_t chan_id) \ { \ - const struct device *dev = DEVICE_DT_GET(SYS_TIMER_NODE(n)); \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ const struct nxp_s32_sys_timer_config *config = dev->config; \ struct nxp_s32_sys_timer_data *data = dev->data; \ struct nxp_s32_sys_timer_chan_data *ch_data = &data->ch_data[chan_id]; \ @@ -233,12 +239,10 @@ static const struct counter_driver_api nxp_s32_sys_timer_driver_api = { \ static int nxp_s32_sys_timer_##n##_init(const struct device *dev) \ { \ - IRQ_CONNECT(DT_IRQN(SYS_TIMER_NODE(n)), \ - DT_IRQ(SYS_TIMER_NODE(n), priority), \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ SYS_TIMER_ISR(CONFIG_NXP_S32_RTU_INDEX, n), \ - DEVICE_DT_GET(SYS_TIMER_NODE(n)), \ - DT_IRQ(SYS_TIMER_NODE(n), flags)); \ - irq_enable(DT_IRQN(SYS_TIMER_NODE(n))); \ + DEVICE_DT_INST_GET(n), DT_INST_IRQ(n, flags)); \ + irq_enable(DT_INST_IRQN(n)); \ \ return nxp_s32_sys_timer_init(dev); \ } \ @@ -252,19 +256,18 @@ static const struct counter_driver_api nxp_s32_sys_timer_driver_api = { .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ }, \ .hw_cfg = { \ - .stopInDebugMode = DT_PROP(SYS_TIMER_NODE(n), freeze), \ - .clockPrescaler = DT_PROP(SYS_TIMER_NODE(n), prescaler) - 1, \ + .stopInDebugMode = DT_INST_PROP(n, freeze), \ + .clockPrescaler = DT_INST_PROP(n, prescaler) - 1, \ }, \ .ch_cfg = { \ LISTIFY(SYS_TIMER_NUM_CHANNELS, SYS_TIMER_CHANNEL_CFG, (,), n) \ }, \ - .instance = SYS_TIMER_INSTANCE_ID(n), \ - .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(SYS_TIMER_NODE(n))), \ - .clock_subsys = (clock_control_subsys_t) \ - DT_CLOCKS_CELL(SYS_TIMER_NODE(n), name), \ + .instance = SYS_TIMER_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), \ }; \ \ - DEVICE_DT_DEFINE(SYS_TIMER_NODE(n), \ + DEVICE_DT_INST_DEFINE(n, \ nxp_s32_sys_timer_##n##_init, \ NULL, \ &nxp_s32_sys_timer_data_##n, \ @@ -273,18 +276,4 @@ static const struct counter_driver_api nxp_s32_sys_timer_driver_api = { CONFIG_COUNTER_INIT_PRIORITY, \ &nxp_s32_sys_timer_driver_api); -#if DT_NODE_HAS_STATUS(SYS_TIMER_NODE(0), okay) -SYS_TIMER_INIT_DEVICE(0) -#endif - -#if DT_NODE_HAS_STATUS(SYS_TIMER_NODE(1), okay) -SYS_TIMER_INIT_DEVICE(1) -#endif - -#if DT_NODE_HAS_STATUS(SYS_TIMER_NODE(2), okay) -SYS_TIMER_INIT_DEVICE(2) -#endif - -#if DT_NODE_HAS_STATUS(SYS_TIMER_NODE(3), okay) -SYS_TIMER_INIT_DEVICE(3) -#endif +DT_INST_FOREACH_STATUS_OKAY(SYS_TIMER_INIT_DEVICE) diff --git a/drivers/counter/counter_rpi_pico_timer.c b/drivers/counter/counter_rpi_pico_timer.c index 3e1a1dcbb0bd403..c2140d587774834 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/counter/maxim_ds3231.c b/drivers/counter/maxim_ds3231.c index 514ddd32b1af327..93d20639ecd1ba3 100644 --- a/drivers/counter/maxim_ds3231.c +++ b/drivers/counter/maxim_ds3231.c @@ -1300,7 +1300,7 @@ DEVICE_DT_INST_DEFINE(0, ds3231_init, NULL, &ds3231_0_data, #ifdef CONFIG_USERSPACE -#include +#include int z_vrfy_maxim_ds3231_get_syncpoint(const struct device *dev, struct maxim_ds3231_syncpoint *syncpoint) @@ -1308,13 +1308,13 @@ int z_vrfy_maxim_ds3231_get_syncpoint(const struct device *dev, struct maxim_ds3231_syncpoint value; int rv; - Z_OOPS(Z_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_COUNTER, &ds3231_api)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(syncpoint, sizeof(*syncpoint))); + K_OOPS(K_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_COUNTER, &ds3231_api)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(syncpoint, sizeof(*syncpoint))); rv = z_impl_maxim_ds3231_get_syncpoint(dev, &value); if (rv >= 0) { - Z_OOPS(z_user_to_copy(syncpoint, &value, sizeof(*syncpoint))); + K_OOPS(k_usermode_to_copy(syncpoint, &value, sizeof(*syncpoint))); } return rv; @@ -1325,9 +1325,9 @@ int z_vrfy_maxim_ds3231_get_syncpoint(const struct device *dev, int z_vrfy_maxim_ds3231_req_syncpoint(const struct device *dev, struct k_poll_signal *sig) { - Z_OOPS(Z_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_COUNTER, &ds3231_api)); + K_OOPS(K_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_COUNTER, &ds3231_api)); if (sig != NULL) { - Z_OOPS(Z_SYSCALL_OBJ(sig, K_OBJ_POLL_SIGNAL)); + K_OOPS(K_SYSCALL_OBJ(sig, K_OBJ_POLL_SIGNAL)); } return z_impl_maxim_ds3231_req_syncpoint(dev, sig); diff --git a/drivers/crypto/CMakeLists.txt b/drivers/crypto/CMakeLists.txt index 07eb8a414ec9a34..68b63aef6ee9a61 100644 --- a/drivers/crypto/CMakeLists.txt +++ b/drivers/crypto/CMakeLists.txt @@ -5,6 +5,7 @@ zephyr_library_sources_ifdef(CONFIG_CRYPTO_TINYCRYPT_SHIM crypto_tc_shim.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_ATAES132A crypto_ataes132a.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_MBEDTLS_SHIM crypto_mtls_shim.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_STM32 crypto_stm32.c) +zephyr_library_sources_ifdef(CONFIG_CRYPTO_SMARTBOND crypto_smartbond.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_NRF_ECB crypto_nrf_ecb.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_INTEL_SHA crypto_intel_sha.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_NPCX_SHA crypto_npcx_sha.c) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index c209ed226f79170..5342441038e66fb 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -80,5 +80,6 @@ source "drivers/crypto/Kconfig.npcx" source "drivers/crypto/Kconfig.xec" source "drivers/crypto/Kconfig.it8xxx2" source "drivers/crypto/Kconfig.mcux_dcp" +source "drivers/crypto/Kconfig.smartbond" endif # CRYPTO diff --git a/drivers/crypto/Kconfig.smartbond b/drivers/crypto/Kconfig.smartbond new file mode 100644 index 000000000000000..6c2077c3a42e2da --- /dev/null +++ b/drivers/crypto/Kconfig.smartbond @@ -0,0 +1,17 @@ +# Smartbond Cryptographic Accelerator configuration options + +# Copyright (c) 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +menuconfig CRYPTO_SMARTBOND + bool "Smartbond Cryptographic Accelerator driver" + depends on DT_HAS_RENESAS_SMARTBOND_CRYPTO_ENABLED + default y + help + Enable Smartbond Cryptographic Accelerator driver. + +config CRYPTO_ASYNC + bool "Support ASYNC crypto operations." + depends on CRYPTO_SMARTBOND + help + Enable ASYNC crypto operations. diff --git a/drivers/crypto/crypto_npcx_sha.c b/drivers/crypto/crypto_npcx_sha.c index 264035993606377..7354ea5877b5bc9 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/crypto/crypto_smartbond.c b/drivers/crypto/crypto_smartbond.c new file mode 100644 index 000000000000000..5b003875b93f26b --- /dev/null +++ b/drivers/crypto/crypto_smartbond.c @@ -0,0 +1,956 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(crypto_smartbond_crypto, CONFIG_CRYPTO_LOG_LEVEL); + +#define DT_DRV_COMPAT renesas_smartbond_crypto + +#define SMARTBOND_IRQN DT_INST_IRQN(0) +#define SMARTBOND_IRQ_PRIO DT_INST_IRQ(0, priority) + +#if defined(CONFIG_CRYPTO_ASYNC) +#define CRYPTO_HW_CAPS (CAP_RAW_KEY | CAP_SEPARATE_IO_BUFS | CAP_ASYNC_OPS | CAP_NO_IV_PREFIX) +#else +#define CRYPTO_HW_CAPS (CAP_RAW_KEY | CAP_SEPARATE_IO_BUFS | CAP_SYNC_OPS | CAP_NO_IV_PREFIX) +#endif + +#define SWAP32(_w) __builtin_bswap32(_w) + +#define CRYPTO_CTRL_REG_SET(_field, _val) \ + AES_HASH->CRYPTO_CTRL_REG = \ + (AES_HASH->CRYPTO_CTRL_REG & ~AES_HASH_CRYPTO_CTRL_REG_ ## _field ## _Msk) | \ + ((_val) << AES_HASH_CRYPTO_CTRL_REG_ ## _field ## _Pos) + +#define CRYPTO_CTRL_REG_GET(_field) \ + ((AES_HASH->CRYPTO_CTRL_REG & AES_HASH_CRYPTO_CTRL_REG_ ## _field ## _Msk) >> \ + AES_HASH_CRYPTO_CTRL_REG_ ## _field ## _Pos) + + +struct crypto_smartbond_data { + /* + * Semaphore to provide mutual exlusion when a crypto session is requested. + */ + struct k_sem session_sem; + + /* + * Semaphore to provide mutual exlusion when a cryptographic task is requested. + * (a session should be requested at this point). + */ + struct k_sem device_sem; +#if defined(CONFIG_CRYPTO_ASYNC) + /* + * User-defined callbacks to be called upon completion of asynchronous + * cryptographic operations. Note that the AES and HASH modes can work + * complementary to each other. + */ + union { + cipher_completion_cb cipher_user_cb; + hash_completion_cb hash_user_cb; + }; + + /* + * Packet context should be stored during a session so that can be rertieved + * from within the crypto engine ISR context. + */ + union { + struct cipher_pkt *cipher_pkt; + struct hash_pkt *hash_pkt; + }; +#else + /* + * Semaphore used to block for as long as a synchronous cryptographic operation + * is in progress. + */ + struct k_sem sync_sem; +#endif +}; + +/* + * Status flag to indicate if the crypto engine resources have been granted. Note that the + * device integrates a single crypto engine instance. + */ +static bool in_use; + +static void crypto_smartbond_set_status(bool enable); + +static void smartbond_crypto_isr(const void *arg) +{ + struct crypto_smartbond_data *data = ((const struct device *)arg)->data; + uint32_t status = AES_HASH->CRYPTO_STATUS_REG; + + if (status & AES_HASH_CRYPTO_STATUS_REG_CRYPTO_IRQ_ST_Msk) { + /* Clear interrupt source. Otherwise the handler will be fire constantly! */ + AES_HASH->CRYPTO_CLRIRQ_REG = 0x1; + +#if defined(CONFIG_CRYPTO_ASYNC) + /* Define the slected crypto mode (AES/HASH). */ + if (AES_HASH->CRYPTO_CTRL_REG & AES_HASH_CRYPTO_CTRL_REG_CRYPTO_HASH_SEL_Msk) { + if (data->hash_user_cb) { + data->hash_user_cb(data->hash_pkt, status); + } + } else { + if (data->cipher_user_cb) { + data->cipher_user_cb(data->cipher_pkt, status); + } + } +#else + /* Designate the requested cryptographic tasks is finished. */ + k_sem_give(&data->sync_sem); +#endif + } +} + +static bool crypto_smartbond_lock_session(const struct device *dev) +{ + bool lock = false; + struct crypto_smartbond_data *data = dev->data; + + k_sem_take(&data->session_sem, K_FOREVER); + + if (!in_use) { + in_use = true; + crypto_smartbond_set_status(true); + lock = true; + } + + k_sem_give(&data->session_sem); + + return lock; +} + +static void crypto_smartbond_unlock_session(const struct device *dev) +{ + struct crypto_smartbond_data *data = dev->data; + + k_sem_take(&data->session_sem, K_FOREVER); + + if (in_use) { + in_use = false; + crypto_smartbond_set_status(false); + } + + k_sem_give(&data->session_sem); +} + +/* + * Input vector should comply with the following restrictions: + * + * mode | CRYPTO_MORE_IN = true | CRYPTO_MORE_IN = false + * ------------| -----------------------| ---------------------- + * ECB | multiple of 16 (bytes) | multiple of 16 (bytes) + * CBC | multiple of 16 | no restrictions + * CTR | multiple of 16 | no restrictions + * MD5 | multiple of 8 | no restrictions + * SHA_1 | multiple of 8 | no restrictions + * SHA_256_224 | multiple of 8 | no restrictions + * SHA_256 | multiple of 8 | no restrictions + * SHA_384 | multiple of 8 | no restrictions + * SHA_512 | multiple of 8 | no restrictions + * SHA_512_224 | multiple of 8 | no restrictions + * SHA_512_256 | multiple of 8 | no restrictions + */ +static int crypto_smartbond_check_in_restrictions(uint16_t in_len) +{ +#define CRYPTO_ALG_MD_ECB_MAGIC_0 0x00 +#define CRYPTO_ALG_MD_ECB_MAGIC_1 0x01 + + bool not_last_in_block = !!(AES_HASH->CRYPTO_CTRL_REG & + AES_HASH_CRYPTO_CTRL_REG_CRYPTO_MORE_IN_Msk); + + /* Define the slected crypto mode (AES/HASH). */ + if (AES_HASH->CRYPTO_CTRL_REG & AES_HASH_CRYPTO_CTRL_REG_CRYPTO_HASH_SEL_Msk) { + if (not_last_in_block && (in_len & 0x7)) { + return -EINVAL; + } + } else { + if (in_len & 0xF) { + if (not_last_in_block) { + return -EINVAL; + } + + uint32_t crypto_mode = CRYPTO_CTRL_REG_GET(CRYPTO_ALG_MD); + + /* Check if AES mode is ECB */ + if (crypto_mode == CRYPTO_ALG_MD_ECB_MAGIC_0 || + crypto_mode == CRYPTO_ALG_MD_ECB_MAGIC_1) { + return -EINVAL; + } + } + } + + return 0; +} + +/* + * The driver model does not define the max. output length. As such, the max supported length + * per mode is applied. + */ +static int crypto_smartbond_hash_set_out_len(void) +{ + uint32_t hash_algo = (AES_HASH->CRYPTO_CTRL_REG & AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ALG_Msk); + + if (AES_HASH->CRYPTO_CTRL_REG & AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ALG_MD_Msk) { + /* 64-bit HASH operations */ + switch (hash_algo) { + case 0x0: + /* SHA-384: 0..47 --> 1..48 bytes */ + CRYPTO_CTRL_REG_SET(CRYPTO_HASH_OUT_LEN, 47); + break; + case 0x1: + /* SHA-512: 0..63 --> 1..64 bytes */ + CRYPTO_CTRL_REG_SET(CRYPTO_HASH_OUT_LEN, 63); + break; + case 0x2: + /* SHA-512/224: 0..27 --> 1..28 bytes */ + CRYPTO_CTRL_REG_SET(CRYPTO_HASH_OUT_LEN, 27); + break; + case 0x3: + /* SHA-512/256: 0..31 --> 1..32 bytes */ + CRYPTO_CTRL_REG_SET(CRYPTO_HASH_OUT_LEN, 31); + break; + default: + break; + } + } else { + /* 32-bit HASH operations */ + switch (hash_algo) { + case 0x0: + /* MD5: 0..15 --> 1..16 bytes */ + CRYPTO_CTRL_REG_SET(CRYPTO_HASH_OUT_LEN, 15); + break; + case 0x1: + /* SHA-1: 0..19 --> 1..20 bytes */ + CRYPTO_CTRL_REG_SET(CRYPTO_HASH_OUT_LEN, 19); + break; + case 0x2: + /* SHA-256/224: 0..27 --> 1..28 bytes */ + CRYPTO_CTRL_REG_SET(CRYPTO_HASH_OUT_LEN, 27); + break; + case 0x3: + /* SHA-256: 0..31 --> 1..32 bytes */ + CRYPTO_CTRL_REG_SET(CRYPTO_HASH_OUT_LEN, 31); + break; + default: + break; + } + } + + /* Return the OUT size applied. */ + return CRYPTO_CTRL_REG_GET(CRYPTO_HASH_OUT_LEN) + 1; +} + +static uint32_t crypto_smartbond_swap_word(uint8_t *data) +{ + /* Check word boundaries of given address and if possible accellerate swapping */ + if ((uint32_t)data & 0x3) { + sys_mem_swap(data, sizeof(uint32_t)); + + return (*(uint32_t *)data); + } else { + return SWAP32(*(uint32_t *)data); + } +} + +static int crypto_smartbond_cipher_key_load(uint8_t *key, uint16_t key_len) +{ + if (key == NULL) { + return -EIO; + } + + AES_HASH->CRYPTO_CTRL_REG &= ~(AES_HASH_CRYPTO_CTRL_REG_CRYPTO_AES_KEY_SZ_Msk); + + if (key_len == 32) { + AES_HASH->CRYPTO_CTRL_REG |= + (0x2 << AES_HASH_CRYPTO_CTRL_REG_CRYPTO_AES_KEY_SZ_Pos); + } else if (key_len == 24) { + AES_HASH->CRYPTO_CTRL_REG |= + (0x1 << AES_HASH_CRYPTO_CTRL_REG_CRYPTO_AES_KEY_SZ_Pos); + } else if (key_len == 16) { + /* Nothing to do */ + } else { + return -EINVAL; + } + + /* Key expansion is performed by the crypto engine */ + AES_HASH->CRYPTO_CTRL_REG |= AES_HASH_CRYPTO_CTRL_REG_CRYPTO_AES_KEXP_Msk; + + /* Check whether the cipher key is located in OTP (user keys segment) */ + if (IS_ADDRESS_USER_DATA_KEYS_SEGMENT((uint32_t)key)) { + + /* User keys segmnet can be accessed if not locked (stick bits are not set) */ + if (CRG_TOP->SECURE_BOOT_REG & CRG_TOP_SECURE_BOOT_REG_PROT_AES_KEY_READ_Msk) { + return -EIO; + } + + uint32_t cell_offset = da1469x_otp_address_to_cell_offset((uint32_t)key); + + da1469x_otp_read(cell_offset, + (void *)&AES_HASH->CRYPTO_KEYS_START, (uint32_t)key_len); + } else { + volatile uint32_t *kmem_ptr = &AES_HASH->CRYPTO_KEYS_START; + + do { + *(kmem_ptr++) = crypto_smartbond_swap_word(key); + key += 4; + key_len -= 4; + } while (key_len); + } + + return 0; +} + +static int crypto_smartbond_cipher_set_mode(enum cipher_mode mode) +{ + /* Select AES mode */ + AES_HASH->CRYPTO_CTRL_REG &= ~(AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ALG_MD_Msk | + AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ALG_Msk | + AES_HASH_CRYPTO_CTRL_REG_CRYPTO_HASH_SEL_Msk); + switch (mode) { + case CRYPTO_CIPHER_MODE_ECB: + /* Already done; CRYPTO_ALG_MD = 0x0 or 0x1 defines ECB. */ + break; + case CRYPTO_CIPHER_MODE_CTR: + AES_HASH->CRYPTO_CTRL_REG |= (0x2 << AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ALG_MD_Pos); + break; + case CRYPTO_CIPHER_MODE_CBC: + AES_HASH->CRYPTO_CTRL_REG |= (0x3 << AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ALG_MD_Pos); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int crypto_smartbond_hash_set_algo(enum hash_algo algo) +{ + /* Select HASH mode and reset to 32-bit mode */ + AES_HASH->CRYPTO_CTRL_REG = + (AES_HASH->CRYPTO_CTRL_REG & ~(AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ALG_Msk | + AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ALG_MD_Msk)) | + AES_HASH_CRYPTO_CTRL_REG_CRYPTO_HASH_SEL_Msk; + + switch (algo) { + case CRYPTO_HASH_ALGO_SHA224: + /* CRYPTO_ALG_MD = 0x0 defines 32-bit operations */ + AES_HASH->CRYPTO_CTRL_REG |= (0x2 << AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ALG_Pos); + break; + case CRYPTO_HASH_ALGO_SHA256: + /* CRYPTO_ALG_MD = 0x0 defines 32-bit operations */ + AES_HASH->CRYPTO_CTRL_REG |= (0x3 << AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ALG_Pos); + break; + case CRYPTO_HASH_ALGO_SHA384: + /* CRYPTO_ALG_MD = 0x1 defines 64-bit operations */ + AES_HASH->CRYPTO_CLRIRQ_REG |= AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ALG_MD_Msk; + break; + case CRYPTO_HASH_ALGO_SHA512: + /* CRYPTO_ALG_MD = 0x1 defines 64-bit operations */ + AES_HASH->CRYPTO_CTRL_REG |= (AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ALG_MD_Msk | + (0x1 << AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ALG_Pos)); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int crypto_smartbond_set_in_out_buf(uint8_t *in_buf, uint8_t *out_buf, int len) +{ + if (in_buf == NULL) { + return -EIO; + } + + /* + * Input data can reside in any address space. Cryto DMA can only access physical addresses + * (not remapped). + */ + uint32_t phy_addr = black_orca_phy_addr((uint32_t)in_buf); + + if (IS_QSPIF_CACHED_ADDRESS(phy_addr)) { + /* + * To achiebe max. perfomance, peripherals should not access the Flash memory + * through the instruction cache controller (avoid cache misses). + */ + phy_addr += (MCU_QSPIF_M_BASE - MCU_QSPIF_M_CACHED_BASE); + } else if (IS_OTP_ADDRESS(phy_addr)) { + /* Peripherals should access the OTP memory through its peripheral address space. */ + phy_addr += (MCU_OTP_M_P_BASE - MCU_OTP_M_BASE); + } + + AES_HASH->CRYPTO_FETCH_ADDR_REG = phy_addr; + + /* + * OUT buffer can be NULL in case of fregmented data processing. CRYPTO_DEST_ADDR and + * CRYPTO_FETCH_ADDR are being updated as calculations prceed and OUT data are written + * into memory. + */ + if (out_buf) { + uint32_t remap_adr0 = CRG_TOP->SYS_CTRL_REG & CRG_TOP_SYS_CTRL_REG_REMAP_ADR0_Msk; + + /* + * OUT data can only be written in SYSRAM, non-cached remapped SYSRAM and + * cached non-remapped SYSRAM. + */ + if (IS_SYSRAM_ADDRESS(out_buf) || + (IS_REMAPPED_ADDRESS(out_buf) && remap_adr0 == 3)) { + AES_HASH->CRYPTO_DEST_ADDR_REG = black_orca_phy_addr((uint32_t)out_buf); + } else { + return -EIO; + } + } + + AES_HASH->CRYPTO_LEN_REG = len; + + return 0; +} + +static inline void crypto_smartbond_cipher_store_dep_data(uint32_t *words, uint32_t len_words) +{ + volatile uint32_t *mreg3 = &AES_HASH->CRYPTO_MREG3_REG; + + for (int i = 0; i < len_words; i++) { + *(mreg3--) = crypto_smartbond_swap_word((uint8_t *)(words++)); + } +} + +static int crypto_smartbond_cipher_set_mreg(uint8_t *mreg, uint32_t len_words) +{ + if (mreg == NULL || len_words == 0 || len_words > 4) { + return -EINVAL; + } + + AES_HASH->CRYPTO_MREG0_REG = 0; + AES_HASH->CRYPTO_MREG1_REG = 0; + AES_HASH->CRYPTO_MREG2_REG = 0; + AES_HASH->CRYPTO_MREG3_REG = 0; + + crypto_smartbond_cipher_store_dep_data((uint32_t *)mreg, len_words); + + return 0; +} + +static void crypto_smartbond_set_status(bool enable) +{ + unsigned int key; + + key = irq_lock(); + + if (enable) { + CRG_TOP->CLK_AMBA_REG |= (CRG_TOP_CLK_AMBA_REG_AES_CLK_ENABLE_Msk); + + AES_HASH->CRYPTO_CLRIRQ_REG = 0x1; + AES_HASH->CRYPTO_CTRL_REG |= (AES_HASH_CRYPTO_CTRL_REG_CRYPTO_IRQ_EN_Msk); + + irq_enable(SMARTBOND_IRQN); + } else { + AES_HASH->CRYPTO_CTRL_REG &= ~(AES_HASH_CRYPTO_CTRL_REG_CRYPTO_IRQ_EN_Msk); + AES_HASH->CRYPTO_CLRIRQ_REG = 0x1; + + irq_disable(SMARTBOND_IRQN); + + CRG_TOP->CLK_AMBA_REG &= ~(CRG_TOP_CLK_AMBA_REG_AES_CLK_ENABLE_Msk); + } + + irq_unlock(key); +} + +static int crypto_smartbond_query_hw_caps(const struct device *dev) +{ + return CRYPTO_HW_CAPS; +} + +static int crypto_smartbond_cipher_ecb_handler(struct cipher_ctx *ctx, struct cipher_pkt *pkt) +{ + int ret; + struct crypto_smartbond_data *data = ctx->device->data; + + if ((AES_HASH->CRYPTO_STATUS_REG & AES_HASH_CRYPTO_STATUS_REG_CRYPTO_INACTIVE_Msk) == 0) { + LOG_ERR("Crypto engine is already employed"); + return -EINVAL; + } + + if (pkt->out_buf_max < pkt->in_len) { + LOG_ERR("OUT buffer cannot be less that IN buffer"); + return -EINVAL; + } + + if (pkt->in_buf == NULL || pkt->out_buf == NULL) { + LOG_ERR("Missing IN or OUT buffer declaration"); + return -EIO; + } + + if (pkt->in_len > 16) { + LOG_ERR("For security reasons, do not operate on more than 16 bytes"); + return -EINVAL; + } + + k_sem_take(&data->device_sem, K_FOREVER); + + ret = crypto_smartbond_check_in_restrictions(pkt->in_len); + if (ret < 0) { + LOG_ERR("Unsupported IN buffer size"); + k_sem_give(&data->device_sem); + return ret; + } + + ret = crypto_smartbond_set_in_out_buf(pkt->in_buf, pkt->out_buf, pkt->in_len); + if (ret < 0) { + LOG_ERR("Unsupported IN or OUT buffer location"); + k_sem_give(&data->device_sem); + return ret; + } + +#if defined(CONFIG_CRYPTO_ASYNC) + data->cipher_pkt = pkt; +#endif + + /* Start crypto processing */ + AES_HASH->CRYPTO_START_REG = 1; + +#if !defined(CONFIG_CRYPTO_ASYNC) + /* Wait for crypto to finish its task */ + k_sem_take(&data->sync_sem, K_FOREVER); +#endif + + /* Report that number of bytes operated upon. */ + pkt->out_len = pkt->in_len; + + k_sem_give(&data->device_sem); + + return 0; +} + +static int +crypto_smartbond_cipher_cbc_handler(struct cipher_ctx *ctx, struct cipher_pkt *pkt, uint8_t *iv) +{ + int ret; + int offset = 0; + struct crypto_smartbond_data *data = ctx->device->data; + bool is_op_encryption = + !!(AES_HASH->CRYPTO_CTRL_REG & AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ENCDEC_Msk); + + if ((AES_HASH->CRYPTO_STATUS_REG & AES_HASH_CRYPTO_STATUS_REG_CRYPTO_INACTIVE_Msk) == 0) { + LOG_ERR("Crypto engine is already employed"); + return -EINVAL; + } + + if ((is_op_encryption && pkt->out_buf_max < (pkt->in_len + 16)) || + pkt->out_buf_max < (pkt->in_len - 16)) { + LOG_ERR("Invalid OUT buffer size"); + return -EINVAL; + } + + if (pkt->in_buf == NULL || pkt->out_buf == NULL) { + LOG_ERR("Missing IN or OUT buffer declaration"); + return -EIO; + } + + if ((ctx->flags & CAP_NO_IV_PREFIX) == 0) { + offset = 16; + if (is_op_encryption) { + /* Prefix IV to ciphertet unless CAP_NO_IV_PREFIX is set. */ + memcpy(pkt->out_buf, iv, offset); + } + } + + k_sem_take(&data->device_sem, K_FOREVER); + + ret = crypto_smartbond_check_in_restrictions(pkt->in_len); + if (ret < 0) { + LOG_ERR("Unsupported IN buffer size"); + k_sem_give(&data->device_sem); + return ret; + } + + ret = crypto_smartbond_cipher_set_mreg(iv, 4); + if (ret < 0) { + LOG_ERR("Missing Initialization Vector (IV)"); + k_sem_give(&data->device_sem); + return ret; + } + + if (is_op_encryption) { + ret = crypto_smartbond_set_in_out_buf(pkt->in_buf, + pkt->out_buf + offset, pkt->in_len); + } else { + ret = crypto_smartbond_set_in_out_buf(pkt->in_buf + offset, + pkt->out_buf, pkt->in_len - offset); + } + + if (ret < 0) { + LOG_ERR("Unsupported IN or OUT buffer location"); + k_sem_give(&data->device_sem); + return ret; + } + +#if defined(CONFIG_CRYPTO_ASYNC) + data->cipher_pkt = pkt; +#endif + + /* Start crypto processing */ + AES_HASH->CRYPTO_START_REG = 1; + +#if !defined(CONFIG_CRYPTO_ASYNC) + /* Wait for crypto to finish its task */ + k_sem_take(&data->sync_sem, K_FOREVER); +#endif + + /* Report that number of bytes operated upon. */ + if (is_op_encryption) { + pkt->out_len = pkt->in_len + offset; + } else { + pkt->out_len = pkt->in_len - offset; + } + + k_sem_give(&data->device_sem); + + return 0; +} + +static int crypto_smartbond_cipher_ctr_handler(struct cipher_ctx *ctx, + struct cipher_pkt *pkt, uint8_t *ic) +{ + int ret; + /* ivlen + ctrlen = keylen, ctrl_len is expressed in bits */ + uint32_t iv_len = ctx->keylen - (ctx->mode_params.ctr_info.ctr_len >> 3); + struct crypto_smartbond_data *data = ctx->device->data; + + if ((AES_HASH->CRYPTO_STATUS_REG & AES_HASH_CRYPTO_STATUS_REG_CRYPTO_INACTIVE_Msk) == 0) { + LOG_ERR("Crypto engine is already employed"); + return -EINVAL; + } + + if (pkt->out_buf_max < pkt->in_len) { + LOG_ERR("OUT buffer cannot be less that IN buffer"); + return -EINVAL; + } + + if (pkt->in_buf == NULL || pkt->out_buf == NULL) { + LOG_ERR("Missing IN or OUT buffer declaration"); + return -EIO; + } + + k_sem_take(&data->device_sem, K_FOREVER); + + ret = crypto_smartbond_check_in_restrictions(pkt->in_len); + if (ret < 0) { + LOG_ERR("Unsupported IN buffer size"); + k_sem_give(&data->device_sem); + return ret; + } + + ret = crypto_smartbond_cipher_set_mreg(ic, iv_len >> 2); + if (ret < 0) { + LOG_ERR("Missing Initialization Counter (IC)"); + k_sem_give(&data->device_sem); + return ret; + } + + ret = crypto_smartbond_set_in_out_buf(pkt->in_buf, pkt->out_buf, pkt->in_len); + if (ret < 0) { + LOG_ERR("Unsupported IN or OUT buffer location"); + k_sem_give(&data->device_sem); + return ret; + } + +#if defined(CONFIG_CRYPTO_ASYNC) + data->cipher_pkt = pkt; +#endif + + /* Start crypto processing */ + AES_HASH->CRYPTO_START_REG = 1; + +#if !defined(CONFIG_CRYPTO_ASYNC) + /* Wait for crypto to finish its task */ + k_sem_take(&data->sync_sem, K_FOREVER); +#endif + + /* Report that number of bytes operated upon. */ + pkt->out_len = pkt->in_len; + + k_sem_give(&data->device_sem); + + return 0; +} + +static int crypto_smartbond_hash_handler(struct hash_ctx *ctx, struct hash_pkt *pkt, bool finish) +{ + int ret; + struct crypto_smartbond_data *data = ctx->device->data; + /* + * In case of framgemented data processing crypto status should be visible as busy for + * as long as the last block is to be processed. + */ + bool is_multipart_started = + (AES_HASH->CRYPTO_STATUS_REG & AES_HASH_CRYPTO_STATUS_REG_CRYPTO_WAIT_FOR_IN_Msk) && + !(AES_HASH->CRYPTO_STATUS_REG & AES_HASH_CRYPTO_STATUS_REG_CRYPTO_INACTIVE_Msk); + + if (pkt->in_buf == NULL || (pkt->out_buf == NULL)) { + LOG_ERR("Missing IN or OUT buffer declaration"); + return -EIO; + } + + k_sem_take(&data->device_sem, K_FOREVER); + + /* Check if this is the last block to process or more blocks will follow */ + if (finish) { + AES_HASH->CRYPTO_CTRL_REG &= ~(AES_HASH_CRYPTO_CTRL_REG_CRYPTO_MORE_IN_Msk); + } else { + AES_HASH->CRYPTO_CTRL_REG |= AES_HASH_CRYPTO_CTRL_REG_CRYPTO_MORE_IN_Msk; + } + + /* CRYPTO_MORE_IN should be updated prior to checking for IN restrictions! */ + ret = crypto_smartbond_check_in_restrictions(pkt->in_len); + if (ret < 0) { + LOG_ERR("Unsupported IN buffer size"); + k_sem_give(&data->device_sem); + return ret; + } + + if (!is_multipart_started) { + ret = crypto_smartbond_hash_set_out_len(); + if (ret < 0) { + LOG_ERR("Invalid OUT buffer size"); + k_sem_give(&data->device_sem); + return ret; + } + } + + if (!is_multipart_started) { + ret = crypto_smartbond_set_in_out_buf(pkt->in_buf, pkt->out_buf, pkt->in_len); + } else { + /* Destination buffer is being updated as fragmented input is being processed. */ + ret = crypto_smartbond_set_in_out_buf(pkt->in_buf, NULL, pkt->in_len); + } + + if (ret < 0) { + LOG_ERR("Unsupported IN or OUT buffer location"); + k_sem_give(&data->device_sem); + return ret; + } + +#if defined(CONFIG_CRYPTO_ASYNC) + data->hash_pkt = pkt; +#endif + + /* Start hash processing */ + AES_HASH->CRYPTO_START_REG = 1; + +#if !defined(CONFIG_CRYPTO_ASYNC) + k_sem_take(&data->sync_sem, K_FOREVER); +#endif + + k_sem_give(&data->device_sem); + + return 0; +} + +static int +crypto_smartbond_cipher_begin_session(const struct device *dev, struct cipher_ctx *ctx, + enum cipher_algo algo, enum cipher_mode mode, enum cipher_op op_type) +{ + int ret; + + if (ctx->flags & ~(CRYPTO_HW_CAPS)) { + LOG_ERR("Unsupported flag"); + return -EINVAL; + } + + if (algo != CRYPTO_CIPHER_ALGO_AES) { + LOG_ERR("Unsupported cipher algo"); + return -EINVAL; + } + + if (!crypto_smartbond_lock_session(dev)) { + LOG_ERR("No free session for now"); + return -ENOSPC; + } + + ret = crypto_smartbond_cipher_key_load(ctx->key.bit_stream, ctx->keylen); + if (ret < 0) { + LOG_ERR("Invalid key length or key cannot be accessed"); + crypto_smartbond_unlock_session(dev); + return ret; + } + + ret = crypto_smartbond_cipher_set_mode(mode); + if (ret < 0) { + LOG_ERR("Unsupported cipher mode"); + crypto_smartbond_unlock_session(dev); + return ret; + } + + if (op_type == CRYPTO_CIPHER_OP_ENCRYPT) { + AES_HASH->CRYPTO_CTRL_REG |= AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ENCDEC_Msk; + } else { + AES_HASH->CRYPTO_CTRL_REG &= ~(AES_HASH_CRYPTO_CTRL_REG_CRYPTO_ENCDEC_Msk); + } + + /* IN buffer fragmentation is not supported by the driver model */ + AES_HASH->CRYPTO_CTRL_REG &= ~(AES_HASH_CRYPTO_CTRL_REG_CRYPTO_MORE_IN_Msk); + + switch (mode) { + case CRYPTO_CIPHER_MODE_ECB: + ctx->ops.block_crypt_hndlr = crypto_smartbond_cipher_ecb_handler; + break; + case CRYPTO_CIPHER_MODE_CBC: + ctx->ops.cbc_crypt_hndlr = crypto_smartbond_cipher_cbc_handler; + break; + case CRYPTO_CIPHER_MODE_CTR: + ctx->ops.ctr_crypt_hndlr = crypto_smartbond_cipher_ctr_handler; + break; + default: + break; + } + + ctx->drv_sessn_state = NULL; + + return 0; +} + +static int crypto_smartbond_cipher_free_session(const struct device *dev, struct cipher_ctx *ctx) +{ + ARG_UNUSED(ctx); + crypto_smartbond_unlock_session(dev); + + return 0; +} + +#if defined(CONFIG_CRYPTO_ASYNC) +static int +crypto_smartbond_cipher_set_async_callback(const struct device *dev, cipher_completion_cb cb) +{ + struct crypto_smartbond_data *data = dev->data; + + data->cipher_user_cb = cb; + + return 0; +} +#endif + +static int +crypto_smartbond_hash_begin_session(const struct device *dev, + struct hash_ctx *ctx, enum hash_algo algo) +{ + int ret; + + if (ctx->flags & ~(CRYPTO_HW_CAPS)) { + LOG_ERR("Unsupported flag"); + return -EINVAL; + } + + if (!crypto_smartbond_lock_session(dev)) { + LOG_ERR("No free session for now"); + return -ENOSPC; + } + + /* + * Crypto should be disabled only if not used in other sessions. In case of failure, + * developer should next free the current session. + */ + crypto_smartbond_set_status(true); + + ret = crypto_smartbond_hash_set_algo(algo); + if (ret < 0) { + LOG_ERR("Unsupported HASH algo"); + crypto_smartbond_unlock_session(dev); + return ret; + } + + ctx->hash_hndlr = crypto_smartbond_hash_handler; + + ctx->drv_sessn_state = NULL; + + return 0; +} + +static int crypto_smartbond_hash_free_session(const struct device *dev, struct hash_ctx *ctx) +{ + ARG_UNUSED(ctx); + crypto_smartbond_unlock_session(dev); + + return 0; +} + +#if defined(CONFIG_CRYPTO_ASYNC) +static int +crypto_smartbond_hash_set_async_callback(const struct device *dev, hash_completion_cb cb) +{ + struct crypto_smartbond_data *data = dev->data; + + data->hash_user_cb = cb; + + return 0; +} +#endif + +static struct crypto_driver_api crypto_smartbond_driver_api = { + .cipher_begin_session = crypto_smartbond_cipher_begin_session, + .cipher_free_session = crypto_smartbond_cipher_free_session, +#if defined(CONFIG_CRYPTO_ASYNC) + .cipher_async_callback_set = crypto_smartbond_cipher_set_async_callback, +#endif + .hash_begin_session = crypto_smartbond_hash_begin_session, + .hash_free_session = crypto_smartbond_hash_free_session, +#if defined(CONFIG_CRYPTO_ASYNC) + .hash_async_callback_set = crypto_smartbond_hash_set_async_callback, +#endif + .query_hw_caps = crypto_smartbond_query_hw_caps +}; + +static int crypto_smartbond_init(const struct device *dev) +{ + struct crypto_smartbond_data *data = dev->data; + + /* Semaphore used during sessions (begin/free) */ + k_sem_init(&data->session_sem, 1, 1); + + /* Semaphore used to employ the crypto device */ + k_sem_init(&data->device_sem, 1, 1); + +#if !defined(CONFIG_CRYPTO_ASYNC) + /* Sempahore used when sync operations are enabled */ + k_sem_init(&data->sync_sem, 0, 1); +#endif + + IRQ_CONNECT(SMARTBOND_IRQN, SMARTBOND_IRQ_PRIO, smartbond_crypto_isr, + DEVICE_DT_INST_GET(0), 0); + + crypto_smartbond_set_status(false); + + return 0; +} + +/* + * There is only one instance integrated on the SoC. Just in case that assumption becomes invalid + * in the future, we use a BUILD_ASSERT(). + */ +#define SMARTBOND_CRYPTO_INIT(inst) \ + BUILD_ASSERT((inst) == 0, \ + "multiple instances are not supported"); \ + \ + static struct crypto_smartbond_data crypto_smartbond_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(0, \ + crypto_smartbond_init, NULL, \ + &crypto_smartbond_data_##inst, NULL, \ + POST_KERNEL, \ + CONFIG_CRYPTO_INIT_PRIORITY, \ + &crypto_smartbond_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(SMARTBOND_CRYPTO_INIT) diff --git a/drivers/crypto/crypto_stm32.c b/drivers/crypto/crypto_stm32.c index ca80b2afe35211c..17250a944a97822 100644 --- a/drivers/crypto/crypto_stm32.c +++ b/drivers/crypto/crypto_stm32.c @@ -43,8 +43,13 @@ LOG_MODULE_REGISTER(crypto_stm32); #define STM32_RCC_CRYPTO_RELEASE_RESET __HAL_RCC_CRYP_RELEASE_RESET #define STM32_CRYPTO_TYPEDEF CRYP_TypeDef #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_aes) +#if defined(CONFIG_SOC_SERIES_STM32WBX) +#define STM32_RCC_CRYPTO_FORCE_RESET __HAL_RCC_AES1_FORCE_RESET +#define STM32_RCC_CRYPTO_RELEASE_RESET __HAL_RCC_AES1_RELEASE_RESET +#else #define STM32_RCC_CRYPTO_FORCE_RESET __HAL_RCC_AES_FORCE_RESET #define STM32_RCC_CRYPTO_RELEASE_RESET __HAL_RCC_AES_RELEASE_RESET +#endif #define STM32_CRYPTO_TYPEDEF AES_TypeDef #endif diff --git a/drivers/dac/CMakeLists.txt b/drivers/dac/CMakeLists.txt index d2164f92d7ebda1..c84b0d9d78e5662 100644 --- a/drivers/dac/CMakeLists.txt +++ b/drivers/dac/CMakeLists.txt @@ -18,5 +18,6 @@ zephyr_library_sources_ifdef(CONFIG_DAC_MCP4725 dac_mcp4725.c) zephyr_library_sources_ifdef(CONFIG_DAC_MCP4728 dac_mcp4728.c) zephyr_library_sources_ifdef(CONFIG_DAC_GD32 dac_gd32.c) zephyr_library_sources_ifdef(CONFIG_DAC_ESP32 dac_esp32.c) +zephyr_library_sources_ifdef(CONFIG_DAC_AD5592 dac_ad5592.c) zephyr_library_sources_ifdef(CONFIG_DAC_AD56XX dac_ad56xx.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE dac_handlers.c) diff --git a/drivers/dac/Kconfig b/drivers/dac/Kconfig index 6449032fa4822e9..3735a11aa2aa6b0 100644 --- a/drivers/dac/Kconfig +++ b/drivers/dac/Kconfig @@ -19,7 +19,6 @@ source "subsys/logging/Kconfig.template.log_config" config DAC_SHELL bool "DAC shell" - default y depends on SHELL help Enable DAC related shell commands. @@ -54,4 +53,6 @@ source "drivers/dac/Kconfig.esp32" source "drivers/dac/Kconfig.ad56xx" +source "drivers/dac/Kconfig.ad5592" + endif # DAC diff --git a/drivers/dac/Kconfig.ad5592 b/drivers/dac/Kconfig.ad5592 new file mode 100644 index 000000000000000..1010992fb7fad3e --- /dev/null +++ b/drivers/dac/Kconfig.ad5592 @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Grinn +# SPDX -License-Identifier: Apache-2.0 + +config DAC_AD5592 + bool "AD5592 DAC driver" + default y + depends on DT_HAS_ADI_AD5592_DAC_ENABLED + select MFD + help + Enable the AD5592 DAC driver. diff --git a/drivers/dac/dac_ad5592.c b/drivers/dac/dac_ad5592.c new file mode 100644 index 000000000000000..653df85dd566a1f --- /dev/null +++ b/drivers/dac/dac_ad5592.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_ad5592_dac + +#include +#include +#include + +#include + +#include +LOG_MODULE_REGISTER(dac_ad5592, CONFIG_DAC_LOG_LEVEL); + +#define AD5592_DAC_RESOLUTION 12 +#define AD5592_DAC_WR_MSB_BIT BIT(15) +#define AD5592_DAC_CHANNEL_SHIFT_VAL 12 + +struct dac_ad5592_config { + const struct device *mfd_dev; +}; + +struct dac_ad5592_data { + uint8_t dac_conf; +}; + +static int dac_ad5592_channel_setup(const struct device *dev, + const struct dac_channel_cfg *channel_cfg) +{ + const struct dac_ad5592_config *config = dev->config; + struct dac_ad5592_data *data = dev->data; + + if (channel_cfg->channel_id >= AD5592_PIN_MAX) { + LOG_ERR("Invalid channel number %d", channel_cfg->channel_id); + return -EINVAL; + } + + if (channel_cfg->resolution != AD5592_DAC_RESOLUTION) { + LOG_ERR("Invalid resolution %d", channel_cfg->resolution); + return -EINVAL; + } + + data->dac_conf |= BIT(channel_cfg->channel_id); + + return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_LDAC_EN, data->dac_conf); +} + +static int dac_ad5592_write_value(const struct device *dev, uint8_t channel, + uint32_t value) +{ + const struct dac_ad5592_config *config = dev->config; + uint16_t msg; + + if (channel >= AD5592_PIN_MAX) { + LOG_ERR("Invalid channel number %d", channel); + return -EINVAL; + } + + if (value >= (1 << AD5592_DAC_RESOLUTION)) { + LOG_ERR("Value %d out of range", value); + return -EINVAL; + } + + msg = sys_cpu_to_be16(AD5592_DAC_WR_MSB_BIT | + channel << AD5592_DAC_CHANNEL_SHIFT_VAL | + value); + + return mfd_ad5592_write_raw(config->mfd_dev, msg); +} + +static const struct dac_driver_api dac_ad5592_api = { + .channel_setup = dac_ad5592_channel_setup, + .write_value = dac_ad5592_write_value, +}; + +static int dac_ad5592_init(const struct device *dev) +{ + const struct dac_ad5592_config *config = dev->config; + int ret; + + if (!device_is_ready(config->mfd_dev)) { + return -ENODEV; + } + + ret = mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_PD_REF_CTRL, AD5592_EN_REF); + if (ret < 0) { + return ret; + } + + return 0; +} + +#define DAC_AD5592_DEFINE(inst) \ + static const struct dac_ad5592_config dac_ad5592_config##inst = { \ + .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + }; \ + \ + struct dac_ad5592_data dac_ad5592_data##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, dac_ad5592_init, NULL, \ + &dac_ad5592_data##inst, &dac_ad5592_config##inst, \ + POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ + &dac_ad5592_api); + +DT_INST_FOREACH_STATUS_OKAY(DAC_AD5592_DEFINE) diff --git a/drivers/dac/dac_handlers.c b/drivers/dac/dac_handlers.c index aa6660651e26b63..bd9ee0bc7e0d6f7 100644 --- a/drivers/dac/dac_handlers.c +++ b/drivers/dac/dac_handlers.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include static inline int z_vrfy_dac_channel_setup(const struct device *dev, @@ -13,8 +13,8 @@ static inline int z_vrfy_dac_channel_setup(const struct device *dev, { struct dac_channel_cfg channel_cfg; - Z_OOPS(Z_SYSCALL_DRIVER_DAC(dev, channel_setup)); - Z_OOPS(z_user_from_copy(&channel_cfg, + K_OOPS(K_SYSCALL_DRIVER_DAC(dev, channel_setup)); + K_OOPS(k_usermode_from_copy(&channel_cfg, (struct dac_channel_cfg *)user_channel_cfg, sizeof(struct dac_channel_cfg))); @@ -26,7 +26,7 @@ static inline int z_vrfy_dac_channel_setup(const struct device *dev, static inline int z_vrfy_dac_write_value(const struct device *dev, uint8_t channel, uint32_t value) { - Z_OOPS(Z_SYSCALL_DRIVER_DAC(dev, write_value)); + K_OOPS(K_SYSCALL_DRIVER_DAC(dev, write_value)); return z_impl_dac_write_value((const struct device *)dev, channel, value); diff --git a/drivers/dac/dac_sam.c b/drivers/dac/dac_sam.c index de4680b3ff674ee..df8b96f66e9c78f 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 2b96b8bc30d3223..95f561d4a6abb6b 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 90b5d8b931cc6a3..b6bd04939d520e7 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 770b528da6a3857..da882a99fa00229 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/alh/Kconfig.alh b/drivers/dai/intel/alh/Kconfig.alh index e2885a29e5da49b..785074454fb7dc9 100644 --- a/drivers/dai/intel/alh/Kconfig.alh +++ b/drivers/dai/intel/alh/Kconfig.alh @@ -16,8 +16,9 @@ config DAI_INTEL_ALH if DAI_INTEL_ALH config DAI_ALH_HAS_OWNERSHIP - bool "Intel ALH driver has ownership" - default y if SOC_SERIES_INTEL_ACE + bool "Intel ALH driver has ownership only on ACE 1.5" + default y + depends on SOC_INTEL_ACE15_MTPM help Select this to enable programming HW ownership diff --git a/drivers/dai/intel/dmic/dmic_nhlt.c b/drivers/dai/intel/dmic/dmic_nhlt.c index 17a8f385a023d11..3d803da33b9cc1e 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 809cc9833eb025b..4b8f6e00742f121 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 1d37b9a3335f715..0d53c0c61598257 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 000000000000000..755261307a6a2f2 --- /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 000000000000000..04c1ff7a4305cf6 --- /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 000000000000000..3addb5670f2054b --- /dev/null +++ b/drivers/dai/nxp/sai/sai.c @@ -0,0 +1,908 @@ +/* + * 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; + } + + /* 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_dline_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); + +out_dline_disable: + /* disable TX/RX data line */ + sai_tx_rx_set_dline_mask(dir, data->regmap, 0x0); + + /* 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_tx_rx; + } + + 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); + + /* 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); + +out_enable_tx_rx: + /* 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 000000000000000..f3f4441a6cb2e20 --- /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 20bd8659afffb56..3b166e73892e43f 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 f6a39f0f98473ca..53b1a6f39176f00 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 000000000000000..aba24c445f1ae6d --- /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.sdl b/drivers/display/Kconfig.sdl index a06b143f31ed4df..bfa1f07c48e3bdb 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 1d998c33e8f996a..11efe7668973b4f 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 31951bd8180f13e..75678d2f66310e4 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 000000000000000..cddf14e11f2fb17 --- /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 000000000000000..ff989dd44cf247c --- /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 9a71197b481c70e..b14846ae3438531 100644 --- a/drivers/display/display_hx8394.c +++ b/drivers/display/display_hx8394.c @@ -31,7 +31,7 @@ struct hx8394_config { #define HX8394_MIPI_LP_CD_DIS BIT(5) #define HX8394_MIPI_TA_6TL 0x3 #define HX8394_MIPI_DPHYCMD_LPRX_8NS 0x40 -#define HX8394_MIPI_DPHYCMD_LPRX_66mV 0x10 +#define HX8394_MIPI_DPHYCMD_LPRX_66mV 0x20 #define HX8394_MIPI_DPHYCMD_LPTX_SRLIM 0x8 #define HX8394_MIPI_DPHYCMD_LDO_1_55V 0x60 #define HX8394_MIPI_DPHYCMD_HSRX_7X 0x8 @@ -404,7 +404,7 @@ const uint8_t hx8394_bank0[] = { const uint8_t hx8394_cmd3[] = {0xC6U, 0xEDU}; -const uint8_t tear_config[] = {HX8394_SET_TEAR, HX8394_TEAR_VBLANK | 0x3}; +const uint8_t tear_config[] = {HX8394_SET_TEAR, HX8394_TEAR_VBLANK}; static int hx8394_write(const struct device *dev, const uint16_t x, const uint16_t y, @@ -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_intel_multibootfb.c b/drivers/display/display_intel_multibootfb.c index fc2ef3f32f53ce4..e2b93b60940c76e 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 6613e4c5e4779ab..f3ccc52c9d49dbc 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 830bc3e9a0cfc23..304638011f1e440 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 dd36126a7ce3d97..d88bc760e76adc7 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 2463b4311440c29..5f00ac3a13c5b3b 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 edf9d6eb55df9e9..e63a44618101db5 100644 --- a/drivers/display/display_rm67162.c +++ b/drivers/display/display_rm67162.c @@ -13,6 +13,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(rm67162, CONFIG_DISPLAY_LOG_LEVEL); @@ -433,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; @@ -515,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) { @@ -568,13 +551,36 @@ static int rm67162_set_orientation(const struct device *dev, return -ENOTSUP; } +#ifdef CONFIG_PM_DEVICE + +static int rm67162_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct rm67162_config *config = dev->config; + struct rm67162_data *data = dev->data; + struct mipi_dsi_device mdev = {0}; + + mdev.data_lanes = config->num_of_lanes; + mdev.pixfmt = data->pixel_format; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + /* Detach from the MIPI DSI controller */ + return mipi_dsi_detach(config->mipi_dsi, config->channel, &mdev); + case PM_DEVICE_ACTION_RESUME: + return mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev); + default: + return -ENOTSUP; + } +} + +#endif /* CONFIG_PM_DEVICE */ + static const struct display_driver_api rm67162_api = { .blanking_on = rm67162_blanking_on, .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, }; @@ -593,9 +599,10 @@ static const struct display_driver_api rm67162_api = { static struct rm67162_data rm67162_data_##id = { \ .pixel_format = DT_INST_PROP(id, pixel_format), \ }; \ + PM_DEVICE_DT_INST_DEFINE(id, rm67162_pm_action); \ DEVICE_DT_INST_DEFINE(id, \ &rm67162_init, \ - NULL, \ + PM_DEVICE_DT_INST_GET(id), \ &rm67162_data_##id, \ &rm67162_config_##id, \ POST_KERNEL, \ diff --git a/drivers/display/display_rm68200.c b/drivers/display/display_rm68200.c index a89e0d0201a8764..7048790bdf39652 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 2a457249edede40..f21288d1b0f94c9 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 a7ad1929f4ea969..0e995a341c9a317 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 91ea890c13b4d9c..54973777f1be055 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 a20242d97037935..88c282d89f88e9c 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 56440c369c9c617..0d3a9eb37aadad8 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 99001c3b37b1bba..a70cea32461d8bf 100644 --- a/drivers/display/display_stm32_ltdc.c +++ b/drivers/display/display_stm32_ltdc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(display_stm32_ltdc, CONFIG_DISPLAY_LOG_LEVEL); @@ -54,27 +55,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 +73,26 @@ 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); }; -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 +163,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; + } - 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); + 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); + } + + } + + 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 +228,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 +237,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); } @@ -305,19 +324,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,13 +420,8 @@ 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 @@ -414,16 +450,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 +568,7 @@ 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, \ }; \ DEVICE_DT_INST_DEFINE(inst, \ &stm32_ltdc_init, \ diff --git a/drivers/display/uc81xx.c b/drivers/display/uc81xx.c index 88df6be0289a7c0..3aafe9337500e91 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 322423324ad9566..aba38ac3e7fe81c 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 5a11cd7f324a6f2..7231848a05aee49 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -34,3 +34,9 @@ zephyr_library_sources_ifdef(CONFIG_DMA_XMC4XXX dma_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_DMA_RPI_PICO dma_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_MCUX_PXP dma_mcux_pxp.c) zephyr_library_sources_ifdef(CONFIG_DMA_MCUX_SMARTDMA dma_mcux_smartdma.c) +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 37cd83383d86cc3..7f584dae57bcd45 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -64,4 +64,16 @@ source "drivers/dma/Kconfig.mcux_pxp" source "drivers/dma/Kconfig.mcux_smartdma" +source "drivers/dma/Kconfig.andes_atcdmac300" + +source "drivers/dma/Kconfig.sedi" + +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.andes_atcdmac300 b/drivers/dma/Kconfig.andes_atcdmac300 new file mode 100644 index 000000000000000..cb1133cdeb5dc05 --- /dev/null +++ b/drivers/dma/Kconfig.andes_atcdmac300 @@ -0,0 +1,12 @@ +# Andestech ATCDMAC300 configuration options +# Copyright (c) 2023 Andes Technology Corporation. + +# SPDX-License-Identifier: Apache-2.0 + + +config DMA_ANDES_ATCDMAC300 + bool "Using Andes ATCDMAC300 DMA driver" + default y + depends on DT_HAS_ANDESTECH_ATCDMAC300_ENABLED + help + Andes ATCDMAC300 DMA driver. diff --git a/drivers/dma/Kconfig.emul b/drivers/dma/Kconfig.emul new file mode 100644 index 000000000000000..595f577f3d100b1 --- /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.mcux_edma b/drivers/dma/Kconfig.mcux_edma index 0362a5faad649fe..d1e513e3c136fb3 100644 --- a/drivers/dma/Kconfig.mcux_edma +++ b/drivers/dma/Kconfig.mcux_edma @@ -28,10 +28,10 @@ config DMA_TCD_QUEUE_SIZE config DMA_MCUX_TEST_SLOT_START int "test slot start num" - depends on (SOC_SERIES_KINETIS_K6X || SOC_SERIES_KINETIS_KE1XF || SOC_SERIES_S32K3_M7) + depends on (SOC_SERIES_KINETIS_K6X || SOC_SERIES_KINETIS_KE1XF || SOC_SERIES_S32K3XX) default 58 if SOC_SERIES_KINETIS_K6X default 60 if SOC_SERIES_KINETIS_KE1XF - default 62 if SOC_SERIES_S32K3_M7 + default 62 if SOC_SERIES_S32K3XX help test slot start num diff --git a/drivers/dma/Kconfig.nxp_edma b/drivers/dma/Kconfig.nxp_edma new file mode 100644 index 000000000000000..3698605451ab6ae --- /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/Kconfig.nxp_sof_host_dma b/drivers/dma/Kconfig.nxp_sof_host_dma new file mode 100644 index 000000000000000..f909612f3aa302c --- /dev/null +++ b/drivers/dma/Kconfig.nxp_sof_host_dma @@ -0,0 +1,34 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config DMA_NXP_SOF_HOST_DMA + bool "NXP DMA driver used by SOF's host component" + default y + depends on DT_HAS_NXP_SOF_HOST_DMA_ENABLED + help + Enable NXP's DMA driver used by + SOF (Sound Open Firmware) host + component. Specifically, this driver + is used by the SOF host component to + perform transfers between the host + memory and firmware (local) memory, which + can be accessed without an actual + DMA engine. + +if DMA_NXP_SOF_HOST_DMA + +config DMA_NXP_SOF_HOST_DMA_ALIGN + int "Alignment (in bytes) required for memory regions passed to this driver" + default 8 + help + Use this to set the alignment (in bytes) + which shall be used by entities employing + this driver to adjust a memory region's size + and base address. Since this driver doesn't + actually have any hardware to back it up this + configuration doesn't make much sense as there's + no alignment restrictions imposed by memcpy. + Nevertheless, this is needed because this driver + needs to act as if it controls a DMA engine. + +endif # DMA_NXP_SOF_HOST_DMA diff --git a/drivers/dma/Kconfig.sedi b/drivers/dma/Kconfig.sedi new file mode 100644 index 000000000000000..9f07bff903a454e --- /dev/null +++ b/drivers/dma/Kconfig.sedi @@ -0,0 +1,14 @@ +# Intel sedi DMA configuration options + +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config DMA_SEDI + bool "SEDI DMA driver" + select DMA_64BIT + default y + depends on DT_HAS_INTEL_SEDI_DMA_ENABLED + help + This option enables the Intel SEDI DMA driver. + This driver is simply a shim driver built upon the SEDI + bare metal DMA driver in the hal-intel module diff --git a/drivers/dma/Kconfig.smartbond b/drivers/dma/Kconfig.smartbond new file mode 100644 index 000000000000000..3234e13020feccb --- /dev/null +++ b/drivers/dma/Kconfig.smartbond @@ -0,0 +1,11 @@ +# Smartbond DMA Accelerator Configuration Options + +# Copyright (c) 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config DMA_SMARTBOND + bool "Smartbond DMA Accelerator Driver" + depends on DT_HAS_RENESAS_SMARTBOND_DMA_ENABLED + default y + help + Enable Smartbond DMA Accelerator Driver diff --git a/drivers/dma/dma_andes_atcdmac300.c b/drivers/dma/dma_andes_atcdmac300.c new file mode 100644 index 000000000000000..ef90868f943065a --- /dev/null +++ b/drivers/dma/dma_andes_atcdmac300.c @@ -0,0 +1,536 @@ +/* + * Copyright (c) 2023 Andes Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT andestech_atcdmac300 + +#define LOG_LEVEL CONFIG_DMA_LOG_LEVEL +#include +LOG_MODULE_REGISTER(dma_andes_atcdmac300); + +#define ATCDMAC100_MAX_CHAN 8 + +#define DMA_ABORT(dev) (((struct dma_atcdmac300_cfg *)dev->config)->base + 0x24) +#define DMA_INT_STATUS(dev) \ + (((struct dma_atcdmac300_cfg *)dev->config)->base + 0x30) + +#define DMA_CH_OFFSET(ch) (ch * 0x20) +#define DMA_CH_CTRL(dev, ch) \ + (((struct dma_atcdmac300_cfg *)dev->config)->base + 0x40 + DMA_CH_OFFSET(ch)) +#define DMA_CH_TRANSIZE(dev, ch) \ + (((struct dma_atcdmac300_cfg *)dev->config)->base + 0x44 + DMA_CH_OFFSET(ch)) +#define DMA_CH_SRC_ADDR_L(dev, ch) \ + (((struct dma_atcdmac300_cfg *)dev->config)->base + 0x48 + DMA_CH_OFFSET(ch)) +#define DMA_CH_SRC_ADDR_H(dev, ch) \ + (((struct dma_atcdmac300_cfg *)dev->config)->base + 0x4C + DMA_CH_OFFSET(ch)) +#define DMA_CH_DST_ADDR_L(dev, ch) \ + (((struct dma_atcdmac300_cfg *)dev->config)->base + 0x50 + DMA_CH_OFFSET(ch)) +#define DMA_CH_DST_ADDR_H(dev, ch) \ + (((struct dma_atcdmac300_cfg *)dev->config)->base + 0x54 + DMA_CH_OFFSET(ch)) +#define DMA_CH_LL_PTR_L(dev, ch) \ + (((struct dma_atcdmac300_cfg *)dev->config)->base + 0x58 + DMA_CH_OFFSET(ch)) +#define DMA_CH_LL_PTR_H(dev, ch) \ + (((struct dma_atcdmac300_cfg *)dev->config)->base + 0x5C + DMA_CH_OFFSET(ch)) + +/* Source burst size options */ +#define DMA_BSIZE_1 (0) +#define DMA_BSIZE_2 (1) +#define DMA_BSIZE_4 (2) +#define DMA_BSIZE_8 (3) +#define DMA_BSIZE_16 (4) +#define DMA_BSIZE_32 (5) +#define DMA_BSIZE_64 (6) +#define DMA_BSIZE_128 (7) +#define DMA_BSIZE_256 (8) +#define DMA_BSIZE_512 (9) +#define DMA_BSIZE_1024 (10) + +/* Source/Destination transfer width options */ +#define DMA_WIDTH_BYTE (0) +#define DMA_WIDTH_HALFWORD (1) +#define DMA_WIDTH_WORD (2) +#define DMA_WIDTH_DWORD (3) +#define DMA_WIDTH_QWORD (4) +#define DMA_WIDTH_EWORD (5) + +/* Bus interface index */ +#define DMA_INF_IDX0 (0) +#define DMA_INF_IDX1 (1) + +/* DMA Channel Control Register Definition */ +#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(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_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_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)) +#define DMA_CH_CTRL_DSTADDR_FIX FIELD_PREP(DMA_CH_CTRL_DSTADDRCTRL_MASK, (2)) +#define DMA_CH_CTRL_SRCREQ_MASK GENMASK(11, 8) +#define DMA_CH_CTRL_SRCREQ(n) FIELD_PREP(DMA_CH_CTRL_SRCREQ_MASK, (n)) +#define DMA_CH_CTRL_DSTREQ_MASK GENMASK(7, 4) +#define DMA_CH_CTRL_DSTREQ(n) FIELD_PREP(DMA_CH_CTRL_DSTREQ_MASK, (n)) +#define DMA_CH_CTRL_INTABT BIT(3) +#define DMA_CH_CTRL_INTERR BIT(2) +#define DMA_CH_CTRL_INTTC BIT(1) +#define DMA_CH_CTRL_ENABLE BIT(0) + +/* DMA Interrupt Status Register Definition */ +#define DMA_INT_STATUS_TC_MASK GENMASK(23, 16) +#define DMA_INT_STATUS_ABORT_MASK GENMASK(15, 8) +#define DMA_INT_STATUS_ERROR_MASK GENMASK(7, 0) +#define DMA_INT_STATUS_TC_VAL(x) FIELD_GET(DMA_INT_STATUS_TC_MASK, (x)) +#define DMA_INT_STATUS_ABORT_VAL(x) FIELD_GET(DMA_INT_STATUS_ABORT_MASK, (x)) +#define DMA_INT_STATUS_ERROR_VAL(x) FIELD_GET(DMA_INT_STATUS_ERROR_MASK, (x)) +#define DMA_INT_STATUS_CH_MSK(ch) (0x111 << ch) + +typedef void (*atcdmac300_cfg_func_t)(void); + +struct chain_block { + uint32_t ctrl; + uint32_t transize; + uint32_t srcaddrl; + uint32_t srcaddrh; + uint32_t dstaddrl; + uint32_t dstaddrh; + uint32_t llpointerl; + uint32_t llpointerh; +#if __riscv_xlen == 32 + uint32_t reserved; +#endif + struct chain_block *next_block; +}; + +/* data for each DMA channel */ +struct dma_chan_data { + void *blkuser_data; + dma_callback_t blkcallback; + struct chain_block *head_block; + struct dma_status status; +}; + +/* Device run time data */ +struct dma_atcdmac300_data { + struct dma_chan_data chan[ATCDMAC100_MAX_CHAN]; + struct k_spinlock lock; +}; + +/* Device constant configuration parameters */ +struct dma_atcdmac300_cfg { + atcdmac300_cfg_func_t irq_config; + uint32_t base; + uint32_t irq_num; +}; + +static struct __aligned(64) + chain_block dma_chain[ATCDMAC100_MAX_CHAN][sizeof(struct chain_block) * 16]; + +static void dma_atcdmac300_isr(const struct device *dev) +{ + uint32_t int_status, int_ch_status, channel; + struct dma_atcdmac300_data *const data = dev->data; + struct dma_chan_data *ch_data; + k_spinlock_key_t key; + + key = k_spin_lock(&data->lock); + int_status = sys_read32(DMA_INT_STATUS(dev)); + /* Clear interrupt*/ + sys_write32(int_status, DMA_INT_STATUS(dev)); + + k_spin_unlock(&data->lock, key); + + /* Handle terminal count status */ + int_ch_status = DMA_INT_STATUS_TC_VAL(int_status); + while (int_ch_status) { + channel = find_msb_set(int_ch_status) - 1; + int_ch_status &= ~(BIT(channel)); + + ch_data = &data->chan[channel]; + if (ch_data->blkcallback) { + ch_data->blkcallback(dev, ch_data->blkuser_data, channel, 0); + } + data->chan[channel].status.busy = false; + } + + /* Handle error status */ + int_ch_status = DMA_INT_STATUS_ERROR_VAL(int_status); + while (int_ch_status) { + channel = find_msb_set(int_ch_status) - 1; + int_ch_status &= ~(BIT(channel)); + + ch_data = &data->chan[channel]; + if (ch_data->blkcallback) { + ch_data->blkcallback(dev, ch_data->blkuser_data, channel, -EIO); + } + } +} + +static int dma_atcdmac300_config(const struct device *dev, uint32_t channel, + struct dma_config *cfg) +{ + struct dma_atcdmac300_data *const data = dev->data; + uint32_t src_width, dst_width, src_burst_size, ch_ctrl, tfr_size; + int32_t ret = 0; + struct dma_block_config *cfg_blocks; + k_spinlock_key_t key; + + if (channel >= ATCDMAC100_MAX_CHAN) { + return -EINVAL; + } + + __ASSERT_NO_MSG(cfg->source_data_size == cfg->dest_data_size); + __ASSERT_NO_MSG(cfg->source_burst_length == cfg->dest_burst_length); + + if (cfg->source_data_size != 1 && cfg->source_data_size != 2 && + cfg->source_data_size != 4) { + LOG_ERR("Invalid 'source_data_size' value"); + ret = -EINVAL; + goto end; + } + + cfg_blocks = cfg->head_block; + if (cfg_blocks == NULL) { + ret = -EINVAL; + goto end; + } + + tfr_size = cfg_blocks->block_size/cfg->source_data_size; + if (tfr_size == 0) { + ret = -EINVAL; + goto end; + } + + ch_ctrl = 0; + + switch (cfg->channel_direction) { + case MEMORY_TO_MEMORY: + break; + case MEMORY_TO_PERIPHERAL: + ch_ctrl |= DMA_CH_CTRL_DSTREQ(cfg->dma_slot); + ch_ctrl |= DMA_CH_CTRL_DMODE_HANDSHAKE; + break; + case PERIPHERAL_TO_MEMORY: + ch_ctrl |= DMA_CH_CTRL_SRCREQ(cfg->dma_slot); + ch_ctrl |= DMA_CH_CTRL_SMODE_HANDSHAKE; + break; + default: + ret = -EINVAL; + goto end; + } + + + switch (cfg_blocks->source_addr_adj) { + case DMA_ADDR_ADJ_INCREMENT: + ch_ctrl |= DMA_CH_CTRL_SRCADDR_INC; + break; + case DMA_ADDR_ADJ_DECREMENT: + ch_ctrl |= DMA_CH_CTRL_SRCADDR_DEC; + break; + case DMA_ADDR_ADJ_NO_CHANGE: + ch_ctrl |= DMA_CH_CTRL_SRCADDR_FIX; + break; + default: + ret = -EINVAL; + goto end; + } + + switch (cfg_blocks->dest_addr_adj) { + case DMA_ADDR_ADJ_INCREMENT: + ch_ctrl |= DMA_CH_CTRL_DSTADDR_INC; + break; + case DMA_ADDR_ADJ_DECREMENT: + ch_ctrl |= DMA_CH_CTRL_DSTADDR_DEC; + break; + case DMA_ADDR_ADJ_NO_CHANGE: + ch_ctrl |= DMA_CH_CTRL_DSTADDR_FIX; + break; + default: + ret = -EINVAL; + goto end; + } + + ch_ctrl |= DMA_CH_CTRL_INTABT; + + /* Disable the error callback */ + if (!cfg->error_callback_en) { + ch_ctrl |= DMA_CH_CTRL_INTERR; + } + + src_width = find_msb_set(cfg->source_data_size) - 1; + dst_width = find_msb_set(cfg->dest_data_size) - 1; + src_burst_size = find_msb_set(cfg->source_burst_length) - 1; + + ch_ctrl |= DMA_CH_CTRL_SWIDTH(src_width) | + DMA_CH_CTRL_DWIDTH(dst_width) | + DMA_CH_CTRL_SBSIZE(src_burst_size); + + + /* Reset DMA channel configuration */ + sys_write32(0, DMA_CH_CTRL(dev, channel)); + + key = k_spin_lock(&data->lock); + /* Clear DMA interrupts status */ + sys_write32(DMA_INT_STATUS_CH_MSK(channel), DMA_INT_STATUS(dev)); + k_spin_unlock(&data->lock, key); + + /* Set transfer size */ + sys_write32(tfr_size, DMA_CH_TRANSIZE(dev, channel)); + + /* Update the status of channel */ + data->chan[channel].status.dir = cfg->channel_direction; + data->chan[channel].status.pending_length = cfg->source_data_size; + + /* Configure a callback appropriately depending on whether the + * interrupt is requested at the end of transaction completion or + * at the end of each block. + */ + data->chan[channel].blkcallback = cfg->dma_callback; + data->chan[channel].blkuser_data = cfg->user_data; + + sys_write32(ch_ctrl, DMA_CH_CTRL(dev, channel)); + + /* Set source and destination address */ + sys_write32(cfg_blocks->source_address, + DMA_CH_SRC_ADDR_L(dev, channel)); + sys_write32(0, DMA_CH_SRC_ADDR_H(dev, channel)); + sys_write32(cfg_blocks->dest_address, + DMA_CH_DST_ADDR_L(dev, channel)); + sys_write32(0, DMA_CH_DST_ADDR_H(dev, channel)); + + if (cfg->dest_chaining_en == 1 && cfg_blocks->next_block) { + uint32_t current_block_idx = 0; + + sys_write32((uint32_t)((long)&dma_chain[channel][current_block_idx]), + DMA_CH_LL_PTR_L(dev, channel)); + sys_write32(0, DMA_CH_LL_PTR_H(dev, channel)); + + for (cfg_blocks = cfg_blocks->next_block; cfg_blocks != NULL; + cfg_blocks = cfg_blocks->next_block) { + + ch_ctrl &= ~(DMA_CH_CTRL_SRCADDRCTRL_MASK | + DMA_CH_CTRL_DSTADDRCTRL_MASK); + + switch (cfg_blocks->source_addr_adj) { + case DMA_ADDR_ADJ_INCREMENT: + ch_ctrl |= DMA_CH_CTRL_SRCADDR_INC; + break; + case DMA_ADDR_ADJ_DECREMENT: + ch_ctrl |= DMA_CH_CTRL_SRCADDR_DEC; + break; + case DMA_ADDR_ADJ_NO_CHANGE: + ch_ctrl |= DMA_CH_CTRL_SRCADDR_FIX; + break; + default: + ret = -EINVAL; + goto end; + } + + switch (cfg_blocks->dest_addr_adj) { + case DMA_ADDR_ADJ_INCREMENT: + ch_ctrl |= DMA_CH_CTRL_DSTADDR_INC; + break; + case DMA_ADDR_ADJ_DECREMENT: + ch_ctrl |= DMA_CH_CTRL_DSTADDR_DEC; + break; + case DMA_ADDR_ADJ_NO_CHANGE: + ch_ctrl |= DMA_CH_CTRL_DSTADDR_FIX; + break; + default: + ret = -EINVAL; + goto end; + } + dma_chain[channel][current_block_idx].ctrl = ch_ctrl; + dma_chain[channel][current_block_idx].transize = + cfg_blocks->block_size/cfg->source_data_size; + + dma_chain[channel][current_block_idx].srcaddrl = + (uint32_t)cfg_blocks->source_address; + dma_chain[channel][current_block_idx].srcaddrh = 0x0; + + dma_chain[channel][current_block_idx].dstaddrl = + (uint32_t)((long)cfg_blocks->dest_address); + dma_chain[channel][current_block_idx].dstaddrh = 0x0; + + if (cfg_blocks->next_block) { + dma_chain[channel][current_block_idx].llpointerl = + (uint32_t)&dma_chain[channel][current_block_idx + 1]; + dma_chain[channel][current_block_idx].llpointerh = 0x0; + + current_block_idx = current_block_idx + 1; + + } else { + dma_chain[channel][current_block_idx].llpointerl = 0x0; + dma_chain[channel][current_block_idx].llpointerh = 0x0; + dma_chain[channel][current_block_idx].next_block = NULL; + } + } + } else { + /* Single transfer is supported, but Chain transfer is still + * not supported. Therefore, set LLPointer to zero + */ + sys_write32(0, DMA_CH_LL_PTR_L(dev, channel)); + sys_write32(0, DMA_CH_LL_PTR_H(dev, channel)); + } + +end: + return ret; +} + +static int dma_atcdmac300_reload(const struct device *dev, uint32_t channel, + uint32_t src, uint32_t dst, size_t size) +{ + uint32_t src_width; + + if (channel >= ATCDMAC100_MAX_CHAN) { + return -EINVAL; + } + + /* Set source and destination address */ + sys_write32(src, DMA_CH_SRC_ADDR_L(dev, channel)); + sys_write32(0, DMA_CH_SRC_ADDR_H(dev, channel)); + sys_write32(dst, DMA_CH_DST_ADDR_L(dev, channel)); + sys_write32(0, DMA_CH_DST_ADDR_H(dev, channel)); + + src_width = FIELD_GET(DMA_CH_CTRL_SWIDTH_MASK, sys_read32(DMA_CH_CTRL(dev, channel))); + src_width = BIT(src_width); + + /* Set transfer size */ + sys_write32(size/src_width, DMA_CH_TRANSIZE(dev, channel)); + + return 0; +} + +static int dma_atcdmac300_transfer_start(const struct device *dev, + uint32_t channel) +{ + struct dma_atcdmac300_data *const data = dev->data; + + if (channel >= ATCDMAC100_MAX_CHAN) { + return -EINVAL; + } + + sys_write32(sys_read32(DMA_CH_CTRL(dev, channel)) | DMA_CH_CTRL_ENABLE, + DMA_CH_CTRL(dev, channel)); + + data->chan[channel].status.busy = true; + + return 0; +} + +static int dma_atcdmac300_transfer_stop(const struct device *dev, + uint32_t channel) +{ + struct dma_atcdmac300_data *const data = dev->data; + k_spinlock_key_t key; + + if (channel >= ATCDMAC100_MAX_CHAN) { + return -EINVAL; + } + + key = k_spin_lock(&data->lock); + + sys_write32(BIT(channel), DMA_ABORT(dev)); + sys_write32(0, DMA_CH_CTRL(dev, channel)); + sys_write32(FIELD_GET(DMA_INT_STATUS_ABORT_MASK, (channel)), DMA_INT_STATUS(dev)); + data->chan[channel].status.busy = false; + + k_spin_unlock(&data->lock, key); + + return 0; +} + +static int dma_atcdmac300_init(const struct device *dev) +{ + const struct dma_atcdmac300_cfg *const config = (struct dma_atcdmac300_cfg *)dev->config; + uint32_t ch_num; + + /* Disable all channels and Channel interrupts */ + for (ch_num = 0; ch_num < ATCDMAC100_MAX_CHAN; ch_num++) { + sys_write32(0, DMA_CH_CTRL(dev, ch_num)); + } + + sys_write32(0xFFFFFF, DMA_INT_STATUS(dev)); + + /* Configure interrupts */ + config->irq_config(); + + irq_enable(config->irq_num); + + return 0; +} + +static int dma_atcdmac300_get_status(const struct device *dev, + uint32_t channel, + struct dma_status *stat) +{ + struct dma_atcdmac300_data *const data = dev->data; + + stat->busy = data->chan[channel].status.busy; + stat->dir = data->chan[channel].status.dir; + stat->pending_length = data->chan[channel].status.pending_length; + + return 0; +} + +static const struct dma_driver_api dma_atcdmac300_api = { + .config = dma_atcdmac300_config, + .reload = dma_atcdmac300_reload, + .start = dma_atcdmac300_transfer_start, + .stop = dma_atcdmac300_transfer_stop, + .get_status = dma_atcdmac300_get_status +}; + +#define ATCDMAC300_INIT(n) \ + \ + static void dma_atcdmac300_irq_config_##n(void); \ + \ + static const struct dma_atcdmac300_cfg dma_config_##n = { \ + .irq_config = dma_atcdmac300_irq_config_##n, \ + .base = DT_INST_REG_ADDR(n), \ + .irq_num = DT_INST_IRQN(n), \ + }; \ + \ + static struct dma_atcdmac300_data dma_data_##n; \ + \ + DEVICE_DT_INST_DEFINE(0, \ + dma_atcdmac300_init, \ + NULL, \ + &dma_data_##n, \ + &dma_config_##n, \ + POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &dma_atcdmac300_api); \ + \ + static void dma_atcdmac300_irq_config_##n(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + 1, \ + dma_atcdmac300_isr, \ + DEVICE_DT_INST_GET(n), \ + 0); \ + } + + +DT_INST_FOREACH_STATUS_OKAY(ATCDMAC300_INIT) diff --git a/drivers/dma/dma_dw_common.c b/drivers/dma/dma_dw_common.c index bb000298385f431..22de9a7d9ef89c2 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" @@ -434,7 +435,7 @@ bool dw_dma_is_enabled(const struct device *dev, uint32_t channel) { const struct dw_dma_dev_cfg *const dev_cfg = dev->config; - return dw_read(dev_cfg->base, DW_DMA_CHAN_EN) & DW_CHAN_MASK(channel); + return dw_read(dev_cfg->base, DW_DMA_CHAN_EN) & DW_CHAN(channel); } int dw_dma_start(const struct device *dev, uint32_t channel) @@ -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 000000000000000..235593df6249928 --- /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_handlers.c b/drivers/dma/dma_handlers.c index 058cbbf462312f1..d84c151015219e3 100644 --- a/drivers/dma/dma_handlers.c +++ b/drivers/dma/dma_handlers.c @@ -5,7 +5,7 @@ */ #include -#include +#include /* Both of these APIs are assuming that the drive implementations are checking * the validity of the channel ID and returning -errno if it's bogus @@ -13,14 +13,14 @@ static inline int z_vrfy_dma_start(const struct device *dev, uint32_t channel) { - Z_OOPS(Z_SYSCALL_DRIVER_DMA(dev, start)); + K_OOPS(K_SYSCALL_DRIVER_DMA(dev, start)); return z_impl_dma_start((const struct device *)dev, channel); } #include static inline int z_vrfy_dma_stop(const struct device *dev, uint32_t channel) { - Z_OOPS(Z_SYSCALL_DRIVER_DMA(dev, stop)); + K_OOPS(K_SYSCALL_DRIVER_DMA(dev, stop)); return z_impl_dma_stop((const struct device *)dev, channel); } #include diff --git a/drivers/dma/dma_intel_adsp_gpdma.c b/drivers/dma/dma_intel_adsp_gpdma.c index 1601d9af6ac6a40..50e1fdae50e452e 100644 --- a/drivers/dma/dma_intel_adsp_gpdma.c +++ b/drivers/dma/dma_intel_adsp_gpdma.c @@ -320,6 +320,7 @@ static int intel_adsp_gpdma_enable(const struct device *dev) return 0; } +#ifdef CONFIG_PM_DEVICE static int intel_adsp_gpdma_disable(const struct device *dev) { const struct intel_adsp_gpdma_cfg *const dev_cfg = dev->config; @@ -328,7 +329,8 @@ static int intel_adsp_gpdma_disable(const struct device *dev) sys_write32(sys_read32(reg) & ~SHIM_CLKCTL_LPGPDMA_SPA, reg); return 0; } -#endif +#endif /* CONFIG_PM_DEVICE */ +#endif /* CONFIG_SOC_SERIES_INTEL_ACE */ static int intel_adsp_gpdma_power_on(const struct device *dev) { diff --git a/drivers/dma/dma_intel_adsp_hda.c b/drivers/dma/dma_intel_adsp_hda.c index 2dd0bea6ed6c268..7717013fddce99f 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,14 @@ int intel_adsp_hda_dma_stop(const struct device *dev, uint32_t channel) intel_adsp_hda_disable(cfg->base, cfg->regblock_size, channel); + /* host dma needs some cycles to completely stop */ + if (cfg->direction == HOST_TO_MEMORY || cfg->direction == MEMORY_TO_HOST) { + if (!WAIT_FOR(!(*DGCS(cfg->base, cfg->regblock_size, channel) & DGCS_GBUSY), 1000, + k_busy_wait(1))) { + return -EBUSY; + } + } + return pm_device_runtime_put(dev); } @@ -458,9 +464,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 b76d0820815beaa..ad004fc1cf865be 100644 --- a/drivers/dma/dma_intel_lpss.c +++ b/drivers/dma/dma_intel_lpss.c @@ -24,33 +24,104 @@ 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; }; -static int dma_intel_lpss_init(const struct device *dev) +int dma_intel_lpss_setup(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)) { - LOG_ERR("LPSS DMA parent not ready"); - ret = -ENODEV; - goto out; + if (dev_cfg->dw_cfg.base != 0) { + return dw_dma_setup(dev); } - base = DEVICE_MMIO_GET(dev_cfg->parent) + DMA_INTEL_LPSS_OFFSET; + return 0; +} + +void dma_intel_lpss_set_base(const struct device *dev, uintptr_t base) +{ + struct dma_intel_lpss_cfg *dev_cfg = (struct dma_intel_lpss_cfg *)dev->config; + dev_cfg->dw_cfg.base = base; +} - ret = dw_dma_setup(dev); +#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; + struct dw_dma_dev_cfg *const dev_cfg = &lpss_dev_cfg->dw_cfg; + struct dw_dma_chan_data *chan_data; + uint32_t ctrl_hi = 0; - if (ret != 0) { - LOG_ERR("failed to initialize LPSS DMA %s", dev->name); - goto out; + if (channel >= DW_CHAN_COUNT) { + return -EINVAL; } - ret = 0; -out: - return ret; + + chan_data = &dev_data->chan[channel]; + + chan_data->lli_current->sar = src; + chan_data->lli_current->dar = dst; + chan_data->ptr_data.current_ptr = dst; + chan_data->ptr_data.buffer_bytes = size; + + ctrl_hi = dw_read(dev_cfg->base, DW_CTRL_HIGH(channel)); + ctrl_hi &= ~(DW_CTLH_DONE(1) | DW_CTLH_BLOCK_TS_MASK); + ctrl_hi |= size & DW_CTLH_BLOCK_TS_MASK; + + chan_data->lli_current->ctrl_hi = ctrl_hi; + chan_data->ptr_data.start_ptr = DW_DMA_LLI_ADDRESS(chan_data->lli_current, + chan_data->direction); + chan_data->ptr_data.end_ptr = chan_data->ptr_data.start_ptr + + chan_data->ptr_data.buffer_bytes; + chan_data->ptr_data.hw_ptr = chan_data->ptr_data.start_ptr; + + chan_data->state = DW_DMA_PREPARED; + + return 0; +} + +int dma_intel_lpss_get_status(const struct device *dev, uint32_t channel, + struct dma_status *stat) +{ + struct dma_intel_lpss_cfg *lpss_dev_cfg = (struct dma_intel_lpss_cfg *)dev->config; + struct dw_dma_dev_cfg *const dev_cfg = &lpss_dev_cfg->dw_cfg; + struct dw_dma_dev_data *const dev_data = dev->data; + struct dw_dma_chan_data *chan_data; + uint32_t ctrl_hi; + size_t current_length; + bool done; + + if (channel >= DW_CHAN_COUNT) { + return -EINVAL; + } + + chan_data = &dev_data->chan[channel]; + ctrl_hi = dw_read(dev_cfg->base, DW_CTRL_HIGH(channel)); + current_length = ctrl_hi & DW_CTLH_BLOCK_TS_MASK; + done = ctrl_hi & DW_CTLH_DONE(1); + + if (!(dw_read(dev_cfg->base, DW_DMA_CHAN_EN) & DW_CHAN(channel))) { + stat->busy = false; + stat->pending_length = chan_data->ptr_data.buffer_bytes; + return 0; + } + stat->busy = true; + + if (done) { + stat->pending_length = 0; + } else if (current_length == chan_data->ptr_data.buffer_bytes) { + stat->pending_length = chan_data->ptr_data.buffer_bytes; + } else { + stat->pending_length = + chan_data->ptr_data.buffer_bytes - current_length; + } + + return 0; } void dma_intel_lpss_isr(const struct device *dev) @@ -61,6 +132,8 @@ void dma_intel_lpss_isr(const struct device *dev) static const struct dma_driver_api dma_intel_lpss_driver_api = { .config = dw_dma_config, .start = dw_dma_start, + .reload = dma_intel_lpss_reload, + .get_status = dma_intel_lpss_get_status, .stop = dw_dma_stop, }; @@ -82,7 +155,6 @@ static const struct dma_driver_api dma_intel_lpss_driver_api = { .dw_cfg = { \ .base = 0, \ }, \ - .parent = DEVICE_DT_GET(DT_INST_PHANDLE(n, dma_parent)),\ }; \ \ static struct dw_dma_dev_data dma_intel_lpss##n##_data = { \ @@ -90,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_INTEL_LPSS_INIT_PRIORITY, \ + &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 eb44d4fb5fca174..f8d9ab81e08fd2d 100644 --- a/drivers/dma/dma_mcux_lpc.c +++ b/drivers/dma/dma_mcux_lpc.c @@ -18,6 +18,7 @@ #include #include #include +#include #define DT_DRV_COMPAT nxp_lpc_dma @@ -40,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; @@ -82,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 */ @@ -112,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)); @@ -145,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 */ @@ -186,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 */ @@ -199,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, @@ -238,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, @@ -256,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, @@ -269,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; @@ -289,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; /* @@ -328,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"); @@ -373,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); @@ -383,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) { @@ -461,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)) { @@ -477,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, @@ -527,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; } } @@ -543,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; } @@ -554,11 +654,35 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, data->descriptors_queued = true; } - if (is_periph) { + if (config->dma_slot) { + uint32_t cfg_reg = 0; + + /* User supplied manual trigger configuration */ + if (config->dma_slot & LPC_DMA_PERIPH_REQ_EN) { + cfg_reg |= DMA_CHANNEL_CFG_PERIPHREQEN_MASK; + } + if (config->dma_slot & LPC_DMA_HWTRIG_EN) { + /* Setup hardware trigger */ + cfg_reg |= DMA_CHANNEL_CFG_HWTRIGEN_MASK; + if (config->dma_slot & LPC_DMA_TRIGTYPE_LEVEL) { + cfg_reg |= DMA_CHANNEL_CFG_TRIGTYPE_MASK; + } + if (config->dma_slot & LPC_DMA_TRIGPOL_HIGH_RISING) { + cfg_reg |= DMA_CHANNEL_CFG_TRIGPOL_MASK; + } + if (config->dma_slot & LPC_DMA_TRIGBURST) { + cfg_reg |= DMA_CHANNEL_CFG_TRIGBURST_MASK; + cfg_reg |= DMA_CHANNEL_CFG_BURSTPOWER( + LPC_DMA_GET_BURSTPOWER(config->dma_slot)); + } + } + p_handle->base->CHANNEL[p_handle->channel].CFG = cfg_reg; + } else if (is_periph) { DMA_EnableChannelPeriphRq(p_handle->base, p_handle->channel); } else { DMA_DisableChannelPeriphRq(p_handle->base, p_handle->channel); } + DMA_SetChannelPriority(p_handle->base, p_handle->channel, config->channel_priority); data->busy = false; if (config->dma_callback) { @@ -606,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; @@ -635,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, @@ -650,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 b1870b3959c1545..9899797ae53f151 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 000000000000000..aea1e25a5f090d6 --- /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 000000000000000..234b3fcb70a2d29 --- /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_nxp_sof_host_dma.c b/drivers/dma/dma_nxp_sof_host_dma.c new file mode 100644 index 000000000000000..6c03d84418ca6c9 --- /dev/null +++ b/drivers/dma/dma_nxp_sof_host_dma.c @@ -0,0 +1,284 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/* used for driver binding */ +#define DT_DRV_COMPAT nxp_sof_host_dma + +/* macros used to parse DTS properties */ +#define IDENTITY_VARGS(V, ...) IDENTITY(V) + +#define _SOF_HOST_DMA_CHANNEL_INDEX_ARRAY(inst)\ + LISTIFY(DT_INST_PROP_OR(inst, dma_channels, 0), IDENTITY_VARGS, (,)) + +#define _SOF_HOST_DMA_CHANNEL_DECLARE(idx) {} + +#define SOF_HOST_DMA_CHANNELS_DECLARE(inst)\ + FOR_EACH(_SOF_HOST_DMA_CHANNEL_DECLARE,\ + (,), _SOF_HOST_DMA_CHANNEL_INDEX_ARRAY(inst)) + +LOG_MODULE_REGISTER(nxp_sof_host_dma); + +/* note: This driver doesn't attempt to provide + * a generic software-based DMA engine implementation. + * As its name suggests, its only usage is in SOF + * (Sound Open Firmware) for NXP plaforms which are + * able to access the host memory directly from the + * core on which the firmware is running. + */ + +enum channel_state { + CHAN_STATE_INIT = 0, + CHAN_STATE_CONFIGURED, +}; + +struct sof_host_dma_channel { + uint32_t src; + uint32_t dest; + uint32_t size; + uint32_t direction; + enum channel_state state; +}; + +struct sof_host_dma_data { + /* this needs to be first */ + struct dma_context ctx; + atomic_t channel_flags; + struct sof_host_dma_channel *channels; +}; + +static int channel_change_state(struct sof_host_dma_channel *chan, + enum channel_state next) +{ + enum channel_state prev = chan->state; + + /* validate transition */ + switch (prev) { + case CHAN_STATE_INIT: + case CHAN_STATE_CONFIGURED: + if (next != CHAN_STATE_CONFIGURED) { + return -EPERM; + } + break; + default: + LOG_ERR("invalid channel previous state: %d", prev); + return -EINVAL; + } + + chan->state = next; + + return 0; +} + +static int sof_host_dma_reload(const struct device *dev, uint32_t chan_id, + uint32_t src, uint32_t dst, size_t size) +{ + ARG_UNUSED(src); + ARG_UNUSED(dst); + ARG_UNUSED(size); + + struct sof_host_dma_data *data; + struct sof_host_dma_channel *chan; + int ret; + + data = dev->data; + + if (chan_id >= data->ctx.dma_channels) { + LOG_ERR("channel %d is not a valid channel ID", chan_id); + return -EINVAL; + } + + /* fetch channel data */ + chan = &data->channels[chan_id]; + + /* validate state */ + if (chan->state != CHAN_STATE_CONFIGURED) { + LOG_ERR("attempting to reload unconfigured DMA channel %d", chan_id); + return -EINVAL; + } + + if (chan->direction == HOST_TO_MEMORY) { + /* the host may have modified the region we're about to copy + * to local memory. In this case, the data cache holds stale + * data so invalidate it to force a read from the main memory. + */ + ret = sys_cache_data_invd_range(UINT_TO_POINTER(chan->src), + chan->size); + if (ret < 0) { + LOG_ERR("failed to invalidate data cache range"); + return ret; + } + } + + memcpy(UINT_TO_POINTER(chan->dest), UINT_TO_POINTER(chan->src), chan->size); + + if (chan->direction == MEMORY_TO_HOST) { + /* force range to main memory so that host doesn't read any + * stale data. + */ + ret = sys_cache_data_flush_range(UINT_TO_POINTER(chan->dest), + chan->size); + if (ret < 0) { + LOG_ERR("failed to flush data cache range"); + return ret; + } + } + + return 0; +} + + +static int sof_host_dma_config(const struct device *dev, uint32_t chan_id, + struct dma_config *config) +{ + struct sof_host_dma_data *data; + struct sof_host_dma_channel *chan; + int ret; + + data = dev->data; + + if (chan_id >= data->ctx.dma_channels) { + LOG_ERR("channel %d is not a valid channel ID", chan_id); + return -EINVAL; + } + + /* fetch channel data */ + chan = &data->channels[chan_id]; + + /* attempt a state transition */ + ret = channel_change_state(chan, CHAN_STATE_CONFIGURED); + if (ret < 0) { + LOG_ERR("failed to change channel %d's state to CONFIGURED", chan_id); + return ret; + } + + /* SG configurations are not currently supported */ + if (config->block_count != 1) { + LOG_ERR("invalid number of blocks: %d", config->block_count); + return -EINVAL; + } + + if (!config->head_block->source_address) { + LOG_ERR("got NULL source address"); + return -EINVAL; + } + + if (!config->head_block->dest_address) { + LOG_ERR("got NULL destination address"); + return -EINVAL; + } + + if (!config->head_block->block_size) { + LOG_ERR("got 0 bytes to copy"); + return -EINVAL; + } + + /* for now, only H2M and M2H transfers are supported */ + if (config->channel_direction != HOST_TO_MEMORY && + config->channel_direction != MEMORY_TO_HOST) { + LOG_ERR("invalid channel direction: %d", + config->channel_direction); + return -EINVAL; + } + + /* latch onto the passed configuration */ + chan->src = config->head_block->source_address; + chan->dest = config->head_block->dest_address; + chan->size = config->head_block->block_size; + chan->direction = config->channel_direction; + + LOG_DBG("configured channel %d with SRC 0x%x DST 0x%x SIZE 0x%x", + chan_id, chan->src, chan->dest, chan->size); + + return 0; +} + +static int sof_host_dma_start(const struct device *dev, uint32_t chan_id) +{ + /* nothing to be done here */ + return 0; +} + +static int sof_host_dma_stop(const struct device *dev, uint32_t chan_id) +{ + /* nothing to be done here */ + return 0; +} + +static int sof_host_dma_suspend(const struct device *dev, uint32_t chan_id) +{ + /* nothing to be done here */ + return 0; +} + +static int sof_host_dma_resume(const struct device *dev, uint32_t chan_id) +{ + /* nothing to be done here */ + return 0; +} + +static int sof_host_dma_get_status(const struct device *dev, + uint32_t chan_id, struct dma_status *stat) +{ + /* nothing to be done here */ + return 0; +} + +static int sof_host_dma_get_attribute(const struct device *dev, uint32_t type, uint32_t *val) +{ + switch (type) { + case DMA_ATTR_COPY_ALIGNMENT: + case DMA_ATTR_BUFFER_SIZE_ALIGNMENT: + case DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT: + *val = CONFIG_DMA_NXP_SOF_HOST_DMA_ALIGN; + break; + default: + LOG_ERR("invalid attribute type: %d", type); + return -EINVAL; + } + + return 0; +} + +static const struct dma_driver_api sof_host_dma_api = { + .reload = sof_host_dma_reload, + .config = sof_host_dma_config, + .start = sof_host_dma_start, + .stop = sof_host_dma_stop, + .suspend = sof_host_dma_suspend, + .resume = sof_host_dma_resume, + .get_status = sof_host_dma_get_status, + .get_attribute = sof_host_dma_get_attribute, +}; + +static int sof_host_dma_init(const struct device *dev) +{ + struct sof_host_dma_data *data = dev->data; + + data->channel_flags = ATOMIC_INIT(0); + data->ctx.atomic = &data->channel_flags; + + return 0; +} + +static struct sof_host_dma_channel channels[] = { + SOF_HOST_DMA_CHANNELS_DECLARE(0), +}; + +static struct sof_host_dma_data sof_host_dma_data = { + .ctx.magic = DMA_MAGIC, + .ctx.dma_channels = ARRAY_SIZE(channels), + .channels = channels, +}; + +/* assumption: only 1 SOF_HOST_DMA instance */ +DEVICE_DT_INST_DEFINE(0, sof_host_dma_init, NULL, + &sof_host_dma_data, NULL, + PRE_KERNEL_1, CONFIG_DMA_INIT_PRIORITY, + &sof_host_dma_api); diff --git a/drivers/dma/dma_sedi.c b/drivers/dma/dma_sedi.c new file mode 100644 index 000000000000000..7c4ffa72e57755d --- /dev/null +++ b/drivers/dma/dma_sedi.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT intel_sedi_dma + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sedi_driver_dma.h" +#include "sedi_driver_core.h" + +#include +LOG_MODULE_REGISTER(sedi_dma, CONFIG_DMA_LOG_LEVEL); + +extern void dma_isr(sedi_dma_t dma_device); + +struct dma_sedi_config_info { + sedi_dma_t peripheral_id; /* Controller instance. */ + uint8_t chn_num; + void (*irq_config)(void); +}; + +struct dma_sedi_driver_data { + struct dma_config dma_configs[DMA_CHANNEL_NUM]; +}; + +#define DEV_DATA(dev) ((struct dma_sedi_driver_data *const)(dev)->data) +#define DEV_CFG(dev) \ + ((const struct dma_sedi_config_info *const)(dev)->config) + +/* + * this function will be called when dma transferring is completed + * or error happened + */ +static void dma_handler(sedi_dma_t dma_device, int channel, int event_id, + void *args) +{ + ARG_UNUSED(args); + const struct device *dev = (const struct device *)args; + struct dma_sedi_driver_data *const data = DEV_DATA(dev); + struct dma_config *config = &(data->dma_configs[channel]); + + /* run user-defined callback */ + if (config->dma_callback) { + if ((event_id == SEDI_DMA_EVENT_TRANSFER_DONE) && + (config->complete_callback_en)) { + config->dma_callback(dev, config->user_data, + channel, 0); + } else if (config->error_callback_en) { + config->dma_callback(dev, config->user_data, + channel, event_id); + } + } +} + +/* map width to certain macros*/ +static int width_index(uint32_t num_bytes, uint32_t *index) +{ + switch (num_bytes) { + case 1: + *index = DMA_TRANS_WIDTH_8; + break; + case 2: + *index = DMA_TRANS_WIDTH_16; + break; + case 4: + *index = DMA_TRANS_WIDTH_32; + break; + case 8: + *index = DMA_TRANS_WIDTH_64; + break; + case 16: + *index = DMA_TRANS_WIDTH_128; + break; + case 32: + *index = DMA_TRANS_WIDTH_256; + break; + default: + return -ENOTSUP; + } + + return 0; +} + +/* map burst size to certain macros*/ +static int burst_index(uint32_t num_units, uint32_t *index) +{ + switch (num_units) { + case 1: + *index = DMA_BURST_TRANS_LENGTH_1; + break; + case 4: + *index = DMA_BURST_TRANS_LENGTH_4; + break; + case 8: + *index = DMA_BURST_TRANS_LENGTH_8; + break; + case 16: + *index = DMA_BURST_TRANS_LENGTH_16; + break; + case 32: + *index = DMA_BURST_TRANS_LENGTH_32; + break; + case 64: + *index = DMA_BURST_TRANS_LENGTH_64; + break; + case 128: + *index = DMA_BURST_TRANS_LENGTH_128; + break; + case 256: + *index = DMA_BURST_TRANS_LENGTH_256; + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static void dma_config_convert(struct dma_config *config, + dma_memory_type_t *src_mem, + dma_memory_type_t *dst_mem, + uint8_t *sedi_dma_dir) +{ + + *src_mem = DMA_SRAM_MEM; + *dst_mem = DMA_SRAM_MEM; + *sedi_dma_dir = MEMORY_TO_MEMORY; + switch (config->channel_direction) { + case MEMORY_TO_MEMORY: + case MEMORY_TO_PERIPHERAL: + case PERIPHERAL_TO_MEMORY: + case PERIPHERAL_TO_PERIPHERAL: + *sedi_dma_dir = config->channel_direction; + break; + case MEMORY_TO_HOST: + *dst_mem = DMA_DRAM_MEM; + break; + case HOST_TO_MEMORY: + *src_mem = DMA_DRAM_MEM; + break; +#ifdef MEMORY_TO_IMR + case MEMORY_TO_IMR: + *dst_mem = DMA_UMA_MEM; + break; +#endif +#ifdef IMR_TO_MEMORY + case IMR_TO_MEMORY: + *src_mem = DMA_UMA_MEM; + break; +#endif + } +} + +/* config basic dma */ +static int dma_sedi_apply_common_config(sedi_dma_t dev, uint32_t channel, + struct dma_config *config, uint8_t *dir) +{ + uint8_t direction = MEMORY_TO_MEMORY; + dma_memory_type_t src_mem = DMA_SRAM_MEM, dst_mem = DMA_SRAM_MEM; + + dma_config_convert(config, &src_mem, &dst_mem, &direction); + + if (dir) { + *dir = direction; + } + + /* configure dma transferring direction*/ + sedi_dma_control(dev, channel, SEDI_CONFIG_DMA_DIRECTION, + direction); + + if (direction == MEMORY_TO_MEMORY) { + sedi_dma_control(dev, channel, SEDI_CONFIG_DMA_SR_MEM_TYPE, + src_mem); + sedi_dma_control(dev, channel, SEDI_CONFIG_DMA_DT_MEM_TYPE, + dst_mem); + } else if (direction == MEMORY_TO_PERIPHERAL) { + sedi_dma_control(dev, channel, SEDI_CONFIG_DMA_HS_DEVICE_ID, + config->dma_slot); + sedi_dma_control(dev, channel, SEDI_CONFIG_DMA_HS_POLARITY, + DMA_HS_POLARITY_HIGH); + sedi_dma_control(dev, channel, + SEDI_CONFIG_DMA_HS_DEVICE_ID_PER_DIR, + DMA_HS_PER_TX); + } else if (direction == PERIPHERAL_TO_MEMORY) { + sedi_dma_control(dev, channel, SEDI_CONFIG_DMA_HS_DEVICE_ID, + config->dma_slot); + sedi_dma_control(dev, channel, SEDI_CONFIG_DMA_HS_POLARITY, + DMA_HS_POLARITY_HIGH); + sedi_dma_control(dev, channel, + SEDI_CONFIG_DMA_HS_DEVICE_ID_PER_DIR, + DMA_HS_PER_RX); + } else { + return -1; + } + return 0; +} + +static int dma_sedi_apply_single_config(sedi_dma_t dev, uint32_t channel, + struct dma_config *config) +{ + int ret = 0; + uint32_t temp = 0; + + ret = dma_sedi_apply_common_config(dev, channel, config, NULL); + if (ret != 0) { + goto INVALID_ARGS; + } + /* configurate dma width of source data*/ + ret = width_index(config->source_data_size, &temp); + if (ret != 0) { + goto INVALID_ARGS; + } + sedi_dma_control(dev, channel, SEDI_CONFIG_DMA_SR_TRANS_WIDTH, temp); + + /* configurate dma width of destination data*/ + ret = width_index(config->dest_data_size, &temp); + if (ret != 0) { + goto INVALID_ARGS; + } + sedi_dma_control(dev, channel, SEDI_CONFIG_DMA_DT_TRANS_WIDTH, temp); + + /* configurate dma burst size*/ + ret = burst_index(config->source_burst_length, &temp); + if (ret != 0) { + goto INVALID_ARGS; + } + sedi_dma_control(dev, channel, SEDI_CONFIG_DMA_BURST_LENGTH, temp); + return 0; + +INVALID_ARGS: + return ret; +} + +static int dma_sedi_chan_config(const struct device *dev, uint32_t channel, + struct dma_config *config) +{ + if ((dev == NULL) || (channel >= DEV_CFG(dev)->chn_num) + || (config == NULL) + || (config->block_count != 1)) { + goto INVALID_ARGS; + } + + const struct dma_sedi_config_info *const info = DEV_CFG(dev); + struct dma_sedi_driver_data *const data = DEV_DATA(dev); + + memcpy(&(data->dma_configs[channel]), config, sizeof(struct dma_config)); + + /* initialize the dma controller, following the sedi api*/ + sedi_dma_event_cb_t cb = dma_handler; + + sedi_dma_init(info->peripheral_id, (int)channel, cb, (void *)dev); + + return 0; + +INVALID_ARGS: + return -1; +} + +static int dma_sedi_reload(const struct device *dev, uint32_t channel, + uint64_t src, uint64_t dst, size_t size) +{ + if ((dev == NULL) || (channel >= DEV_CFG(dev)->chn_num)) { + LOG_ERR("dma reload failed for invalid args"); + return -ENOTSUP; + } + + int ret = 0; + struct dma_sedi_driver_data *const data = DEV_DATA(dev); + struct dma_config *config = &(data->dma_configs[channel]); + struct dma_block_config *block_config; + + if ((config == NULL) || (config->head_block == NULL)) { + LOG_ERR("dma reload failed, no config found"); + return -ENOTSUP; + } + block_config = config->head_block; + + if ((config->block_count == 1) || (block_config->next_block == NULL)) { + block_config->source_address = src; + block_config->dest_address = dst; + block_config->block_size = size; + } else { + LOG_ERR("no reload support for multi-linkedlist mode"); + return -ENOTSUP; + } + return ret; +} + +static int dma_sedi_start(const struct device *dev, uint32_t channel) +{ + if ((dev == NULL) || (channel >= DEV_CFG(dev)->chn_num)) { + LOG_ERR("dma transferring failed for invalid args"); + return -ENOTSUP; + } + + int ret = -1; + const struct dma_sedi_config_info *const info = DEV_CFG(dev); + struct dma_sedi_driver_data *const data = DEV_DATA(dev); + struct dma_config *config = &(data->dma_configs[channel]); + struct dma_block_config *block_config = config->head_block; + uint64_t src_addr, dst_addr; + + if (config->block_count == 1) { + /* call sedi start function */ + ret = dma_sedi_apply_single_config(info->peripheral_id, + channel, config); + if (ret) { + goto ERR; + } + src_addr = block_config->source_address; + dst_addr = block_config->dest_address; + + ret = sedi_dma_start_transfer(info->peripheral_id, channel, + src_addr, dst_addr, block_config->block_size); + } else { + LOG_ERR("MULTIPLE_BLOCK CONFIG is not set"); + goto ERR; + } + + if (ret != SEDI_DRIVER_OK) { + goto ERR; + } + + return ret; + +ERR: + LOG_ERR("dma transfer failed"); + return ret; +} + +static int dma_sedi_stop(const struct device *dev, uint32_t channel) +{ + const struct dma_sedi_config_info *const info = DEV_CFG(dev); + + LOG_DBG("stopping dma: %p, %d", dev, channel); + sedi_dma_abort_transfer(info->peripheral_id, channel); + + return 0; +} + +static const struct dma_driver_api dma_funcs = { .config = dma_sedi_chan_config, + .start = dma_sedi_start, + .stop = dma_sedi_stop, + .reload = dma_sedi_reload, + .get_status = NULL +}; + +static int dma_sedi_init(const struct device *dev) +{ + const struct dma_sedi_config_info *const config = DEV_CFG(dev); + + config->irq_config(); + + return 0; +} + +#define DMA_DEVICE_INIT_SEDI(inst) \ + static void dma_sedi_##inst##_irq_config(void); \ + \ + static struct dma_sedi_driver_data dma_sedi_dev_data_##inst; \ + static const struct dma_sedi_config_info dma_sedi_config_data_##inst = { \ + .peripheral_id = DT_INST_PROP(inst, peripheral_id), \ + .chn_num = DT_INST_PROP(inst, dma_channels), \ + .irq_config = dma_sedi_##inst##_irq_config \ + }; \ + DEVICE_DT_DEFINE(DT_INST(inst, DT_DRV_COMPAT), &dma_sedi_init, \ + NULL, &dma_sedi_dev_data_##inst, &dma_sedi_config_data_##inst, PRE_KERNEL_2, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, (void *)&dma_funcs); \ + \ + static void dma_sedi_##inst##_irq_config(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), \ + DT_INST_IRQ(inst, priority), dma_isr, \ + (void *)DT_INST_PROP(inst, peripheral_id), \ + DT_INST_IRQ(inst, sense)); \ + irq_enable(DT_INST_IRQN(inst)); \ + } + +DT_INST_FOREACH_STATUS_OKAY(DMA_DEVICE_INIT_SEDI) diff --git a/drivers/dma/dma_smartbond.c b/drivers/dma/dma_smartbond.c new file mode 100644 index 000000000000000..79305c77d6a0674 --- /dev/null +++ b/drivers/dma/dma_smartbond.c @@ -0,0 +1,969 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(dma_smartbond, CONFIG_DMA_LOG_LEVEL); + +#define DT_DRV_COMPAT renesas_smartbond_dma + +#define SMARTBOND_IRQN DT_INST_IRQN(0) +#define SMARTBOND_IRQ_PRIO DT_INST_IRQ(0, priority) + +#define DMA_CHANNELS_COUNT DT_PROP(DT_NODELABEL(dma), dma_channels) +#define DMA_BLOCK_COUNT DT_PROP(DT_NODELABEL(dma), block_count) +#define DMA_SECURE_CHANNEL 7 + +#define DMA_CTRL_REG_SET_FIELD(_field, _var, _val) \ + (_var) = \ + (((_var) & ~DMA_DMA0_CTRL_REG_ ## _field ## _Msk) | \ + (((_val) << DMA_DMA0_CTRL_REG_ ## _field ## _Pos) & DMA_DMA0_CTRL_REG_ ## _field ## _Msk)) + +#define DMA_CTRL_REG_GET_FIELD(_field, _var) \ + (((_var) & DMA_DMA0_CTRL_REG_ ## _field ## _Msk) >> DMA_DMA0_CTRL_REG_ ## _field ## _Pos) + +#define DMA_CHN2REG(_idx) (&((struct channel_regs *)DMA)[(_idx)]) + +#define DMA_MUX_SHIFT(_idx) (((_idx) >> 1) * 4) + +#define DMA_REQ_MUX_REG_SET(_idx, _val) \ + DMA->DMA_REQ_MUX_REG = \ + (DMA->DMA_REQ_MUX_REG & ~(0xf << DMA_MUX_SHIFT((_idx)))) | \ + (((_val) & 0xf) << DMA_MUX_SHIFT((_idx))) + +#define DMA_REQ_MUX_REG_GET(_idx) \ + ((DMA->DMA_REQ_MUX_REG >> DMA_MUX_SHIFT((_idx))) & 0xf) + +#define CRYPTO_KEYS_BUF_ADDR 0x30040100 +#define CRYPTO_KEYS_BUF_SIZE 0x100 +#define IS_AES_KEYS_BUF_RANGE(_a) ((uint32_t)(_a) >= (uint32_t)(CRYPTO_KEYS_BUF_ADDR)) && \ + ((uint32_t)(_a) < (uint32_t)(CRYPTO_KEYS_BUF_ADDR + CRYPTO_KEYS_BUF_SIZE)) + +/* + * DMA channel priority level. The smaller the value the lower the priority granted to a channel + * when two or more channels request the bus at the same time. For channels of same priority an + * inherent mechanism is applied in which the lower the channel number the higher the priority. + */ +enum dma_smartbond_channel_prio { + DMA_SMARTBOND_CHANNEL_PRIO_0 = 0x0, /* Lowest channel priority */ + DMA_SMARTBOND_CHANNEL_PRIO_1, + DMA_SMARTBOND_CHANNEL_PRIO_2, + DMA_SMARTBOND_CHANNEL_PRIO_3, + DMA_SMARTBOND_CHANNEL_PRIO_4, + DMA_SMARTBOND_CHANNEL_PRIO_5, + DMA_SMARTBOND_CHANNEL_PRIO_6, + DMA_SMARTBOND_CHANNEL_PRIO_7, /* Highest channel priority */ + DMA_SMARTBOND_CHANNEL_PRIO_MAX +}; + +enum dma_smartbond_channel { + DMA_SMARTBOND_CHANNEL_0 = 0x0, + DMA_SMARTBOND_CHANNEL_1, + DMA_SMARTBOND_CHANNEL_2, + DMA_SMARTBOND_CHANNEL_3, + DMA_SMARTBOND_CHANNEL_4, + DMA_SMARTBOND_CHANNEL_5, + DMA_SMARTBOND_CHANNEL_6, + DMA_SMARTBOND_CHANNEL_7, + DMA_SMARTBOND_CHANNEL_MAX +}; + +enum dma_smartbond_burst_len { + DMA_SMARTBOND_BURST_LEN_1B = 0x1, /* Burst mode is disabled */ + DMA_SMARTBOND_BURST_LEN_4B = 0x4, /* Perform bursts of 4 beats (INCR4) */ + DMA_SMARTBOND_BURST_LEN_8B = 0x8 /* Perform bursts of 8 beats (INCR8) */ +}; + +/* + * DMA bus width indicating how many bytes are retrived/written per transfer. + * Note that the bus width is the same for the source and destination. + */ +enum dma_smartbond_bus_width { + DMA_SMARTBOND_BUS_WIDTH_1B = 0x1, + DMA_SMARTBOND_BUS_WIDTH_2B = 0x2, + DMA_SMARTBOND_BUS_WIDTH_4B = 0x4 +}; + +enum dreq_mode { + DREQ_MODE_SW = 0x0, + DREQ_MODE_HW +}; + +enum burst_mode { + BURST_MODE_0B = 0x0, + BURST_MODE_4B = 0x1, + BURST_MODE_8B = 0x2 +}; + +enum bus_width { + BUS_WIDTH_1B = 0x0, + BUS_WIDTH_2B = 0x1, + BUS_WIDTH_4B = 0x2 +}; + +enum addr_adj { + ADDR_ADJ_NO_CHANGE = 0x0, + ADDR_ADJ_INCR +}; + +enum copy_mode { + COPY_MODE_BLOCK = 0x0, + COPY_MODE_INIT +}; + +enum req_sense { + REQ_SENSE_LEVEL = 0x0, + REQ_SENSE_EDGE +}; + +struct channel_regs { + __IO uint32_t DMA_A_START; + __IO uint32_t DMA_B_START; + __IO uint32_t DMA_INT_REG; + __IO uint32_t DMA_LEN_REG; + __IO uint32_t DMA_CTRL_REG; + + __I uint32_t DMA_IDX_REG; + __I uint32_t RESERVED[2]; +}; + +struct dma_channel_data { + dma_callback_t cb; + void *user_data; + enum dma_smartbond_bus_width bus_width; + enum dma_smartbond_burst_len burst_len; + enum dma_channel_direction dir; + bool is_dma_configured; +}; + +struct dma_smartbond_data { + /* Should be the first member of the driver data */ + struct dma_context dma_ctx; + + ATOMIC_DEFINE(channels_atomic, DMA_CHANNELS_COUNT); + + /* User callbacks and data to be stored per channel */ + struct dma_channel_data channel_data[DMA_CHANNELS_COUNT]; +}; + +/* True if there is any DMA activity on any channel, false otheriwise. */ +static bool dma_smartbond_is_dma_active(void) +{ + int idx; + struct channel_regs *regs; + + for (idx = 0; idx < DMA_CHANNELS_COUNT; idx++) { + regs = DMA_CHN2REG(idx); + + if (DMA_CTRL_REG_GET_FIELD(DMA_ON, regs->DMA_CTRL_REG)) { + return true; + } + } + + return false; +} + +static void dma_smartbond_set_channel_status(uint32_t channel, bool status) +{ + unsigned int key; + struct channel_regs *regs = DMA_CHN2REG(channel); + + key = irq_lock(); + + if (status) { + /* Make sure the status register for the requested channel is cleared. */ + DMA->DMA_CLEAR_INT_REG |= BIT(channel); + /* Enable interrupts for the requested channel. */ + DMA->DMA_INT_MASK_REG |= BIT(channel); + + /* Check if this is the first attempt to enable DMA interrupts. */ + if (!irq_is_enabled(SMARTBOND_IRQN)) { + irq_enable(SMARTBOND_IRQN); + } + + DMA_CTRL_REG_SET_FIELD(DMA_ON, regs->DMA_CTRL_REG, 0x1); + } else { + DMA_CTRL_REG_SET_FIELD(DMA_ON, regs->DMA_CTRL_REG, 0x0); + + /* + * It might happen that DMA is already in progress. Make sure the current + * on-going transfer is complete (cannot be interrupted). + */ + while (DMA_CTRL_REG_GET_FIELD(DMA_ON, regs->DMA_CTRL_REG)) { + } + + /* Disable interrupts for the requested channel */ + DMA->DMA_INT_MASK_REG &= ~(BIT(channel)); + /* Clear the status register; the requested channel should be considered obsolete */ + DMA->DMA_CLEAR_INT_REG |= BIT(channel); + + /* DMA interrupts should be disabled only if all channels are disabled. */ + if (!dma_smartbond_is_dma_active()) { + irq_disable(SMARTBOND_IRQN); + } + } + + irq_unlock(key); +} + +static bool dma_channel_dst_addr_check_and_adjust(uint32_t channel, uint32_t *dst) +{ + uint32_t phy_address; + uint32_t secure_boot_reg; + bool is_aes_keys_protected, is_qspic_keys_protected; + + phy_address = black_orca_phy_addr(*dst); + + secure_boot_reg = CRG_TOP->SECURE_BOOT_REG; + is_aes_keys_protected = + (secure_boot_reg & CRG_TOP_SECURE_BOOT_REG_PROT_AES_KEY_READ_Msk); + is_qspic_keys_protected = + (secure_boot_reg & CRG_TOP_SECURE_BOOT_REG_PROT_QSPI_KEY_READ_Msk); + + /* + * If the destination address reflects the AES key buffer area and secure keys are protected + * then only the secure channel #7 can be used to transfer data to AES key buffer. + */ + if ((IS_AES_KEYS_BUF_RANGE(phy_address) && + (is_aes_keys_protected || is_qspic_keys_protected) && + (channel != DMA_SECURE_CHANNEL))) { + LOG_ERR("Keys are protected. Only secure channel #7 can be employed."); + return false; + } + + if (IS_QSPIF_ADDRESS(phy_address) || IS_QSPIF_CACHED_ADDRESS(phy_address) || + IS_OTP_ADDRESS(phy_address) || IS_OTP_P_ADDRESS(phy_address)) { + LOG_ERR("Invalid destination location."); + return false; + } + + *dst = phy_address; + + return true; +} + +static bool dma_channel_src_addr_check_and_adjust(uint32_t channel, uint32_t *src) +{ + uint32_t phy_address; + uint32_t secure_boot_reg; + bool is_aes_keys_protected, is_qspic_keys_protected; + + /* DMA can only access physical addresses, not remapped. */ + phy_address = black_orca_phy_addr(*src); + + if (IS_QSPIF_CACHED_ADDRESS(phy_address)) { + /* + * To achiebe max. perfomance, peripherals should not access the Flash memory + * through the instruction cache controller (avoid cache misses). + */ + phy_address += (MCU_QSPIF_M_BASE - MCU_QSPIF_M_CACHED_BASE); + } else if (IS_OTP_ADDRESS(phy_address)) { + /* Peripherals should access OTP through its peripheral address space. */ + phy_address += (MCU_OTP_M_P_BASE - MCU_OTP_M_BASE); + } + + secure_boot_reg = CRG_TOP->SECURE_BOOT_REG; + is_aes_keys_protected = + (secure_boot_reg & CRG_TOP_SECURE_BOOT_REG_PROT_AES_KEY_READ_Msk); + is_qspic_keys_protected = + (secure_boot_reg & CRG_TOP_SECURE_BOOT_REG_PROT_QSPI_KEY_READ_Msk); + + /* + * If the source address reflects protected area in OTP then only the + * secure channel #7 can be used to fetch secure keys data. + */ + if (((IS_ADDRESS_USER_DATA_KEYS_SEGMENT(phy_address) && is_aes_keys_protected) || + (IS_ADDRESS_QSPI_FW_KEYS_SEGMENT(phy_address) && is_qspic_keys_protected)) && + (channel != DMA_SECURE_CHANNEL)) { + LOG_ERR("Keys are protected. Only secure channel #7 can be employed."); + return false; + } + + *src = phy_address; + + return true; +} + +static bool dma_channel_update_dreq_mode(enum dma_channel_direction direction, + uint32_t *dma_ctrl_reg) +{ + switch (direction) { + case MEMORY_TO_HOST: + case HOST_TO_MEMORY: + case MEMORY_TO_MEMORY: + /* DMA channel starts immediately */ + DMA_CTRL_REG_SET_FIELD(DREQ_MODE, *dma_ctrl_reg, DREQ_MODE_SW); + break; + case PERIPHERAL_TO_MEMORY: + case PERIPHERAL_TO_PERIPHERAL: + /* DMA channels starts by peripheral DMA req */ + DMA_CTRL_REG_SET_FIELD(DREQ_MODE, *dma_ctrl_reg, DREQ_MODE_HW); + break; + default: + return false; + }; + + return true; +} + +static bool dma_channel_update_src_addr_adj(enum dma_addr_adj addr_adj, uint32_t *dma_ctrl_reg) +{ + switch (addr_adj) { + case DMA_ADDR_ADJ_NO_CHANGE: + DMA_CTRL_REG_SET_FIELD(AINC, *dma_ctrl_reg, ADDR_ADJ_NO_CHANGE); + break; + case DMA_ADDR_ADJ_INCREMENT: + DMA_CTRL_REG_SET_FIELD(AINC, *dma_ctrl_reg, ADDR_ADJ_INCR); + break; + default: + return false; + } + + return true; +} + +static bool dma_channel_update_dst_addr_adj(enum dma_addr_adj addr_adj, uint32_t *dma_ctrl_reg) +{ + switch (addr_adj) { + case DMA_ADDR_ADJ_NO_CHANGE: + DMA_CTRL_REG_SET_FIELD(BINC, *dma_ctrl_reg, ADDR_ADJ_NO_CHANGE); + break; + case DMA_ADDR_ADJ_INCREMENT: + DMA_CTRL_REG_SET_FIELD(BINC, *dma_ctrl_reg, ADDR_ADJ_INCR); + break; + default: + return false; + } + + return true; +} + +static bool dma_channel_update_bus_width(uint16_t bw, uint32_t *dma_ctrl_reg) +{ + switch (bw) { + case DMA_SMARTBOND_BUS_WIDTH_1B: + DMA_CTRL_REG_SET_FIELD(BW, *dma_ctrl_reg, BUS_WIDTH_1B); + break; + case DMA_SMARTBOND_BUS_WIDTH_2B: + DMA_CTRL_REG_SET_FIELD(BW, *dma_ctrl_reg, BUS_WIDTH_2B); + break; + case DMA_SMARTBOND_BUS_WIDTH_4B: + DMA_CTRL_REG_SET_FIELD(BW, *dma_ctrl_reg, BUS_WIDTH_4B); + break; + default: + return false; + } + + return true; +} + +static bool dma_channel_update_burst_mode(uint16_t burst, uint32_t *dma_ctrl_reg) +{ + switch (burst) { + case DMA_SMARTBOND_BURST_LEN_1B: + DMA_CTRL_REG_SET_FIELD(BURST_MODE, *dma_ctrl_reg, BURST_MODE_0B); + break; + case DMA_SMARTBOND_BURST_LEN_4B: + DMA_CTRL_REG_SET_FIELD(BURST_MODE, *dma_ctrl_reg, BURST_MODE_4B); + break; + case DMA_SMARTBOND_BURST_LEN_8B: + DMA_CTRL_REG_SET_FIELD(BURST_MODE, *dma_ctrl_reg, BURST_MODE_8B); + break; + default: + return false; + } + + return true; +} + +static void dma_channel_update_req_sense(enum dma_smartbond_trig_mux trig_mux, + uint32_t channel, uint32_t *dma_ctrl_reg) +{ + switch (trig_mux) { + case DMA_SMARTBOND_TRIG_MUX_UART: + case DMA_SMARTBOND_TRIG_MUX_UART2: + case DMA_SMARTBOND_TRIG_MUX_UART3: + case DMA_SMARTBOND_TRIG_MUX_I2C: + case DMA_SMARTBOND_TRIG_MUX_I2C2: + case DMA_SMARTBOND_TRIG_MUX_USB: + /* Odd channel numbers should reflect TX path */ + if (channel & BIT(0)) { + DMA_CTRL_REG_SET_FIELD(REQ_SENSE, *dma_ctrl_reg, REQ_SENSE_EDGE); + break; + } + default: + DMA_CTRL_REG_SET_FIELD(REQ_SENSE, *dma_ctrl_reg, REQ_SENSE_LEVEL); + } +} + +static void dma_set_mux_request(enum dma_smartbond_trig_mux trig_mux, uint32_t channel) +{ + unsigned int key; + + key = irq_lock(); + DMA_REQ_MUX_REG_SET(channel, trig_mux); + + /* + * Having same trigger for different channels can cause unpredictable results. + * The audio triggers (src and pcm) are an exception, as they use 2 pairs each + * for DMA access. + * The lesser significant selector has higher priority and will control + * the DMA acknowledge signal driven to the selected peripheral. Make sure + * the current selector does not match with selectors of + * higher priorities (dma channels of lower indexing). It's OK if a + * channel of higher indexing defines the same peripheral request source + * (should be ignored as it has lower priority). + */ + if (trig_mux != DMA_SMARTBOND_TRIG_MUX_NONE) { + switch (channel) { + case DMA_SMARTBOND_CHANNEL_7: + case DMA_SMARTBOND_CHANNEL_6: + if (DMA_REQ_MUX_REG_GET(DMA_SMARTBOND_CHANNEL_5) == trig_mux) { + DMA_REQ_MUX_REG_SET(DMA_SMARTBOND_CHANNEL_5, + DMA_SMARTBOND_TRIG_MUX_NONE); + } + /* fall-through */ + case DMA_SMARTBOND_CHANNEL_5: + case DMA_SMARTBOND_CHANNEL_4: + if (DMA_REQ_MUX_REG_GET(DMA_SMARTBOND_CHANNEL_3) == trig_mux) { + DMA_REQ_MUX_REG_SET(DMA_SMARTBOND_CHANNEL_3, + DMA_SMARTBOND_TRIG_MUX_NONE); + } + /* fall-through */ + case DMA_SMARTBOND_CHANNEL_3: + case DMA_SMARTBOND_CHANNEL_2: + if (DMA_REQ_MUX_REG_GET(DMA_SMARTBOND_CHANNEL_1) == trig_mux) { + DMA_REQ_MUX_REG_SET(DMA_SMARTBOND_CHANNEL_1, + DMA_SMARTBOND_TRIG_MUX_NONE); + } + case DMA_SMARTBOND_CHANNEL_1: + case DMA_SMARTBOND_CHANNEL_0: + break; + } + } + + irq_unlock(key); +} + +static int dma_smartbond_config(const struct device *dev, uint32_t channel, struct dma_config *cfg) +{ + struct dma_smartbond_data *data = dev->data; + struct channel_regs *regs; + uint32_t dma_ctrl_reg; + uint32_t src_dst_address; + + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + regs = DMA_CHN2REG(channel); + + dma_ctrl_reg = regs->DMA_CTRL_REG; + + if (DMA_CTRL_REG_GET_FIELD(DMA_ON, dma_ctrl_reg)) { + LOG_ERR("Requested channel is enabled. It should first be disabled"); + return -EIO; + } + + if (cfg == NULL || cfg->head_block == NULL) { + LOG_ERR("Missing configuration structure"); + return -EINVAL; + } + + /* Error handling is not supported; just warn user. */ + if (cfg->error_callback_en) { + LOG_WRN("Error handling is not supported"); + } + + if (!cfg->complete_callback_en) { + data->channel_data[channel].cb = cfg->dma_callback; + data->channel_data[channel].user_data = cfg->user_data; + } else { + LOG_WRN("User callback can only be called at completion only and not per block."); + + /* Nulify pointers to indicate notifications are disabled. */ + data->channel_data[channel].cb = NULL; + data->channel_data[channel].user_data = NULL; + } + + data->channel_data[channel].dir = cfg->channel_direction; + + if (cfg->block_count > DMA_BLOCK_COUNT) { + LOG_WRN("A single block is supported. The rest blocks will be discarded"); + } + + if (cfg->channel_priority >= DMA_SMARTBOND_CHANNEL_PRIO_MAX) { + cfg->channel_priority = DMA_SMARTBOND_CHANNEL_PRIO_7; + LOG_WRN("Channel priority exceeded max. Setting to highest valid level"); + } + + DMA_CTRL_REG_SET_FIELD(DMA_PRIO, dma_ctrl_reg, cfg->channel_priority); + + if (((cfg->source_burst_length != cfg->dest_burst_length) || + !dma_channel_update_burst_mode(cfg->source_burst_length, &dma_ctrl_reg))) { + LOG_ERR("Invalid burst mode or source and destination mode mismatch"); + return -EINVAL; + } + + data->channel_data[channel].burst_len = cfg->source_burst_length; + + if (cfg->source_data_size != cfg->dest_data_size || + !dma_channel_update_bus_width(cfg->source_data_size, &dma_ctrl_reg)) { + LOG_ERR("Invalid bus width or source and destination bus width mismatch"); + return -EINVAL; + } + + data->channel_data[channel].bus_width = cfg->source_data_size; + + if (cfg->source_chaining_en || cfg->dest_chaining_en || + cfg->head_block->source_gather_en || cfg->head_block->dest_scatter_en || + cfg->head_block->source_reload_en || cfg->head_block->dest_reload_en) { + LOG_WRN("Chainning, scattering, gathering or reloading is not supported"); + } + + if (!dma_channel_update_src_addr_adj(cfg->head_block->source_addr_adj, + &dma_ctrl_reg)) { + LOG_ERR("Invalid source address adjustment"); + return -EINVAL; + } + + if (!dma_channel_update_dst_addr_adj(cfg->head_block->dest_addr_adj, &dma_ctrl_reg)) { + LOG_ERR("Invalid destination address adjustment"); + return -EINVAL; + } + + if (!dma_channel_update_dreq_mode(cfg->channel_direction, &dma_ctrl_reg)) { + LOG_ERR("Inavlid channel direction"); + return -EINVAL; + } + + /* Cyclic is valid only when DREQ_MODE is set */ + if (cfg->cyclic && DMA_CTRL_REG_GET_FIELD(DREQ_MODE, dma_ctrl_reg) != DREQ_MODE_HW) { + LOG_ERR("Circular mode is only supported for non memory-memory transfers"); + return -EINVAL; + } + + DMA_CTRL_REG_SET_FIELD(CIRCULAR, dma_ctrl_reg, cfg->cyclic); + + if (DMA_CTRL_REG_GET_FIELD(DREQ_MODE, dma_ctrl_reg) == DREQ_MODE_SW && + DMA_CTRL_REG_GET_FIELD(AINC, dma_ctrl_reg) == ADDR_ADJ_NO_CHANGE && + DMA_CTRL_REG_GET_FIELD(BINC, dma_ctrl_reg) == ADDR_ADJ_INCR) { + /* + * Valid for memory initialization to a specific value. This process + * cannot be interrupted by other DMA channels. + */ + DMA_CTRL_REG_SET_FIELD(DMA_INIT, dma_ctrl_reg, COPY_MODE_INIT); + } else { + DMA_CTRL_REG_SET_FIELD(DMA_INIT, dma_ctrl_reg, COPY_MODE_BLOCK); + } + + dma_channel_update_req_sense(cfg->dma_slot, channel, &dma_ctrl_reg); + + regs->DMA_CTRL_REG = dma_ctrl_reg; + + /* Requested address might be changed */ + src_dst_address = cfg->head_block->source_address; + if (!dma_channel_src_addr_check_and_adjust(channel, &src_dst_address)) { + return -EINVAL; + } + + if (src_dst_address % cfg->source_data_size) { + LOG_ERR("Source address is not bus width aligned"); + return -EINVAL; + } + + regs->DMA_A_START = src_dst_address; + + src_dst_address = cfg->head_block->dest_address; + if (!dma_channel_dst_addr_check_and_adjust(channel, &src_dst_address)) { + return -EINVAL; + } + + if (src_dst_address % cfg->dest_data_size) { + LOG_ERR("Destination address is not bus width aligned"); + return -EINVAL; + } + + regs->DMA_B_START = src_dst_address; + + if (cfg->head_block->block_size % (cfg->source_data_size * cfg->source_burst_length)) { + LOG_ERR("Requested data size is not multiple of bus width"); + return -EINVAL; + } + + regs->DMA_LEN_REG = (cfg->head_block->block_size / cfg->source_data_size) - 1; + + /* Interrupt will be raised once all transfers are complete. */ + regs->DMA_INT_REG = (cfg->head_block->block_size / cfg->source_data_size) - 1; + + if ((cfg->source_handshake != cfg->dest_handshake) || + (cfg->source_handshake != 0)/*HW*/) { + LOG_ERR("Source/destination handshakes mismatch or invalid"); + return -EINVAL; + } + + dma_set_mux_request(cfg->dma_slot, channel); + + /* Designate that channel has been configured */ + data->channel_data[channel].is_dma_configured = true; + + return 0; +} + + +static int dma_smartbond_reload(const struct device *dev, uint32_t channel, uint32_t src, + uint32_t dst, size_t size) +{ + struct dma_smartbond_data *data = dev->data; + struct channel_regs *regs; + + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + regs = DMA_CHN2REG(channel); + + if (!data->channel_data[channel].is_dma_configured) { + LOG_ERR("Requested DMA channel should first be configured"); + return -EINVAL; + } + + if (size == 0) { + LOG_ERR("Min. transfer size is one"); + return -EINVAL; + } + + if (DMA_CTRL_REG_GET_FIELD(DMA_ON, regs->DMA_CTRL_REG)) { + LOG_ERR("Channel is busy, settings cannot be changed mid-transfer"); + return -EBUSY; + } + + if (src % data->channel_data[channel].bus_width) { + LOG_ERR("Source address is not bus width aligned"); + return -EINVAL; + } + + if (!dma_channel_src_addr_check_and_adjust(channel, &src)) { + return -EINVAL; + } + + regs->DMA_A_START = src; + + if (dst % data->channel_data[channel].bus_width) { + LOG_ERR("Destination address is not bus width aligned"); + return -EINVAL; + } + + if (!dma_channel_dst_addr_check_and_adjust(channel, &dst)) { + return -EINVAL; + } + + regs->DMA_B_START = dst; + + if (size % (data->channel_data[channel].burst_len * + data->channel_data[channel].bus_width)) { + LOG_ERR("Requested data size is not multiple of bus width"); + return -EINVAL; + } + + regs->DMA_LEN_REG = (size / data->channel_data[channel].bus_width) - 1; + + /* Interrupt will be raised once all transfers are complete. */ + regs->DMA_INT_REG = (size / data->channel_data[channel].bus_width) - 1; + + return 0; +} + +static int dma_smartbond_start(const struct device *dev, uint32_t channel) +{ + struct channel_regs *regs; + struct dma_smartbond_data *data = dev->data; + + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + regs = DMA_CHN2REG(channel); + + if (!data->channel_data[channel].is_dma_configured) { + LOG_ERR("Requested DMA channel should first be configured"); + return -EINVAL; + } + + /* Should return succss if the requested channel is already started. */ + if (DMA_CTRL_REG_GET_FIELD(DMA_ON, regs->DMA_CTRL_REG)) { + return 0; + } + + dma_smartbond_set_channel_status(channel, true); + + return 0; +} + +static int dma_smartbond_stop(const struct device *dev, uint32_t channel) +{ + struct channel_regs *regs; + + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + regs = DMA_CHN2REG(channel); + + /* + * In normal mode DMA_ON is cleared automatically. However we need to clear + * the corresponding register mask and disable NVIC if there is no other + * channel in use. + */ + dma_smartbond_set_channel_status(channel, false); + + return 0; +} + +static int dma_smartbond_suspend(const struct device *dev, uint32_t channel) +{ + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + + /* + * Freezing the DMA engine is valid for memory-to-memory operations. + * Valid memory locations are SYSRAM and/or PSRAM. + */ + LOG_WRN("DMA is freezed globally"); + + /* + * Freezing the DMA engine can be done universally and not per channel!. + * An attempt to disable the channel would result in resetting the IDX + * register next time the channel was re-enabled. + */ + GPREG->SET_FREEZE_REG = GPREG_SET_FREEZE_REG_FRZ_DMA_Msk; + + return 0; +} + +static int dma_smartbond_resume(const struct device *dev, uint32_t channel) +{ + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + + LOG_WRN("DMA is unfreezed globally"); + + /* Unfreezing the DMA engine can be done unviversally and not per channel! */ + GPREG->RESET_FREEZE_REG = GPREG_RESET_FREEZE_REG_FRZ_DMA_Msk; + + return 0; +} + +static int dma_smartbond_get_status(const struct device *dev, uint32_t channel, + struct dma_status *stat) +{ + struct channel_regs *regs; + int key; + struct dma_smartbond_data *data = dev->data; + uint8_t bus_width; + uint32_t dma_ctrl_reg, dma_idx_reg, dma_len_reg; + + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + + if (stat == NULL) { + LOG_ERR("User should provide a valid pointer to store the status info requested"); + } + + if (!data->channel_data[channel].is_dma_configured) { + LOG_ERR("Requested DMA channel should first be configured"); + return -EINVAL; + } + + regs = DMA_CHN2REG(channel); + + /* + * The DMA is running in parallel with CPU and so it might happen that an on-going transfer + * might be completed the moment user parses the status results. Disable interrupts globally + * so there is no chance for a new transfer to be initiated from within ISR and so changing + * the channel registers values. + */ + key = irq_lock(); + + dma_ctrl_reg = regs->DMA_CTRL_REG; + dma_idx_reg = regs->DMA_IDX_REG; + dma_len_reg = regs->DMA_LEN_REG; + + /* Calculate how many byes each transfer consists of. */ + bus_width = DMA_CTRL_REG_GET_FIELD(BW, dma_ctrl_reg); + if (bus_width == BUS_WIDTH_1B) { + bus_width = 1; + } else { + bus_width <<= 1; + } + + /* Convert transfers to bytes. */ + stat->total_copied = dma_idx_reg * bus_width; + stat->pending_length = ((dma_len_reg + 1) - dma_idx_reg) * bus_width; + stat->busy = DMA_CTRL_REG_GET_FIELD(DMA_ON, dma_ctrl_reg); + stat->dir = data->channel_data[channel].dir; + + /* DMA does not support circular buffer functionality */ + stat->free = 0; + stat->read_position = 0; + stat->write_position = 0; + + irq_unlock(key); + + return 0; +} + +static int dma_smartbond_get_attribute(const struct device *dev, uint32_t type, uint32_t *value) +{ + if (value == NULL) { + LOG_ERR("User should provide a valid pointer to attribute value"); + return -EINVAL; + } + + switch (type) { + /* + * Source and destination addresses should be multiple of a channel's bus width. + * This info could be provided at runtime given that attributes of a specific + * channel could be requested. + */ + case DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT: + case DMA_ATTR_COPY_ALIGNMENT: + /* + * Buffer size should be multiple of a channel's bus width multiplied by burst length. + * This info could be provided at runtime given that attributes of a specific channel + * could be requested. + */ + case DMA_ATTR_BUFFER_SIZE_ALIGNMENT: + return -ENOSYS; + case DMA_ATTR_MAX_BLOCK_COUNT: + *value = DMA_BLOCK_COUNT; + return 0; + default: + return -EINVAL; + } +} + +static bool dma_smartbond_chan_filter(const struct device *dev, int channel, void *filter_param) +{ + uint32_t requested_channel; + + if (channel >= DMA_CHANNELS_COUNT) { + LOG_ERR("Inavlid DMA channel index"); + return -EINVAL; + } + + /* If user does not provide any channel request explicitly, return true. */ + if (filter_param == NULL) { + return true; + } + + requested_channel = *(uint32_t *)filter_param; + + if (channel == requested_channel) { + return true; + } + + return false; +} + +static struct dma_driver_api dma_smartbond_driver_api = { + .config = dma_smartbond_config, + .reload = dma_smartbond_reload, + .start = dma_smartbond_start, + .stop = dma_smartbond_stop, + .suspend = dma_smartbond_suspend, + .resume = dma_smartbond_resume, + .get_status = dma_smartbond_get_status, + .get_attribute = dma_smartbond_get_attribute, + .chan_filter = dma_smartbond_chan_filter +}; + +static void smartbond_dma_isr(const void *arg) +{ + uint16_t dma_int_status_reg; + int i; + struct channel_regs *regs; + struct dma_smartbond_data *data = ((const struct device *)arg)->data; + + /* + * A single interrupt line is generated for all channels and so each channel + * should be parsed separately. + */ + for (i = 0, dma_int_status_reg = DMA->DMA_INT_STATUS_REG; + i < DMA_CHANNELS_COUNT && dma_int_status_reg != 0; ++i, dma_int_status_reg >>= 1) { + /* Check if the selected channel has raised the interrupt line */ + if (dma_int_status_reg & BIT(0)) { + + regs = DMA_CHN2REG(i); + /* + * Should be valid if callbacks are explicitly enabled by users. + * Interrupt should be triggered only when the total size of + * bytes has been transferred. Bus errors cannot raise interrupts. + */ + if (data->channel_data[i].cb) { + data->channel_data[i].cb((const struct device *)arg, + data->channel_data[i].user_data, i, DMA_STATUS_COMPLETE); + } + /* Channel line should be cleared otherwise ISR will keep firing! */ + DMA->DMA_CLEAR_INT_REG = BIT(i); + } + } +} + +static int dma_smartbond_init(const struct device *dev) +{ +#ifdef CONFIG_DMA_64BIT + LOG_ERR("64-bit addressing mode is not supported\n"); + return -ENOSYS; +#endif + + int idx; + struct dma_smartbond_data *data; + + data = dev->data; + data->dma_ctx.magic = DMA_MAGIC; + data->dma_ctx.dma_channels = DMA_CHANNELS_COUNT; + data->dma_ctx.atomic = data->channels_atomic; + + /* Make sure that all channels are disabled. */ + for (idx = 0; idx < DMA_CHANNELS_COUNT; idx++) { + dma_smartbond_set_channel_status(idx, false); + data->channel_data[idx].is_dma_configured = false; + } + + IRQ_CONNECT(SMARTBOND_IRQN, SMARTBOND_IRQ_PRIO, smartbond_dma_isr, + DEVICE_DT_INST_GET(0), 0); + + return 0; +} + +#define SMARTBOND_DMA_INIT(inst) \ + BUILD_ASSERT((inst) == 0, "multiple instances are not supported"); \ + \ + static struct dma_smartbond_data dma_smartbond_data_ ## inst; \ + \ + DEVICE_DT_INST_DEFINE(0, dma_smartbond_init, NULL, \ + &dma_smartbond_data_ ## inst, NULL, \ + POST_KERNEL, \ + CONFIG_DMA_INIT_PRIORITY, \ + &dma_smartbond_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(SMARTBOND_DMA_INIT) diff --git a/drivers/dma/dma_stm32.c b/drivers/dma/dma_stm32.c index 64c3b21f5ae5c23..178d83665b4ca29 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 9e88b7dfc2db702..f21cb07e1834c12 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/edac/Kconfig b/drivers/edac/Kconfig index 45e499a749a6217..e5029ce470f889e 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -19,7 +19,6 @@ config EDAC_ERROR_INJECT config EDAC_SHELL bool "EDAC Shell" depends on SHELL - default y if SHELL help Enable EDAC shell for debugging EDAC. diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig index 745d274ff1e3a97..29405f4ed65fb0a 100644 --- a/drivers/eeprom/Kconfig +++ b/drivers/eeprom/Kconfig @@ -24,7 +24,6 @@ config EEPROM_INIT_PRIORITY config EEPROM_SHELL bool "EEPROM shell" - default y depends on SHELL help Enable the EEPROM shell with EEPROM related commands. diff --git a/drivers/eeprom/eeprom_emulator.c b/drivers/eeprom/eeprom_emulator.c index 822c9a7e2cf488f..0672e83f839f0e9 100644 --- a/drivers/eeprom/eeprom_emulator.c +++ b/drivers/eeprom/eeprom_emulator.c @@ -642,7 +642,7 @@ static int eeprom_emu_init(const struct device *dev) struct eeprom_emu_data *dev_data = dev->data; off_t offset; uint8_t buf[dev_config->flash_cbs]; - int rc; + int rc = 0; k_mutex_init(&dev_data->lock); if (!device_is_ready(dev_config->flash_dev)) { diff --git a/drivers/eeprom/eeprom_fake.c b/drivers/eeprom/eeprom_fake.c index c7ed9ff5cd4e730..f925671fba8ad8b 100644 --- a/drivers/eeprom/eeprom_fake.c +++ b/drivers/eeprom/eeprom_fake.c @@ -9,9 +9,9 @@ #include #include -#ifdef CONFIG_ZTEST_NEW_API +#ifdef CONFIG_ZTEST #include -#endif /* CONFIG_ZTEST_NEW_API */ +#endif /* CONFIG_ZTEST */ #define DT_DRV_COMPAT zephyr_fake_eeprom @@ -32,7 +32,7 @@ size_t fake_eeprom_size_delegate(const struct device *dev) return config->size; } -#ifdef CONFIG_ZTEST_NEW_API +#ifdef CONFIG_ZTEST static void fake_eeprom_reset_rule_before(const struct ztest_unit_test *test, void *fixture) { ARG_UNUSED(test); @@ -47,7 +47,7 @@ static void fake_eeprom_reset_rule_before(const struct ztest_unit_test *test, vo } ZTEST_RULE(fake_eeprom_reset_rule, fake_eeprom_reset_rule_before, NULL); -#endif /* CONFIG_ZTEST_NEW_API */ +#endif /* CONFIG_ZTEST */ static const struct eeprom_driver_api fake_eeprom_driver_api = { .read = fake_eeprom_read, diff --git a/drivers/eeprom/eeprom_handlers.c b/drivers/eeprom/eeprom_handlers.c index 79e00d3a6fd60f1..9b1406a60043a69 100644 --- a/drivers/eeprom/eeprom_handlers.c +++ b/drivers/eeprom/eeprom_handlers.c @@ -4,14 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include static inline int z_vrfy_eeprom_read(const struct device *dev, off_t offset, void *data, size_t len) { - Z_OOPS(Z_SYSCALL_DRIVER_EEPROM(dev, read)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(data, len)); + K_OOPS(K_SYSCALL_DRIVER_EEPROM(dev, read)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(data, len)); return z_impl_eeprom_read((const struct device *)dev, offset, (void *)data, len); @@ -21,8 +21,8 @@ static inline int z_vrfy_eeprom_read(const struct device *dev, off_t offset, static inline int z_vrfy_eeprom_write(const struct device *dev, off_t offset, const void *data, size_t len) { - Z_OOPS(Z_SYSCALL_DRIVER_EEPROM(dev, write)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(data, len)); + K_OOPS(K_SYSCALL_DRIVER_EEPROM(dev, write)); + K_OOPS(K_SYSCALL_MEMORY_READ(data, len)); return z_impl_eeprom_write((const struct device *)dev, offset, (const void *)data, len); } @@ -30,7 +30,7 @@ static inline int z_vrfy_eeprom_write(const struct device *dev, off_t offset, static inline size_t z_vrfy_eeprom_get_size(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_EEPROM(dev, size)); + K_OOPS(K_SYSCALL_DRIVER_EEPROM(dev, size)); return z_impl_eeprom_get_size((const struct device *)dev); } #include diff --git a/drivers/eeprom/eeprom_mchp_xec.c b/drivers/eeprom/eeprom_mchp_xec.c index bd1c83e4c74d7a4..171940a008d4fbf 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 2e8d0ca66505ab4..19efa5b3d9dcd77 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 99184f3b1e5acd8..11e361517c25128 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/Kconfig.psa_crypto b/drivers/entropy/Kconfig.psa_crypto index 50f31509004072b..d06001225b05491 100644 --- a/drivers/entropy/Kconfig.psa_crypto +++ b/drivers/entropy/Kconfig.psa_crypto @@ -5,7 +5,6 @@ config ENTROPY_PSA_CRYPTO_RNG bool "PSA Crypto Random source Entropy driver" - depends on BUILD_WITH_TFM depends on DT_HAS_ZEPHYR_PSA_CRYPTO_RNG_ENABLED select ENTROPY_HAS_DRIVER default y diff --git a/drivers/entropy/entropy_esp32.c b/drivers/entropy/entropy_esp32.c index 359c67dda775e1e..4a15f640ce98ea8 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_handlers.c b/drivers/entropy/entropy_handlers.c index 7eb4dcba0c434c4..76b7df3d0bd705b 100644 --- a/drivers/entropy/entropy_handlers.c +++ b/drivers/entropy/entropy_handlers.c @@ -5,14 +5,14 @@ */ #include -#include +#include static inline int z_vrfy_entropy_get_entropy(const struct device *dev, uint8_t *buffer, uint16_t len) { - Z_OOPS(Z_SYSCALL_DRIVER_ENTROPY(dev, get_entropy)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(buffer, len)); + K_OOPS(K_SYSCALL_DRIVER_ENTROPY(dev, get_entropy)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(buffer, len)); return z_impl_entropy_get_entropy((const struct device *)dev, (uint8_t *)buffer, len); diff --git a/drivers/entropy/entropy_stm32.c b/drivers/entropy/entropy_stm32.c index 3dd8f82e8a5bb6f..9d0e0eb6c48767d 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 */ @@ -235,6 +289,8 @@ static int random_byte_get(void) unsigned int key; RNG_TypeDef *rng = entropy_stm32_rng_data.rng; + key = irq_lock(); + if (IS_ENABLED(CONFIG_ENTROPY_STM32_CLK_CHECK) && !k_is_pre_kernel()) { /* CECS bit signals that a clock configuration issue is detected, * which may lead to generation of non truly random data. @@ -244,8 +300,6 @@ static int random_byte_get(void) "\tSee ref man and update target clock configuration."); } - key = irq_lock(); - if (LL_RNG_IsActiveFlag_SEIS(rng) && (recover_seed_error(rng) < 0)) { retval = -EIO; goto out; @@ -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 000000000000000..f456b978d99c9da --- /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 000000000000000..3fedffc0aac7816 --- /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 33658155595285e..ccdd3aa46e543e7 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 77455ebda016fb8..5379d00ea210653 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 3b1ac7c436ff667..e018f8695157148 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 1da4f661217e33b..3f1d511caa1913c 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 @@ -80,4 +112,10 @@ config ESPI_PERIPHERAL_ACPI_SHM_REGION config ESPI_PERIPHERAL_CUSTOM_OPCODE default y +config ESPI_NPCX_SUPP_VW_GPIO + bool "Indicates that the eSPI hardware supports virtual wire GPIOs" + default y if SOC_SERIES_NPCX9 || SOC_SERIES_NPCX4 + help + Selected if NPCX series supports virtual wire GPIOs in eSPI module. + endif #ESPI_NPCX diff --git a/drivers/espi/espi_handlers.c b/drivers/espi/espi_handlers.c index d6800fe0f6ea028..c215838fd7951f5 100644 --- a/drivers/espi/espi_handlers.c +++ b/drivers/espi/espi_handlers.c @@ -5,7 +5,7 @@ */ #include -#include +#include static inline int z_vrfy_espi_config(const struct device *dev, @@ -13,8 +13,8 @@ static inline int z_vrfy_espi_config(const struct device *dev, { struct espi_cfg cfg_copy; - Z_OOPS(Z_SYSCALL_DRIVER_ESPI(dev, config)); - Z_OOPS(z_user_from_copy(&cfg_copy, cfg, + K_OOPS(K_SYSCALL_DRIVER_ESPI(dev, config)); + K_OOPS(k_usermode_from_copy(&cfg_copy, cfg, sizeof(struct espi_cfg))); return z_impl_espi_config(dev, &cfg_copy); @@ -24,7 +24,7 @@ static inline int z_vrfy_espi_config(const struct device *dev, static inline bool z_vrfy_espi_get_channel_status(const struct device *dev, enum espi_channel ch) { - Z_OOPS(Z_SYSCALL_DRIVER_ESPI(dev, get_channel_status)); + K_OOPS(K_SYSCALL_DRIVER_ESPI(dev, get_channel_status)); return z_impl_espi_get_channel_status(dev, ch); } @@ -37,10 +37,10 @@ static inline int z_vrfy_espi_read_lpc_request(const struct device *dev, int ret; uint32_t data_copy; - Z_OOPS(Z_SYSCALL_DRIVER_ESPI(dev, read_lpc_request)); + K_OOPS(K_SYSCALL_DRIVER_ESPI(dev, read_lpc_request)); ret = z_impl_espi_read_lpc_request(dev, op, &data_copy); - Z_OOPS(z_user_to_copy(data, &data_copy, sizeof(uint8_t))); + K_OOPS(k_usermode_to_copy(data, &data_copy, sizeof(uint8_t))); return ret; } @@ -52,8 +52,8 @@ static inline int z_vrfy_espi_write_lpc_request(const struct device *dev, { uint32_t data_copy; - Z_OOPS(Z_SYSCALL_DRIVER_ESPI(dev, write_lpc_request)); - Z_OOPS(z_user_from_copy(&data_copy, data, sizeof(*data))); + K_OOPS(K_SYSCALL_DRIVER_ESPI(dev, write_lpc_request)); + K_OOPS(k_usermode_from_copy(&data_copy, data, sizeof(*data))); return z_impl_espi_write_lpc_request(dev, op, &data_copy); } @@ -63,7 +63,7 @@ static inline int z_vrfy_espi_send_vwire(const struct device *dev, enum espi_vwire_signal signal, uint8_t level) { - Z_OOPS(Z_SYSCALL_DRIVER_ESPI(dev, send_vwire)); + K_OOPS(K_SYSCALL_DRIVER_ESPI(dev, send_vwire)); return z_impl_espi_send_vwire(dev, signal, level); } @@ -76,10 +76,10 @@ static inline int z_vrfy_espi_receive_vwire(const struct device *dev, int ret; uint8_t level_copy; - Z_OOPS(Z_SYSCALL_DRIVER_ESPI(dev, receive_vwire)); + K_OOPS(K_SYSCALL_DRIVER_ESPI(dev, receive_vwire)); ret = z_impl_espi_receive_vwire(dev, signal, &level_copy); - Z_OOPS(z_user_to_copy(level, &level_copy, sizeof(uint8_t))); + K_OOPS(k_usermode_to_copy(level, &level_copy, sizeof(uint8_t))); return ret; } @@ -91,14 +91,14 @@ static inline int z_vrfy_espi_read_request(const struct device *dev, int ret; struct espi_request_packet req_copy; - Z_OOPS(Z_SYSCALL_DRIVER_ESPI(dev, read_request)); - Z_OOPS(z_user_from_copy(&req_copy, req, + K_OOPS(K_SYSCALL_DRIVER_ESPI(dev, read_request)); + K_OOPS(k_usermode_from_copy(&req_copy, req, sizeof(struct espi_request_packet))); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(req_copy.data, req_copy.len)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(req_copy.data, req_copy.len)); ret = z_impl_espi_read_request(dev, &req_copy); - Z_OOPS(z_user_to_copy(req, &req_copy, + K_OOPS(k_usermode_to_copy(req, &req_copy, sizeof(struct espi_request_packet))); return ret; @@ -111,9 +111,9 @@ static inline int z_vrfy_espi_write_request(const struct device *dev, int ret; struct espi_request_packet req_copy; - Z_OOPS(Z_SYSCALL_DRIVER_ESPI(dev, write_request)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(req->data, req->len)); - Z_OOPS(z_user_from_copy(&req_copy, req, + K_OOPS(K_SYSCALL_DRIVER_ESPI(dev, write_request)); + K_OOPS(K_SYSCALL_MEMORY_READ(req->data, req->len)); + K_OOPS(k_usermode_from_copy(&req_copy, req, sizeof(struct espi_request_packet))); ret = z_impl_espi_write_request(dev, &req_copy); @@ -128,9 +128,9 @@ static inline int z_vrfy_espi_send_oob(const struct device *dev, int ret; struct espi_oob_packet pckt_copy; - Z_OOPS(Z_SYSCALL_DRIVER_ESPI(dev, send_oob)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(pckt->buf, pckt->len)); - Z_OOPS(z_user_from_copy(&pckt_copy, pckt, + K_OOPS(K_SYSCALL_DRIVER_ESPI(dev, send_oob)); + K_OOPS(K_SYSCALL_MEMORY_READ(pckt->buf, pckt->len)); + K_OOPS(k_usermode_from_copy(&pckt_copy, pckt, sizeof(struct espi_oob_packet))); ret = z_impl_espi_send_oob(dev, &pckt_copy); @@ -145,13 +145,13 @@ static inline int z_vrfy_espi_receive_oob(const struct device *dev, int ret; struct espi_oob_packet pckt_copy; - Z_OOPS(Z_SYSCALL_DRIVER_ESPI(dev, receive_oob)); - Z_OOPS(z_user_from_copy(&pckt_copy, pckt, + K_OOPS(K_SYSCALL_DRIVER_ESPI(dev, receive_oob)); + K_OOPS(k_usermode_from_copy(&pckt_copy, pckt, sizeof(struct espi_oob_packet))); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(pckt->buf, pckt->len)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(pckt->buf, pckt->len)); ret = z_impl_espi_receive_oob(dev, &pckt_copy); - Z_OOPS(z_user_to_copy(pckt, &pckt_copy, + K_OOPS(k_usermode_to_copy(pckt, &pckt_copy, sizeof(struct espi_oob_packet))); return ret; @@ -164,13 +164,13 @@ static inline int z_vrfy_espi_read_flash(const struct device *dev, int ret; struct espi_flash_packet pckt_copy; - Z_OOPS(Z_SYSCALL_DRIVER_ESPI(dev, flash_read)); - Z_OOPS(z_user_from_copy(&pckt_copy, pckt, + K_OOPS(K_SYSCALL_DRIVER_ESPI(dev, flash_read)); + K_OOPS(k_usermode_from_copy(&pckt_copy, pckt, sizeof(struct espi_flash_packet))); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(pckt->buf, pckt->len)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(pckt->buf, pckt->len)); ret = z_impl_espi_read_flash(dev, pckt); - Z_OOPS(z_user_to_copy(pckt, &pckt_copy, + K_OOPS(k_usermode_to_copy(pckt, &pckt_copy, sizeof(struct espi_flash_packet))); return ret; @@ -183,10 +183,10 @@ static inline int z_vrfy_espi_write_flash(const struct device *dev, int ret; struct espi_flash_packet pckt_copy; - Z_OOPS(Z_SYSCALL_DRIVER_ESPI(dev, flash_write)); - Z_OOPS(z_user_from_copy(&pckt_copy, pckt, + K_OOPS(K_SYSCALL_DRIVER_ESPI(dev, flash_write)); + K_OOPS(k_usermode_from_copy(&pckt_copy, pckt, sizeof(struct espi_flash_packet))); - Z_OOPS(Z_SYSCALL_MEMORY_READ(pckt->buf, pckt->len)); + K_OOPS(K_SYSCALL_MEMORY_READ(pckt->buf, pckt->len)); ret = z_impl_espi_write_flash(dev, &pckt_copy); @@ -200,10 +200,10 @@ static inline int z_vrfy_espi_flash_erase(const struct device *dev, int ret; struct espi_flash_packet pckt_copy; - Z_OOPS(Z_SYSCALL_DRIVER_ESPI(dev, flash_write)); - Z_OOPS(z_user_from_copy(&pckt_copy, pckt, + K_OOPS(K_SYSCALL_DRIVER_ESPI(dev, flash_write)); + K_OOPS(k_usermode_from_copy(&pckt_copy, pckt, sizeof(struct espi_flash_packet))); - Z_OOPS(Z_SYSCALL_MEMORY_READ(pckt->buf, pckt->len)); + K_OOPS(K_SYSCALL_MEMORY_READ(pckt->buf, pckt->len)); ret = z_impl_espi_flash_erase(dev, &pckt_copy); diff --git a/drivers/espi/espi_npcx.c b/drivers/espi/espi_npcx.c index 7d2679407a4de07..6a8a83a13c336ab 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 @@ -164,7 +165,7 @@ static const struct npcx_vw_out_config vw_out_tbl[] = { /* Virtual wire GPIOs for platform level usage (High at Reset state) */ static const struct npcx_vw_out_config vw_out_gpio_tbl1[] = { /* Only NPCX9 and later series support this feature */ -#if !defined(CONFIG_SOC_SERIES_NPCX7) +#if defined(CONFIG_ESPI_NPCX_SUPP_VW_GPIO) /* index 50h (Out) */ NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_SLV_GPIO_0, vw_slv_gpio_0), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_SLV_GPIO_1, vw_slv_gpio_1), @@ -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 000000000000000..722b26730e8cda3 --- /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 6f963cd68d0fb02..def0c5bf186e7f8 100644 --- a/drivers/ethernet/CMakeLists.txt +++ b/drivers/ethernet/CMakeLists.txt @@ -34,6 +34,9 @@ zephyr_library_sources_ifdef(CONFIG_SLIP_TAP eth_slip_tap.c) 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) @@ -42,14 +45,20 @@ if(CONFIG_ETH_NXP_S32_NETC) endif() zephyr_library_sources_ifdef(CONFIG_ETH_NXP_S32_GMAC eth_nxp_s32_gmac.c) +zephyr_library_sources_ifdef(CONFIG_ETH_NUMAKER eth_numaker.c) if(CONFIG_ETH_NATIVE_POSIX) - set(native_posix_source_files eth_native_posix.c eth_native_posix_adapt.c) - set_source_files_properties(${native_posix_source_files} - PROPERTIES COMPILE_DEFINITIONS - "NO_POSIX_CHEATS;_BSD_SOURCE;_DEFAULT_SOURCE" - ) - zephyr_library_sources(${native_posix_source_files}) + if (CONFIG_NATIVE_APPLICATION) + set(native_posix_source_files eth_native_posix.c eth_native_posix_adapt.c) + set_source_files_properties(${native_posix_source_files} + PROPERTIES COMPILE_DEFINITIONS + "NO_POSIX_CHEATS;_BSD_SOURCE;_DEFAULT_SOURCE" + ) + zephyr_library_sources(${native_posix_source_files}) + else() + zephyr_library_sources(eth_native_posix.c) + target_sources(native_simulator INTERFACE eth_native_posix_adapt.c) + endif() endif() add_subdirectory(phy) diff --git a/drivers/ethernet/Kconfig b/drivers/ethernet/Kconfig index 8160fc74358be43..4bc7b8b9599860a 100644 --- a/drivers/ethernet/Kconfig +++ b/drivers/ethernet/Kconfig @@ -61,6 +61,10 @@ source "drivers/ethernet/Kconfig.nxp_s32_gmac" source "drivers/ethernet/Kconfig.smsc91x" 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.dsa b/drivers/ethernet/Kconfig.dsa index 3683a5397590f2b..c6b78f0a46371e9 100644 --- a/drivers/ethernet/Kconfig.dsa +++ b/drivers/ethernet/Kconfig.dsa @@ -6,10 +6,10 @@ menuconfig NET_DSA bool "Distributed Switch Architecture support" - depends on ETH_MCUX || ETH_SAM_GMAC + depends on ETH_MCUX || ETH_SAM_GMAC || ETH_STM32_HAL help Enable Distributed Switch Architecture support. For now it - only supports Kinetics ENET driver. + only supports Kinetics and STM32 ENET drivers. if NET_DSA diff --git a/drivers/ethernet/Kconfig.esp32 b/drivers/ethernet/Kconfig.esp32 index 8adb24cfb7716bb..35c07860f4ef336 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 new file mode 100644 index 000000000000000..42138aa1ed4423e --- /dev/null +++ b/drivers/ethernet/Kconfig.lan865x @@ -0,0 +1,51 @@ +# Copyright (c) 2023 DENX Software Engineering GmbH +# SPDX-License-Identifier: Apache-2.0 + +menuconfig ETH_LAN865X + bool "LAN865X 10BASE-T1S Controller" + 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 + Mbps single pair Ethernet (SPE). + + Featuring an integrated media access control (MAC) and a PHY, + the LAN865X enables direct connectivity with a variety of controllers + via a serial peripheral inter-face (SPI). + +if ETH_LAN865X + +config ETH_LAN865X_INIT_PRIORITY + int "LAN865X driver init priority" + default 72 + help + LAN865X device driver initialization priority. + Must be initialized after SPI. + + +config ETH_LAN865X_IRQ_THREAD_STACK_SIZE + int "Stack size for a thread that processes IRQ" + default 512 + help + Size of the stack used for internal thread which is ran to + process raised INT IRQ. + +config ETH_LAN865X_IRQ_THREAD_PRIO + int "Priority for internal incoming packet handler" + default 2 + help + Priority level for internal thread which is ran for LAN + INT IRQ processing. + +config ETH_LAN865X_TIMEOUT + int "IP buffer timeout" + default 100 + help + Given timeout in milliseconds. Maximum amount of time + that the driver will wait from the IP stack to get + a memory buffer. + +endif # ETH_LAN865X diff --git a/drivers/ethernet/Kconfig.native_posix b/drivers/ethernet/Kconfig.native_posix index 5fc334505401c8c..8ab1033d477b268 100644 --- a/drivers/ethernet/Kconfig.native_posix +++ b/drivers/ethernet/Kconfig.native_posix @@ -5,65 +5,12 @@ menuconfig ETH_NATIVE_POSIX bool "Native Posix Ethernet driver" - depends on ARCH_POSIX && EXTERNAL_LIBC + depends on ARCH_POSIX help Enable native posix ethernet driver. Note, this driver is run inside a process in your host system. if ETH_NATIVE_POSIX -config ETH_NATIVE_POSIX_STARTUP_AUTOMATIC - bool "Start network interface automatically" - help - If set, the native_posix ethernet driver will set up the network - interface, requiring ``zephyr.exe`` to be run with root privileges - (needed to create and configure the TAP device). - If not set (the default and recommended way), the network interface - must be set up manually using ``net-setup.sh`` (from the net-tools - project repo). The ``zephyr.exe`` program can then be run as a - non-root user. - -if ETH_NATIVE_POSIX_STARTUP_AUTOMATIC - -config ETH_NATIVE_POSIX_SETUP_SCRIPT - string "Host setup script" - default "${ZEPHYR_BASE}/samples/net/eth_native_posix/net_setup_host" - help - This option sets the name of the script that is run when the host TAP - network interface is created. The script should setup IP addresses - etc. for the host TAP network interface. - The default script accepts following options: - -i|--interface , default is zeth - -f|--file , default is net_setup_host.conf - If needed, you can add these options to this script name option. - Note that the driver will add -i option with the value of - CONFIG_ETH_NATIVE_POSIX_DRV_NAME option to the end of the options - list when calling the host setup script. - -config ETH_NATIVE_POSIX_STARTUP_SCRIPT - string "Host startup script" - default "" - help - This option sets the name of the script that is run when the host TAP - network interface is created and setup script has been run. - The startup script could launch e.g., wireshark to capture - the network traffic for the freshly started network interface. - Note that the network interface name CONFIG_ETH_NATIVE_POSIX_DRV_NAME - is appended at the end of this startup script name. - Example script for starting wireshark is provided in - ${ZEPHYR_BASE}/samples/net/eth_native_posix/net_start_wireshark.sh - file. - -config ETH_NATIVE_POSIX_STARTUP_SCRIPT_USER - string "Username to run the host startup script" - default "" - help - By default the startup script is run as a root user. Set here the - username to run the script if running it as a root user is not - desired. Note that this setting is only for startup script and not - for the setup script. The setup script needs to be run always as - a root user. - -endif # ETH_NATIVE_POSIX_STARTUP_AUTOMATIC config ETH_NATIVE_POSIX_INTERFACE_COUNT int "Number of network interfaces created" diff --git a/drivers/ethernet/Kconfig.numaker b/drivers/ethernet/Kconfig.numaker new file mode 100644 index 000000000000000..eb757870d7b502c --- /dev/null +++ b/drivers/ethernet/Kconfig.numaker @@ -0,0 +1,14 @@ +# NUMAKER Ethernet Driver configuration options + +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config ETH_NUMAKER + bool "Nuvoton NUMAKER MCU Ethernet driver" + default y + select HAS_NUMAKER_ETH + depends on DT_HAS_NUVOTON_NUMAKER_ETHERNET_ENABLED + help + This option enables the Ethernet driver for Nuvoton NuMaker family of + processors. + Say y if you wish to enable NuMaker ETH. diff --git a/drivers/ethernet/Kconfig.nxp_enet b/drivers/ethernet/Kconfig.nxp_enet new file mode 100644 index 000000000000000..a6182ade32df00b --- /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.nxp_s32_netc b/drivers/ethernet/Kconfig.nxp_s32_netc index e73f65502a31dec..6c568ca211efb7e 100644 --- a/drivers/ethernet/Kconfig.nxp_s32_netc +++ b/drivers/ethernet/Kconfig.nxp_s32_netc @@ -1,11 +1,10 @@ -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # SPDX-License-Identifier: Apache-2.0 menuconfig ETH_NXP_S32_NETC bool "NXP S32 Ethernet Switch and Controller (NETC) driver" default y depends on (DT_HAS_NXP_S32_NETC_PSI_ENABLED || DT_HAS_NXP_S32_NETC_VSI_ENABLED) - depends on !NET_TEST select MBOX select MDIO if DT_HAS_NXP_S32_NETC_PSI_ENABLED select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT diff --git a/drivers/ethernet/Kconfig.stm32_hal b/drivers/ethernet/Kconfig.stm32_hal index 4f5f79d1f636a45..8161ea31f5f9d59 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 000000000000000..258d1462b8f2c63 --- /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/dsa_ksz8xxx.c b/drivers/ethernet/dsa_ksz8xxx.c index 0a6bb0adffe6997..964cd3505d30d44 100644 --- a/drivers/ethernet/dsa_ksz8xxx.c +++ b/drivers/ethernet/dsa_ksz8xxx.c @@ -1091,8 +1091,6 @@ static struct dsa_api dsa_api_f = { #if defined(CONFIG_DSA_SPI) #define DSA_SPI_BUS_CONFIGURATION(n) \ .spi = SPI_DT_SPEC_INST_GET(n, \ - COND_CODE_1(DT_INST_PROP(n, spi_cpol), (SPI_MODE_CPOL), ()) | \ - COND_CODE_1(DT_INST_PROP(n, spi_cpha), (SPI_MODE_CPHA), ()) | \ SPI_WORD_SET(8), \ 0U) #else diff --git a/drivers/ethernet/eth_adin2111.c b/drivers/ethernet/eth_adin2111.c index c26671b0e3f97dc..e73beb891d4bb68 100644 --- a/drivers/ethernet/eth_adin2111.c +++ b/drivers/ethernet/eth_adin2111.c @@ -264,8 +264,12 @@ static inline void adin2111_port_on_phyint(const struct device *dev) } } -static void adin2111_offload_thread(const struct device *dev) +static void adin2111_offload_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; struct adin2111_data *ctx = dev->data; const struct adin2111_config *adin_cfg = dev->config; bool is_adin2111 = (adin_cfg->id == ADIN2111_MAC); @@ -669,7 +673,7 @@ static void adin2111_port_iface_init(struct net_if *iface) /* all ifaces are done, start INT processing */ k_thread_create(&ctx->rx_thread, ctx->rx_thread_stack, CONFIG_ETH_ADIN2111_IRQ_THREAD_STACK_SIZE, - (k_thread_entry_t)adin2111_offload_thread, + adin2111_offload_thread, (void *)adin, NULL, NULL, CONFIG_ETH_ADIN2111_IRQ_THREAD_PRIO, K_ESSENTIAL, K_NO_WAIT); @@ -696,19 +700,23 @@ static int adin2111_port_set_config(const struct device *dev, const struct device *adin = cfg->adin; int ret = -ENOTSUP; + (void)eth_adin2111_lock(adin, K_FOREVER); + if (type == ETHERNET_CONFIG_TYPE_MAC_ADDRESS) { - ret = adin2111_filter_unicast(adin, data->mac_addr, cfg->port_idx); + ret = adin2111_filter_unicast(adin, (uint8_t *)&config->mac_address.addr[0], + cfg->port_idx); if (ret < 0) { - return ret; + goto end_unlock; } - memcpy(data->mac_addr, config->mac_address.addr, sizeof(data->mac_addr)); + (void)memcpy(data->mac_addr, config->mac_address.addr, sizeof(data->mac_addr)); - net_if_set_link_addr(data->iface, data->mac_addr, - sizeof(data->mac_addr), - NET_LINK_ETHERNET); + (void)net_if_set_link_addr(data->iface, data->mac_addr, sizeof(data->mac_addr), + NET_LINK_ETHERNET); } +end_unlock: + (void)eth_adin2111_unlock(adin); return ret; } @@ -972,8 +980,8 @@ static const struct ethernet_api adin2111_port_api = { static struct adin2111_data name##_data_##inst = { \ .ifaces_left_to_init = ifaces, \ .port = {}, \ - .offload_sem = Z_SEM_INITIALIZER(adin2111_data_##inst.offload_sem, 0, 1), \ - .lock = Z_MUTEX_INITIALIZER(adin2111_data_##inst.lock), \ + .offload_sem = Z_SEM_INITIALIZER(name##_data_##inst.offload_sem, 0, 1), \ + .lock = Z_MUTEX_INITIALIZER(name##_data_##inst.lock), \ .buf = name##_buffer_##inst, \ }; \ /* adin */ \ diff --git a/drivers/ethernet/eth_dwmac_mmu.c b/drivers/ethernet/eth_dwmac_mmu.c index 38e8a99c4356e6e..b78fbbc035d6bbb 100644 --- a/drivers/ethernet/eth_dwmac_mmu.c +++ b/drivers/ethernet/eth_dwmac_mmu.c @@ -15,7 +15,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define DT_DRV_COMPAT snps_designware_ethernet #include -#include +#include #include #include #include diff --git a/drivers/ethernet/eth_enc28j60.c b/drivers/ethernet/eth_enc28j60.c index 35aacd8753a90cf..502d0cc1199da35 100644 --- a/drivers/ethernet/eth_enc28j60.c +++ b/drivers/ethernet/eth_enc28j60.c @@ -708,8 +708,12 @@ static int eth_enc28j60_rx(const struct device *dev, uint16_t *vlan_tag) return 0; } -static void eth_enc28j60_rx_thread(const struct device *dev) +static void eth_enc28j60_rx_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; struct eth_enc28j60_runtime *context = dev->data; uint16_t vlan_tag = NET_VLAN_TAG_UNSPEC; uint8_t int_stat; @@ -850,7 +854,7 @@ static int eth_enc28j60_init(const struct device *dev) /* Start interruption-poll thread */ k_thread_create(&context->thread, context->thread_stack, CONFIG_ETH_ENC28J60_RX_THREAD_STACK_SIZE, - (k_thread_entry_t)eth_enc28j60_rx_thread, + eth_enc28j60_rx_thread, (void *)dev, NULL, NULL, K_PRIO_COOP(CONFIG_ETH_ENC28J60_RX_THREAD_PRIO), 0, K_NO_WAIT); diff --git a/drivers/ethernet/eth_enc424j600.c b/drivers/ethernet/eth_enc424j600.c index c4ab74400581d82..b2b645652cee345 100644 --- a/drivers/ethernet/eth_enc424j600.c +++ b/drivers/ethernet/eth_enc424j600.c @@ -442,8 +442,12 @@ static int enc424j600_rx(const struct device *dev) return 0; } -static void enc424j600_rx_thread(struct enc424j600_runtime *context) +static void enc424j600_rx_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct enc424j600_runtime *context = p1; uint16_t eir; uint16_t estat; uint8_t counter; @@ -767,7 +771,7 @@ static int enc424j600_init(const struct device *dev) /* Start interruption-poll thread */ k_thread_create(&context->thread, context->thread_stack, CONFIG_ETH_ENC424J600_RX_THREAD_STACK_SIZE, - (k_thread_entry_t)enc424j600_rx_thread, + enc424j600_rx_thread, context, NULL, NULL, K_PRIO_COOP(CONFIG_ETH_ENC424J600_RX_THREAD_PRIO), 0, K_NO_WAIT); diff --git a/drivers/ethernet/eth_esp32.c b/drivers/ethernet/eth_esp32.c index 0b1744efe6c80e9..6cf6ba44813d27e 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 eb869261cbcca2e..0d2c104359a7a78 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 b5769a31f03541c..f537d3be295824b 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 d5b5b29a7353d13..3301dd72a35d96d 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 new file mode 100644 index 000000000000000..5a588914b308af4 --- /dev/null +++ b/drivers/ethernet/eth_lan865x.c @@ -0,0 +1,608 @@ +/* + * Copyright (c) 2023 DENX Software Engineering GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT microchip_lan865x + +#include +LOG_MODULE_REGISTER(eth_lan865x, CONFIG_ETHERNET_LOG_LEVEL); + +#include +#include + +#include +#include + +#include +#include +#include + +#include "eth_lan865x_priv.h" + +static int lan865x_mac_rxtx_control(const struct device *dev, bool en) +{ + struct lan865x_data *ctx = dev->data; + uint32_t ctl = 0; + + if (en) { + ctl = LAN865x_MAC_NCR_TXEN | LAN865x_MAC_NCR_RXEN; + } + + return oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_NCR, ctl); +} + +static void lan865x_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct lan865x_data *ctx = dev->data; + + net_if_set_link_addr(iface, ctx->mac_address, sizeof(ctx->mac_address), + NET_LINK_ETHERNET); + + if (ctx->iface == NULL) { + ctx->iface = iface; + } + + ethernet_init(iface); + + net_eth_carrier_on(iface); + ctx->iface_initialized = true; +} + +static enum ethernet_hw_caps lan865x_port_get_capabilities(const struct device *dev) +{ + ARG_UNUSED(dev); + 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; + + if (type == ETHERNET_CONFIG_TYPE_PROMISC_MODE) { + ret = lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_OFF); + if (ret) { + return ret; + } + + ret = oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_NCFGR, + LAN865x_MAC_NCFGR_CAF); + if (ret) { + return ret; + } + + return lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_ON); + } + + if (type == ETHERNET_CONFIG_TYPE_MAC_ADDRESS) { + ret = lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_OFF); + if (ret) { + return ret; + } + + memcpy(ctx->mac_address, config->mac_address.addr, + sizeof(ctx->mac_address)); + + lan865x_write_macaddress(dev); + + net_if_set_link_addr(ctx->iface, ctx->mac_address, + sizeof(ctx->mac_address), + NET_LINK_ETHERNET); + + 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; +} + +static int lan865x_wait_for_reset(const struct device *dev) +{ + struct lan865x_data *ctx = dev->data; + uint8_t i; + + /* Wait for end of LAN865x reset */ + for (i = 0; !ctx->reset && i < LAN865X_RESET_TIMEOUT; i++) { + k_msleep(1); + } + + if (i == LAN865X_RESET_TIMEOUT) { + LOG_ERR("LAN865x reset timeout reached!"); + return -ENODEV; + } + + return 0; +} + +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) */ + gpio_pin_set_dt(&cfg->reset, 1); + k_busy_wait(10U); + /* deassert - end of reset indicated by IRQ_N low */ + gpio_pin_set_dt(&cfg->reset, 0); + + return lan865x_wait_for_reset(dev); +} + +static int lan865x_check_spi(const struct device *dev) +{ + struct lan865x_data *ctx = dev->data; + uint32_t val; + int ret; + + ret = oa_tc6_reg_read(ctx->tc6, LAN865x_DEVID, &val); + if (ret < 0) { + return -ENODEV; + } + + ctx->silicon_rev = val & LAN865X_REV_MASK; + if (ctx->silicon_rev != 1 && ctx->silicon_rev != 2) { + return -ENODEV; + } + + ctx->chip_id = (val >> 4) & 0xFFFF; + if (ctx->chip_id != LAN8650_DEVID && ctx->chip_id != LAN8651_DEVID) { + return -ENODEV; + } + + return ret; +} + +/* Implementation of pseudo code from AN1760 */ +static uint8_t lan865x_read_indirect_reg(const struct device *dev, uint8_t addr, + uint8_t mask) +{ + struct lan865x_data *ctx = dev->data; + uint32_t val; + + oa_tc6_reg_write(ctx->tc6, 0x000400D8, addr); + oa_tc6_reg_write(ctx->tc6, 0x000400DA, 0x02); + + oa_tc6_reg_read(ctx->tc6, 0x000400D9, &val); + + return (uint8_t) val & mask; +} + +static int lan865x_init_chip(const struct device *dev, uint8_t silicon_rev) +{ + struct lan865x_data *ctx = dev->data; + uint8_t value1, value2; + int8_t offset1 = 0, offset2 = 0, ret; + uint16_t value3, value4, value5, value6, value7; + uint16_t cfgparam1, cfgparam2, cfgparam3, cfgparam4, cfgparam5; + uint32_t val; + + ret = lan865x_read_indirect_reg(dev, 0x05, 0x40); + if (ret == 0) { + LOG_ERR("LAN865x error! Please contact microchip support for replacement."); + return -EIO; + } + + value1 = lan865x_read_indirect_reg(dev, 0x04, 0x1F); + if ((value1 & 0x10) != 0) { /* Convert uint8_t to int8_t */ + offset1 = value1 | 0xE0; + if (offset1 < -5) { + LOG_ERR("LAN865x internal error!"); + return -EIO; + } + } else { + offset1 = value1; + } + + value2 = lan865x_read_indirect_reg(dev, 0x08, 0x1F); + if ((value2 & 0x10) != 0) { /* Convert uint8_t to int8_t */ + offset2 = value2 | 0xE0; + } else { + offset2 = value2; + } + + oa_tc6_reg_read(ctx->tc6, 0x00040084, &val); + value3 = (uint16_t)val; + + oa_tc6_reg_read(ctx->tc6, 0x0004008A, &val); + value4 = (uint16_t)val; + + oa_tc6_reg_read(ctx->tc6, 0x000400AD, &val); + value5 = (uint16_t)val; + + oa_tc6_reg_read(ctx->tc6, 0x000400AE, &val); + value6 = (uint8_t)val; + + oa_tc6_reg_read(ctx->tc6, 0x000400AF, &val); + value7 = (uint8_t)val; + + cfgparam1 = (value3 & 0xF) | (((9 + offset1) << 10) | ((14 + offset1) << 4)); + cfgparam2 = (value4 & 0x3FF) | ((40 + offset2) << 10); + cfgparam3 = (value5 & 0xC0C0) | (((5 + offset1) << 8) | (9 + offset1)); + cfgparam4 = (value6 & 0xC0C0) | (((9 + offset1) << 8) | (14 + offset1)); + cfgparam5 = (value7 & 0xC0C0) | (((17 + offset1) << 8) | (22 + offset1)); + + oa_tc6_reg_write(ctx->tc6, 0x00040084, (uint32_t) cfgparam1); + oa_tc6_reg_write(ctx->tc6, 0x0004008A, (uint32_t) cfgparam2); + oa_tc6_reg_write(ctx->tc6, 0x000400AD, (uint32_t) cfgparam3); + oa_tc6_reg_write(ctx->tc6, 0x000400AE, (uint32_t) cfgparam4); + oa_tc6_reg_write(ctx->tc6, 0x000400AF, (uint32_t) cfgparam5); + + return 0; +} +/* Implementation of pseudo code from AN1760 - END */ + +static int lan865x_config_plca(const struct device *dev, uint8_t node_id, + uint8_t node_cnt, uint8_t burst_cnt, uint8_t burst_timer) +{ + struct lan865x_data *ctx = dev->data; + uint32_t val; + + /* Collision Detection */ + oa_tc6_reg_write(ctx->tc6, 0x00040087, 0x0083u); /* COL_DET_CTRL0 */ + + /* T1S Phy Node Id and Max Node Count */ + val = ((uint32_t)node_cnt << 8) | node_id; + oa_tc6_reg_write(ctx->tc6, 0x0004CA02, val); /* PLCA_CONTROL_1_REGISTER */ + + /* PLCA Burst Count and Burst Timer */ + val = ((uint32_t)burst_cnt << 8) | burst_timer; + oa_tc6_reg_write(ctx->tc6, 0x0004CA05, val); /* PLCA_BURST_MODE_REGISTER */ + + /* Enable PLCA */ + oa_tc6_reg_write(ctx->tc6, 0x0004CA01, BIT(15)); /* PLCA_CONTROL_0_REGISTER */ + + return 0; +} + +static void lan865x_write_macaddress(const struct device *dev) +{ + struct lan865x_data *ctx = dev->data; + uint8_t *mac = &ctx->mac_address[0]; + uint32_t val; + + /* SPEC_ADD2_BOTTOM */ + val = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]; + oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAB2, val); + + /* SPEC_ADD2_TOP */ + val = (mac[5] << 8) | mac[4]; + oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAT2, val); + + /* SPEC_ADD1_BOTTOM */ + val = (mac[5] << 24) | (mac[4] << 16) | (mac[3] << 8) | mac[2]; + oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAB1, val); +} + +static int lan865x_default_config(const struct device *dev, uint8_t silicon_rev) +{ + /* Values in the below table are the same for LAN865x rev. B0 and B1 */ + static const oa_mem_map_t lan865x_conf[] = { + { .address = 0x00010000, .value = 0x00000000 }, + { .address = 0x00040091, .value = 0x00009660 }, + { .address = 0x00040081, .value = 0x00000080 }, + { .address = 0x00010077, .value = 0x00000028 }, + { .address = 0x00040043, .value = 0x000000FF }, + { .address = 0x00040044, .value = 0x0000FFFF }, + { .address = 0x00040045, .value = 0x00000000 }, + { .address = 0x00040053, .value = 0x000000FF }, + { .address = 0x00040054, .value = 0x0000FFFF }, + { .address = 0x00040055, .value = 0x00000000 }, + { .address = 0x00040040, .value = 0x00000002 }, + { .address = 0x00040050, .value = 0x00000002 }, + { .address = 0x000400E9, .value = 0x00009E50 }, + { .address = 0x000400F5, .value = 0x00001CF8 }, + { .address = 0x000400F4, .value = 0x0000C020 }, + { .address = 0x000400F8, .value = 0x00009B00 }, + { .address = 0x000400F9, .value = 0x00004E53 }, + { .address = 0x000400B0, .value = 0x00000103 }, + { .address = 0x000400B1, .value = 0x00000910 }, + { .address = 0x000400B2, .value = 0x00001D26 }, + { .address = 0x000400B3, .value = 0x0000002A }, + { .address = 0x000400B4, .value = 0x00000103 }, + { .address = 0x000400B5, .value = 0x0000070D }, + { .address = 0x000400B6, .value = 0x00001720 }, + { .address = 0x000400B7, .value = 0x00000027 }, + { .address = 0x000400B8, .value = 0x00000509 }, + { .address = 0x000400B9, .value = 0x00000E13 }, + { .address = 0x000400BA, .value = 0x00001C25 }, + { .address = 0x000400BB, .value = 0x0000002B }, + { .address = 0x0000000C, .value = 0x00000100 }, + { .address = 0x00040081, .value = 0x000000E0 }, + }; + const struct lan865x_config *cfg = dev->config; + uint8_t i, size = ARRAY_SIZE(lan865x_conf); + struct lan865x_data *ctx = dev->data; + int ret; + + /* Enable protected control RW */ + oa_tc6_set_protected_ctrl(ctx->tc6, true); + + for (i = 0; i < size; i++) { + oa_tc6_reg_write(ctx->tc6, lan865x_conf[i].address, + lan865x_conf[i].value); + } + + if (silicon_rev == 1) { + /* For silicon rev 1 (B0): (bit [3..0] from 0x0A0084 */ + oa_tc6_reg_write(ctx->tc6, 0x000400D0, 0x5F21); + } + + lan865x_write_macaddress(dev); + + ret = lan865x_init_chip(dev, 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 (ret < 0) { + return ret; + } + } + return 0; +} + +static void lan865x_int_callback(const struct device *dev, + struct gpio_callback *cb, + uint32_t pins) +{ + ARG_UNUSED(dev); + ARG_UNUSED(pins); + + struct lan865x_data *ctx = + CONTAINER_OF(cb, struct lan865x_data, gpio_int_callback); + + k_sem_give(&ctx->int_sem); +} + +static void lan865x_read_chunks(const struct device *dev) +{ + const struct lan865x_config *cfg = dev->config; + struct lan865x_data *ctx = dev->data; + struct oa_tc6 *tc6 = ctx->tc6; + struct net_pkt *pkt; + int ret; + + pkt = net_pkt_rx_alloc(K_MSEC(cfg->timeout)); + if (!pkt) { + LOG_ERR("OA RX: Could not allocate packet!"); + return; + } + + k_sem_take(&ctx->tx_rx_sem, K_FOREVER); + ret = oa_tc6_read_chunks(tc6, pkt); + if (ret < 0) { + eth_stats_update_errors_rx(ctx->iface); + net_pkt_unref(pkt); + k_sem_give(&ctx->tx_rx_sem); + return; + } + + /* Feed buffer frame to IP stack */ + ret = net_recv_data(ctx->iface, pkt); + if (ret < 0) { + 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) +{ + 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); + if (!ctx->reset) { + oa_tc6_reg_read(tc6, OA_STATUS0, &sts); + if (sts & OA_STATUS0_RESETC) { + oa_tc6_reg_write(tc6, OA_STATUS0, sts); + lan865x_default_config(dev, ctx->silicon_rev); + oa_tc6_reg_read(tc6, OA_CONFIG0, &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; + /* + * According to OA T1S standard - it is mandatory to + * read chunk of data to get the IRQ_N negated (deasserted). + */ + oa_tc6_read_status(tc6, &ftr); + continue; + } + } + + /* + * 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! + */ + do { + lan865x_read_chunks(dev); + } while (tc6->rca > 0); + + ret = oa_tc6_check_status(tc6); + if (ret == -EIO) { + lan865x_gpio_reset(dev); + } + } +} + +static int lan865x_init(const struct device *dev) +{ + const struct lan865x_config *cfg = dev->config; + struct lan865x_data *ctx = dev->data; + int ret; + + __ASSERT(cfg->spi.config.frequency <= LAN865X_SPI_MAX_FREQUENCY, + "SPI frequency exceeds supported maximum\n"); + + if (!spi_is_ready_dt(&cfg->spi)) { + LOG_ERR("SPI bus %s not ready", cfg->spi.bus->name); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&cfg->interrupt)) { + LOG_ERR("Interrupt GPIO device %s is not ready", + cfg->interrupt.port->name); + return -ENODEV; + } + + /* Check SPI communication after reset */ + ret = lan865x_check_spi(dev); + if (ret < 0) { + LOG_ERR("SPI communication not working, %d", ret); + return ret; + } + + /* + * Configure interrupt service routine for LAN865x IRQ + */ + ret = gpio_pin_configure_dt(&cfg->interrupt, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Failed to configure interrupt GPIO, %d", ret); + return ret; + } + + gpio_init_callback(&(ctx->gpio_int_callback), lan865x_int_callback, + BIT(cfg->interrupt.pin)); + + ret = gpio_add_callback(cfg->interrupt.port, &ctx->gpio_int_callback); + if (ret < 0) { + LOG_ERR("Failed to add INT callback, %d", ret); + return ret; + } + + gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_EDGE_TO_ACTIVE); + + /* Start interruption-poll thread */ + ctx->tid_int = + k_thread_create(&ctx->thread, ctx->thread_stack, + CONFIG_ETH_LAN865X_IRQ_THREAD_STACK_SIZE, + (k_thread_entry_t)lan865x_int_thread, + (void *)dev, NULL, NULL, + K_PRIO_COOP(CONFIG_ETH_LAN865X_IRQ_THREAD_PRIO), + 0, K_NO_WAIT); + k_thread_name_set(ctx->tid_int, "lan865x_interrupt"); + + /* 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", + cfg->reset.port->name); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&cfg->reset, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + LOG_ERR("Failed to configure reset GPIO, %d", ret); + return ret; + } + + return lan865x_gpio_reset(dev); +} + +static int lan865x_port_send(const struct device *dev, struct net_pkt *pkt) +{ + struct lan865x_data *ctx = dev->data; + struct oa_tc6 *tc6 = ctx->tc6; + int ret; + + 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); + eth_stats_update_errors_tx(net_pkt_iface(pkt)); + return ret; + } + + return 0; +} + +static const struct ethernet_api lan865x_api_func = { + .iface_api.init = lan865x_iface_init, + .get_capabilities = lan865x_port_get_capabilities, + .set_config = lan865x_set_config, + .send = lan865x_port_send, +}; + +#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 = &lan865x_config_plca_##inst, \ + }; \ + \ + struct oa_tc6 oa_tc6_##inst = { \ + .cps = 64, \ + .protected = 0, \ + .spi = &lan865x_config_##inst.spi \ + }; \ + 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, 1), \ + .int_sem = Z_SEM_INITIALIZER((lan865x_data_##inst).int_sem, 0, 1), \ + .tc6 = &oa_tc6_##inst \ + }; \ + \ + ETH_NET_DEVICE_DT_INST_DEFINE(inst, lan865x_init, NULL, &lan865x_data_##inst, \ + &lan865x_config_##inst, CONFIG_ETH_INIT_PRIORITY, \ + &lan865x_api_func, NET_ETH_MTU); + +DT_INST_FOREACH_STATUS_OKAY(LAN865X_DEFINE); diff --git a/drivers/ethernet/eth_lan865x_priv.h b/drivers/ethernet/eth_lan865x_priv.h new file mode 100644 index 000000000000000..8f1b767595b69f3 --- /dev/null +++ b/drivers/ethernet/eth_lan865x_priv.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023 DENX Software Engineering GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ETH_LAN865X_PRIV_H__ +#define ETH_LAN865X_PRIV_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "oa_tc6.h" + +#define LAN865X_SPI_MAX_FREQUENCY 25000000U +#define LAN865X_HW_BOOT_DELAY_MS 7 +#define LAN8650_DEVID 0x8650 +#define LAN8651_DEVID 0x8651 +#define LAN865X_REV_MASK GENMASK(3, 0) +#define LAN865X_RESET_TIMEOUT 10 + +/* Memory Map Sector (MMS) 1 (0x1) */ +#define LAN865x_MAC_NCR MMS_REG(0x1, 0x000) +#define LAN865x_MAC_NCR_TXEN BIT(3) +#define LAN865x_MAC_NCR_RXEN BIT(2) +#define LAN865x_MAC_NCFGR MMS_REG(0x1, 0x001) +#define LAN865x_MAC_NCFGR_CAF BIT(4) +#define LAN865x_MAC_SAB1 MMS_REG(0x1, 0x022) +#define LAN865x_MAC_SAB2 MMS_REG(0x1, 0x024) +#define LAN865x_MAC_SAT2 MMS_REG(0x1, 0x025) + +#define LAN865x_MAC_TXRX_ON 1 +#define LAN865x_MAC_TXRX_OFF 0 + +/* 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; + struct gpio_dt_spec reset; + int32_t timeout; + + /* PLCA */ + struct lan865x_config_plca *plca; + + /* MAC */ + bool tx_cut_through_mode; /* 1 - tx cut through, 0 - Store and forward */ + bool rx_cut_through_mode; /* 1 - rx cut through, 0 - Store and forward */ +}; + +struct lan865x_data { + struct net_if *iface; + struct gpio_callback gpio_int_callback; + struct k_sem tx_rx_sem; + struct k_sem int_sem; + struct oa_tc6 *tc6; + uint16_t chip_id; + uint8_t silicon_rev; + uint8_t mac_address[6]; + bool iface_initialized; + bool reset; + + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_ETH_LAN865X_IRQ_THREAD_STACK_SIZE); + struct k_thread thread; + k_tid_t tid_int; +}; + +#endif /* ETH_LAN865X_PRIV_H__ */ diff --git a/drivers/ethernet/eth_mcux.c b/drivers/ethernet/eth_mcux.c index b4e244ae30471d4..81edc564259db73 100644 --- a/drivers/ethernet/eth_mcux.c +++ b/drivers/ethernet/eth_mcux.c @@ -1163,7 +1163,7 @@ static int eth_init(const struct device *dev) return 0; } -#if defined(CONFIG_NET_IPV6) +#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) @@ -1172,30 +1172,32 @@ static void net_if_mcast_cb(struct net_if *iface, struct eth_context *context = dev->data; struct net_eth_addr mac_addr; - if (addr->family != AF_INET6) { + 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; } - net_eth_ipv6_mcast_to_mac_addr(&addr->in6_addr, &mac_addr); - if (is_joined) { ENET_AddMulticastGroup(context->base, mac_addr.addr); } else { ENET_LeaveMulticastGroup(context->base, mac_addr.addr); } } -#endif /* CONFIG_NET_IPV6 */ +#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_IPV6) +#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_IPV6 */ +#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 874077b61a14310..9f1b7b2bcda529b 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) @@ -153,7 +154,7 @@ static void update_gptp(struct net_if *iface, struct net_pkt *pkt, struct gptp_hdr *hdr; int ret; - ret = eth_clock_gettime(×tamp); + ret = eth_clock_gettime(×tamp.second, ×tamp.nanosecond); if (ret < 0) { return; } @@ -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; } @@ -364,8 +365,12 @@ static int read_data(struct eth_context *ctx, int fd) return 0; } -static void eth_rx(struct eth_context *ctx) +static void eth_rx(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct eth_context *ctx = p1; LOG_DBG("Starting ZETH RX thread"); while (1) { @@ -391,7 +396,7 @@ static void create_rx_handler(struct eth_context *ctx) k_thread_create(ctx->rx_thread, ctx->rx_stack, ctx->rx_stack_size, - (k_thread_entry_t)eth_rx, + eth_rx, ctx, NULL, NULL, K_PRIO_COOP(14), 0, K_NO_WAIT); @@ -460,7 +465,7 @@ static void eth_iface_init(struct net_if *iface) * change the documentation etc. and break things. */ if (CONFIG_ETH_NATIVE_POSIX_INTERFACE_COUNT == 1) { - ctx->if_name = ETH_NATIVE_POSIX_DRV_NAME; + ctx->if_name = CONFIG_ETH_NATIVE_POSIX_DRV_NAME; } LOG_DBG("Interface %p using \"%s\"", iface, ctx->if_name); @@ -468,16 +473,12 @@ static void eth_iface_init(struct net_if *iface) net_if_set_link_addr(iface, ll_addr->addr, ll_addr->len, NET_LINK_ETHERNET); - ctx->dev_fd = eth_iface_create(ctx->if_name, false); + ctx->dev_fd = eth_iface_create(CONFIG_ETH_NATIVE_POSIX_DEV_NAME, ctx->if_name, false); if (ctx->dev_fd < 0) { LOG_ERR("Cannot create %s (%d)", ctx->if_name, -errno); } else { /* Create a thread that will handle incoming data from host */ create_rx_handler(ctx); - - eth_setup_host(ctx->if_name); - - eth_start_script(ctx->if_name); } } @@ -573,36 +574,11 @@ static int vlan_setup(const struct device *dev, struct net_if *iface, } #endif /* CONFIG_NET_VLAN */ -static int eth_start_device(const struct device *dev) -{ - struct eth_context *context = dev->data; - int ret; - - context->status = true; - - ret = eth_if_up(context->if_name); - - eth_setup_host(context->if_name); - - return ret; -} - -static int eth_stop_device(const struct device *dev) -{ - struct eth_context *context = dev->data; - - context->status = false; - - return eth_if_down(context->if_name); -} - static const struct ethernet_api eth_if_api = { .iface_api.init = eth_iface_init, .get_capabilities = eth_posix_native_get_capabilities, .set_config = set_config, - .start = eth_start_device, - .stop = eth_stop_device, .send = eth_send, #if defined(CONFIG_NET_VLAN) @@ -671,7 +647,7 @@ static int ptp_clock_get_native_posix(const struct device *clk, { ARG_UNUSED(clk); - return eth_clock_gettime(tm); + return eth_clock_gettime(&tm->second, &tm->nanosecond); } static int ptp_clock_adjust_native_posix(const struct device *clk, diff --git a/drivers/ethernet/eth_native_posix_adapt.c b/drivers/ethernet/eth_native_posix_adapt.c index 14f73d6916a518f..81ae9bdcf8fa2ad 100644 --- a/drivers/ethernet/eth_native_posix_adapt.c +++ b/drivers/ethernet/eth_native_posix_adapt.c @@ -25,39 +25,25 @@ #include #include #include -#include +#include +#include #ifdef __linux +#include #include #endif -/* Zephyr include files. Be very careful here and only include minimum - * things needed. - */ -#define LOG_MODULE_NAME eth_posix_adapt -#define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL - -#include -LOG_MODULE_REGISTER(LOG_MODULE_NAME); - -#include -#include - -#if defined(CONFIG_NET_GPTP) -#include -#endif - #include "eth_native_posix_priv.h" /* Note that we cannot create the TUN/TAP device from the setup script * as we need to get a file descriptor to communicate with the interface. */ -int eth_iface_create(const char *if_name, bool tun_only) +int eth_iface_create(const char *dev_name, const char *if_name, bool tun_only) { struct ifreq ifr; int fd, ret = -EINVAL; - fd = open(ETH_NATIVE_POSIX_DEV_NAME, O_RDWR); + fd = open(dev_name, O_RDWR); if (fd < 0) { return -errno; } @@ -98,48 +84,13 @@ static int ssystem(const char *fmt, ...) vsnprintf(cmd, sizeof(cmd), fmt, ap); va_end(ap); - posix_print_trace("%s\n", cmd); + nsi_print_trace("%s\n", cmd); ret = system(cmd); return -WEXITSTATUS(ret); } -int eth_setup_host(const char *if_name) -{ - if (!IS_ENABLED(CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC)) { - return 0; - } - - /* User might have added -i option to setup script string, so - * check that situation in the script itself so that the -i option - * we add here is ignored in that case. - */ - return ssystem("%s -i %s", ETH_NATIVE_POSIX_SETUP_SCRIPT, - if_name); -} - -int eth_start_script(const char *if_name) -{ - if (!IS_ENABLED(CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC)) { - return 0; - } - - if (ETH_NATIVE_POSIX_STARTUP_SCRIPT[0] == '\0') { - return 0; - } - - if (ETH_NATIVE_POSIX_STARTUP_SCRIPT_USER[0] == '\0') { - return ssystem("%s %s", ETH_NATIVE_POSIX_STARTUP_SCRIPT, - if_name); - } else { - return ssystem("sudo -u %s %s %s", - ETH_NATIVE_POSIX_STARTUP_SCRIPT_USER, - ETH_NATIVE_POSIX_STARTUP_SCRIPT, - if_name); - } -} - int eth_wait_data(int fd) { struct timeval timeout; @@ -165,18 +116,7 @@ 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); -} - -#if defined(CONFIG_NET_GPTP) -int eth_clock_gettime(struct net_ptp_time *time) +int eth_clock_gettime(uint64_t *second, uint32_t *nanosecond) { struct timespec tp; int ret; @@ -186,44 +126,14 @@ int eth_clock_gettime(struct net_ptp_time *time) return -errno; } - time->second = tp.tv_sec; - time->nanosecond = tp.tv_nsec; + *second = (uint64_t)tp.tv_sec; + *nanosecond = (uint32_t)tp.tv_nsec; return 0; } -#endif /* CONFIG_NET_GPTP */ -#if defined(CONFIG_NET_PROMISCUOUS_MODE) int eth_promisc_mode(const char *if_name, bool enable) { - if (!IS_ENABLED(CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC)) { - return 0; - } - return ssystem("ip link set dev %s promisc %s", if_name, enable ? "on" : "off"); } -#endif /* CONFIG_NET_PROMISCUOUS_MODE */ - -/* If we have enabled manual setup, then interface cannot be - * taken up or down by the driver as we normally do not have - * enough permissions. - */ - -int eth_if_up(const char *if_name) -{ - if (!IS_ENABLED(CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC)) { - return 0; - } - - return ssystem("ip link set dev %s up", if_name); -} - -int eth_if_down(const char *if_name) -{ - if (!IS_ENABLED(CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC)) { - return 0; - } - - return ssystem("ip link set dev %s down", if_name); -} diff --git a/drivers/ethernet/eth_native_posix_priv.h b/drivers/ethernet/eth_native_posix_priv.h index 2d925fd83dc639e..f1d56f8df178dab 100644 --- a/drivers/ethernet/eth_native_posix_priv.h +++ b/drivers/ethernet/eth_native_posix_priv.h @@ -11,44 +11,10 @@ #ifndef ZEPHYR_DRIVERS_ETHERNET_ETH_NATIVE_POSIX_PRIV_H_ #define ZEPHYR_DRIVERS_ETHERNET_ETH_NATIVE_POSIX_PRIV_H_ -#define ETH_NATIVE_POSIX_DRV_NAME CONFIG_ETH_NATIVE_POSIX_DRV_NAME -#define ETH_NATIVE_POSIX_DEV_NAME CONFIG_ETH_NATIVE_POSIX_DEV_NAME - -#if defined(CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC) -#define ETH_NATIVE_POSIX_SETUP_SCRIPT CONFIG_ETH_NATIVE_POSIX_SETUP_SCRIPT -#define ETH_NATIVE_POSIX_STARTUP_SCRIPT CONFIG_ETH_NATIVE_POSIX_STARTUP_SCRIPT -#define ETH_NATIVE_POSIX_STARTUP_SCRIPT_USER \ - CONFIG_ETH_NATIVE_POSIX_STARTUP_SCRIPT_USER -#else -#define ETH_NATIVE_POSIX_SETUP_SCRIPT "" -#define ETH_NATIVE_POSIX_STARTUP_SCRIPT "" -#define ETH_NATIVE_POSIX_STARTUP_SCRIPT_USER "" -#endif - -int eth_iface_create(const char *if_name, bool tun_only); +int eth_iface_create(const char *dev_name, const char *if_name, bool tun_only); int eth_iface_remove(int fd); -int eth_setup_host(const char *if_name); -int eth_start_script(const char *if_name); 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_if_up(const char *if_name); -int eth_if_down(const char *if_name); - -#if defined(CONFIG_NET_GPTP) -int eth_clock_gettime(struct net_ptp_time *time); -#endif - -#if defined(CONFIG_NET_PROMISCUOUS_MODE) +int eth_clock_gettime(uint64_t *second, uint32_t *nanosecond); int eth_promisc_mode(const char *if_name, bool enable); -#else -static inline int eth_promisc_mode(const char *if_name, bool enable) -{ - ARG_UNUSED(if_name); - ARG_UNUSED(enable); - - return -ENOTSUP; -} -#endif #endif /* ZEPHYR_DRIVERS_ETHERNET_ETH_NATIVE_POSIX_PRIV_H_ */ diff --git a/drivers/ethernet/eth_numaker.c b/drivers/ethernet/eth_numaker.c new file mode 100644 index 000000000000000..77577943f23dca0 --- /dev/null +++ b/drivers/ethernet/eth_numaker.c @@ -0,0 +1,790 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_numaker_ethernet + +#include +#include +#include +#include +#include +#include +#include +#include "eth_numaker_priv.h" +#include "ethernet/eth_stats.h" +#include +#include +#include + +#ifdef CONFIG_SOC_M467 +#include +#endif + +LOG_MODULE_REGISTER(eth_numaker, CONFIG_ETHERNET_LOG_LEVEL); + +/* Device EMAC Interface port */ +#define NUMAKER_GMAC_INTF 0 +/* 2KB Data Flash at 0xFF800 */ +#define NUMAKER_DATA_FLASH (0xFF800U) +#define NUMAKER_MASK_32 (0xFFFFFFFFU) +#define NUMAKER_MII_CONFIG (ADVERTISE_CSMA | ADVERTISE_10HALF | ADVERTISE_10FULL | \ + ADVERTISE_100HALF | ADVERTISE_100FULL) +#define NUMAKER_MII_LINKED (BMSR_ANEGCOMPLETE | BMSR_LSTATUS) + +extern synopGMACdevice GMACdev[GMAC_CNT]; +extern struct sk_buff tx_buf[GMAC_CNT][TRANSMIT_DESC_SIZE]; +extern struct sk_buff rx_buf[GMAC_CNT][RECEIVE_DESC_SIZE]; + +static uint32_t eth_phy_addr; + +/* Device config */ +struct eth_numaker_config { + uint32_t gmac_base; + const struct reset_dt_spec reset; + uint32_t phy_addr; + uint32_t clk_modidx; + uint32_t clk_src; + uint32_t clk_div; + const struct device *clk_dev; + const struct pinctrl_dev_config *pincfg; +}; + +/* Driver context/data */ +struct eth_numaker_data { + synopGMACdevice *gmacdev; + struct net_if *iface; + uint8_t mac_addr[NU_HWADDR_SIZE]; + struct k_mutex tx_frame_buf_mutex; + struct k_spinlock rx_frame_buf_lock; +}; + +/* Delay execution for given amount of ticks for SDK-HAL */ +void plat_delay(uint32_t delay) +{ + uint32_t us_cnt = k_ticks_to_us_floor32((uint64_t)delay); + + k_busy_wait(us_cnt); +} + +static void mdio_write(synopGMACdevice *gmacdev, uint32_t addr, uint32_t reg, int data) +{ + synopGMAC_write_phy_reg((u32 *)gmacdev->MacBase, addr, reg, data); +} + +static int mdio_read(synopGMACdevice *gmacdev, uint32_t addr, uint32_t reg) +{ + uint16_t data; + + synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase, addr, reg, &data); + return data; +} + +static int numaker_eth_link_ok(synopGMACdevice *gmacdev) +{ + /* first, a dummy read to latch */ + mdio_read(gmacdev, eth_phy_addr, MII_BMSR); + if (mdio_read(gmacdev, eth_phy_addr, MII_BMSR) & BMSR_LSTATUS) { + return 1; + } + return 0; +} + +static int reset_phy(synopGMACdevice *gmacdev) +{ + uint16_t reg; + uint32_t delay_us; + bool ret; + + mdio_write(gmacdev, eth_phy_addr, MII_BMCR, BMCR_RESET); + + delay_us = 200000U; + ret = WAIT_FOR(!(mdio_read(gmacdev, eth_phy_addr, MII_BMCR) & BMCR_RESET), + delay_us, k_msleep(1)); + if (ret == false) { + LOG_DBG("Reset phy failed"); + return -EIO; + } + + LOG_INF("PHY ID 1:0x%x", mdio_read(gmacdev, eth_phy_addr, MII_PHYSID1)); + LOG_INF("PHY ID 2:0x%x", mdio_read(gmacdev, eth_phy_addr, MII_PHYSID2)); + delay_us = 3000000U; + ret = WAIT_FOR(numaker_eth_link_ok(gmacdev), delay_us, k_msleep(1)); + if (ret) { + gmacdev->LinkState = LINKUP; + LOG_DBG("Link Up"); + } else { + gmacdev->LinkState = LINKDOWN; + LOG_DBG("Link Down"); + return -EIO; + } + + mdio_write(gmacdev, eth_phy_addr, MII_ADVERTISE, NUMAKER_MII_CONFIG); + reg = mdio_read(gmacdev, eth_phy_addr, MII_BMCR); + mdio_write(gmacdev, eth_phy_addr, MII_BMCR, reg | BMCR_ANRESTART); + delay_us = 3000000U; + ret = WAIT_FOR((mdio_read(gmacdev, eth_phy_addr, MII_BMSR) & + NUMAKER_MII_LINKED) == NUMAKER_MII_LINKED, + delay_us, k_msleep(1)); + if (ret == false) { + LOG_DBG("AN failed. Set to 100 FULL"); + synopGMAC_set_full_duplex(gmacdev); + synopGMAC_set_mode(NUMAKER_GMAC_INTF, 1); /* Set mode 1: 100Mbps; 2: 10Mbps */ + return -EIO; + } + + reg = mdio_read(gmacdev, eth_phy_addr, MII_LPA); + if (reg & ADVERTISE_100FULL) { + LOG_DBG("100 full"); + gmacdev->DuplexMode = FULLDUPLEX; + gmacdev->Speed = SPEED100; + synopGMAC_set_full_duplex(gmacdev); + synopGMAC_set_mode(NUMAKER_GMAC_INTF, 1); /* Set mode 1: 100Mbps; 2: 10Mbps */ + } else if (reg & ADVERTISE_100HALF) { + LOG_DBG("100 half"); + gmacdev->DuplexMode = HALFDUPLEX; + gmacdev->Speed = SPEED100; + synopGMAC_set_half_duplex(gmacdev); + synopGMAC_set_mode(NUMAKER_GMAC_INTF, 1); /* Set mode 1: 100Mbps; 2: 10Mbps */ + } else if (reg & ADVERTISE_10FULL) { + LOG_DBG("10 full"); + gmacdev->DuplexMode = FULLDUPLEX; + gmacdev->Speed = SPEED10; + synopGMAC_set_full_duplex(gmacdev); + synopGMAC_set_mode(NUMAKER_GMAC_INTF, 2); /* Set mode 1: 100Mbps; 2: 10Mbps */ + } else { + LOG_DBG("10 half"); + gmacdev->DuplexMode = HALFDUPLEX; + gmacdev->Speed = SPEED10; + synopGMAC_set_half_duplex(gmacdev); + synopGMAC_set_mode(NUMAKER_GMAC_INTF, 2); /* Set mode 1: 100Mbps; 2: 10Mbps */ + } + + return 0; +} + +static void m_numaker_read_mac_addr(char *mac) +{ + uint32_t uid1; + /* Fetch word 0 of data flash */ + uint32_t word0 = *(uint32_t *)(NUMAKER_DATA_FLASH + 0x04U); + /* + * Fetch word 1 of data flash + * we only want bottom 16 bits of word1 (MAC bits 32-47) + * and bit 9 forced to 1, bit 8 forced to 0 + * Locally administered MAC, reduced conflicts + * http://en.wikipedia.org/wiki/MAC_address + */ + uint32_t word1 = *(uint32_t *)NUMAKER_DATA_FLASH; + + /* Not burn any mac address at the beginning of data flash */ + if (word0 == NUMAKER_MASK_32) { + /* Generate a semi-unique MAC address from the UUID */ + SYS_UnlockReg(); + /* Enable FMC ISP function */ + FMC_Open(); + uid1 = FMC_ReadUID(1); + word1 = (uid1 & 0x003FFFFF) | ((uid1 & 0x030000) << 6) >> 8; + word0 = ((FMC_ReadUID(0) >> 4) << 20) | ((uid1 & 0xFF) << 12) | + (FMC_ReadUID(2) & 0xFFF); + /* Disable FMC ISP function */ + FMC_Close(); + /* Lock protected registers */ + SYS_LockReg(); + } + + word1 |= 0x00000200; + word1 &= 0x0000FEFF; + + mac[0] = (word1 & 0x0000ff00) >> 8; + mac[1] = (word1 & 0x000000ff); + mac[2] = (word0 & 0xff000000) >> 24; + mac[3] = (word0 & 0x00ff0000) >> 16; + mac[4] = (word0 & 0x0000ff00) >> 8; + mac[5] = (word0 & 0x000000ff); + + LOG_INF("mac address %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], + mac[4], mac[5]); +} + +static void m_numaker_gmacdev_enable(synopGMACdevice *gmacdev) +{ + + synopGMAC_clear_interrupt(gmacdev); + + /* Enable INT & TX/RX */ + synopGMAC_enable_interrupt(gmacdev, DmaIntEnable); + synopGMAC_enable_dma_rx(gmacdev); + synopGMAC_enable_dma_tx(gmacdev); + + synopGMAC_tx_enable(gmacdev); + synopGMAC_rx_enable(gmacdev); +} + +static int m_numaker_gmacdev_init(synopGMACdevice *gmacdev, uint8_t *mac_addr, uint32_t gmac_base) +{ + int status; + int i; + uint32_t offload_needed = 0; + struct sk_buff *skb; + + LOG_DBG(""); + + /*Attach the device to MAC struct This will configure all the required base + * addresses such as Mac base, configuration base, phy base address(out of 32 + * possible phys ) + */ + synopGMAC_attach(gmacdev, gmac_base + MACBASE, gmac_base + DMABASE, DEFAULT_PHY_BASE); + synopGMAC_disable_interrupt_all(gmacdev); + + /* Reset MAC */ + synopGMAC_reset(gmacdev); + gmacdev->Intf = NUMAKER_GMAC_INTF; + synopGMAC_read_version(gmacdev); + + /* Check for Phy initialization */ + synopGMAC_set_mdc_clk_div(gmacdev, GmiiCsrClk5); + gmacdev->ClockDivMdc = synopGMAC_get_mdc_clk_div(gmacdev); + + /* Reset PHY */ + status = reset_phy(gmacdev); + + /* Set up the tx and rx descriptor queue/ring */ + synopGMAC_setup_tx_desc_queue(gmacdev, TRANSMIT_DESC_SIZE, RINGMODE); + synopGMAC_init_tx_desc_base(gmacdev); + + synopGMAC_setup_rx_desc_queue(gmacdev, RECEIVE_DESC_SIZE, RINGMODE); + synopGMAC_init_rx_desc_base(gmacdev); + + /* Initialize the dma interface */ + synopGMAC_dma_bus_mode_init(gmacdev, + DmaBurstLength32 | DmaDescriptorSkip0 | DmaDescriptor8Words); + synopGMAC_dma_control_init(gmacdev, + DmaStoreAndForward | DmaTxSecondFrame | DmaRxThreshCtrl128); + + /* Initialize the mac interface */ + synopGMAC_mac_init(gmacdev); + synopGMAC_promisc_enable(gmacdev); + + /* This enables the pause control in Full duplex mode of operation */ + synopGMAC_pause_control(gmacdev); + +#if defined(NU_USING_HW_CHECKSUM) + /*IPC Checksum offloading is enabled for this driver. Should only be used if + * Full Ip checksumm offload engine is configured in the hardware + */ + offload_needed = 1; + + /* Enable the offload engine in the receive path */ + synopGMAC_enable_rx_chksum_offload(gmacdev); + + /* Default configuration, DMA drops the packets if error in encapsulated ethernet payload */ + synopGMAC_rx_tcpip_chksum_drop_enable(gmacdev); +#endif + + for (i = 0; i < RECEIVE_DESC_SIZE; i++) { + skb = &rx_buf[NUMAKER_GMAC_INTF][i]; + synopGMAC_set_rx_qptr(gmacdev, (u32)((u64)(skb->data) & NUMAKER_MASK_32), + sizeof(skb->data), (u32)((u64)skb & NUMAKER_MASK_32)); + } + + for (i = 0; i < TRANSMIT_DESC_SIZE; i++) { + skb = &tx_buf[NUMAKER_GMAC_INTF][i]; + synopGMAC_set_tx_qptr(gmacdev, (u32)((u64)(skb->data) & NUMAKER_MASK_32), + sizeof(skb->data), (u32)((u64)skb & NUMAKER_MASK_32), + offload_needed, 0); + } + + synopGMAC_set_mac_address(NUMAKER_GMAC_INTF, mac_addr); + synopGMAC_clear_interrupt(gmacdev); + + return status; +} + +static int m_numaker_gmacdev_get_rx_buf(synopGMACdevice *gmacdev, uint16_t *len, uint8_t **buf) +{ + DmaDesc *rxdesc = gmacdev->RxBusyDesc; + + LOG_DBG("start"); + if (synopGMAC_is_desc_owned_by_dma(rxdesc)) { + return -EIO; + } + if (synopGMAC_is_desc_empty(rxdesc)) { + return -EIO; + } + + *len = synop_handle_received_data(NUMAKER_GMAC_INTF, buf); + if (*len <= 0) { + synopGMAC_enable_interrupt(gmacdev, DmaIntEnable); + return -ENOSPC; /* No available RX frame */ + } + + /* length of payload should be <= 1514 */ + if (*len > (NU_ETH_MAX_FLEN - 4)) { + LOG_DBG("unexpected long packet length=%d, buf=0x%x", *len, (uint32_t)*buf); + *len = 0; /* Skip this unexpected long packet */ + } + + LOG_DBG("end"); + return 0; +} + +static void m_numaker_gmacdev_rx_next(synopGMACdevice *gmacdev) +{ + LOG_DBG("RX Next"); + /* Already did in synop_handle_received_data + * No-op at this stage + * DmaDesc * rxdesc = (gmacdev->RxBusyDesc - 1); + * rxdesc->status = DescOwnByDma; + */ +} + +static void m_numaker_gmacdev_trigger_rx(synopGMACdevice *gmacdev) +{ + LOG_DBG("start"); + + /* Enable the interrupt */ + synopGMAC_enable_interrupt(gmacdev, DmaIntEnable); + + /* Trigger RX DMA */ + synopGMAC_enable_dma_rx(gmacdev); + synopGMAC_resume_dma_rx(gmacdev); + LOG_DBG("resume RX DMA"); + LOG_DBG("end"); +} + +static void m_numaker_gmacdev_packet_rx(const struct device *dev) +{ + struct eth_numaker_data *data = dev->data; + synopGMACdevice *gmacdev = data->gmacdev; + uint8_t *buffer; + uint16_t len; + struct net_pkt *pkt; + k_spinlock_key_t key; + int res; + + /* Get exclusive access, use spin-lock instead of mutex in ISR */ + key = k_spin_lock(&data->rx_frame_buf_lock); + + /* Two approach: 1. recv all RX packets in one time. + * 2. recv one RX and set pending interrupt for rx-next. + */ + while (1) { + /* get received frame */ + if (m_numaker_gmacdev_get_rx_buf(gmacdev, &len, &buffer) != 0) { + break; + } + + if (len == 0) { + LOG_WRN("No available RX frame"); + break; + } + /* Allocate a memory buffer chain from buffer pool + * Using root iface. It will be updated in net_recv_data() + */ + pkt = net_pkt_rx_alloc_with_buffer(data->iface, len, AF_UNSPEC, 0, K_NO_WAIT); + if (!pkt) { + LOG_ERR("pkt alloc frame-len=%d failed", len); + goto next; + } + + LOG_DBG("length=%d, pkt=0x%x", len, (uint32_t)pkt); + /* deliver RX packet to upper layer, pack as one net_pkt */ + if (net_pkt_write(pkt, buffer, len)) { + LOG_ERR("Unable to write RX frame into the pkt"); + net_pkt_unref(pkt); + goto error; + } + + if (pkt != NULL) { + res = net_recv_data(data->iface, pkt); + if (res < 0) { + LOG_ERR("net_recv_data: %d", res); + net_pkt_unref(pkt); + goto error; + } + } +next: + m_numaker_gmacdev_rx_next(gmacdev); + } + m_numaker_gmacdev_trigger_rx(gmacdev); + +error: + k_spin_unlock(&data->rx_frame_buf_lock, key); +} + +static uint8_t *m_numaker_gmacdev_get_tx_buf(synopGMACdevice *gmacdev) +{ + DmaDesc *txdesc = gmacdev->TxNextDesc; + + if (!synopGMAC_is_desc_empty(txdesc)) { + return NULL; + } + + if (synopGMAC_is_desc_owned_by_dma(txdesc)) { + return NULL; + } + + return (uint8_t *)(txdesc->buffer1); +} + +static void m_numaker_gmacdev_trigger_tx(synopGMACdevice *gmacdev, uint16_t length) +{ + DmaDesc *txdesc = gmacdev->TxNextDesc; + uint32_t txnext = gmacdev->TxNext; + bool offload_needed = IS_ENABLED(NU_USING_HW_CHECKSUM); + + /* busy tx descriptor is incremented by one as it will be handed over to DMA */ + (gmacdev->BusyTxDesc)++; + + txdesc->length |= ((length << DescSize1Shift) & DescSize1Mask); + txdesc->status |= (DescTxFirst | DescTxLast | DescTxIntEnable); + if (offload_needed) { + /* + * Make sure that the OS you are running supports the IP and TCP checksum + * offloading, before calling any of the functions given below. + */ + synopGMAC_tx_checksum_offload_tcp_pseudo(gmacdev, txdesc); + } else { + synopGMAC_tx_checksum_offload_bypass(gmacdev, txdesc); + } + __DSB(); + txdesc->status |= DescOwnByDma; + + gmacdev->TxNext = synopGMAC_is_last_tx_desc(gmacdev, txdesc) ? 0 : txnext + 1; + gmacdev->TxNextDesc = + synopGMAC_is_last_tx_desc(gmacdev, txdesc) ? gmacdev->TxDesc : (txdesc + 1); + + /* Enable the interrupt */ + synopGMAC_enable_interrupt(gmacdev, DmaIntEnable); + /* Trigger TX DMA */ + synopGMAC_resume_dma_tx(gmacdev); +} + +static int numaker_eth_tx(const struct device *dev, struct net_pkt *pkt) +{ + struct eth_numaker_data *data = dev->data; + synopGMACdevice *gmacdev = data->gmacdev; + uint16_t total_len = net_pkt_get_len(pkt); + uint8_t *buffer; + + /* Get exclusive access */ + k_mutex_lock(&data->tx_frame_buf_mutex, K_FOREVER); + if (total_len > NET_ETH_MAX_FRAME_SIZE) { + /* NuMaker SDK reserve 2048 for tx_buf */ + LOG_ERR("TX packet length [%d] over max [%d]", total_len, NET_ETH_MAX_FRAME_SIZE); + goto error; + } + + buffer = m_numaker_gmacdev_get_tx_buf(gmacdev); + LOG_DBG("buffer=0x%x", (uint32_t)buffer); + if (buffer == NULL) { + goto error; + } + + if (net_pkt_read(pkt, buffer, total_len)) { + goto error; + } + + /* Prepare transmit descriptors to give to DMA */ + m_numaker_gmacdev_trigger_tx(gmacdev, total_len); + + k_mutex_unlock(&data->tx_frame_buf_mutex); + + return 0; + +error: + LOG_ERR("Writing pkt to TX descriptor failed"); + k_mutex_unlock(&data->tx_frame_buf_mutex); + return -EIO; +} + +static void numaker_eth_if_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct eth_numaker_data *data = dev->data; + + synopGMACdevice *gmacdev = data->gmacdev; + + LOG_DBG("eth_if_init"); + + /* Read mac address */ + m_numaker_read_mac_addr(data->mac_addr); + + net_if_set_link_addr(iface, data->mac_addr, sizeof(data->mac_addr), NET_LINK_ETHERNET); + data->iface = iface; + ethernet_init(iface); + + /* Enable GMAC device INT & TX/RX */ + m_numaker_gmacdev_enable(gmacdev); +} + +static int numaker_eth_set_config(const struct device *dev, enum ethernet_config_type type, + const struct ethernet_config *config) +{ + struct eth_numaker_data *data = dev->data; + + switch (type) { + case ETHERNET_CONFIG_TYPE_MAC_ADDRESS: + memcpy(data->mac_addr, config->mac_address.addr, sizeof(data->mac_addr)); + synopGMAC_set_mac_address(NUMAKER_GMAC_INTF, 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: + return -ENOTSUP; + } +} + +static enum ethernet_hw_caps numaker_eth_get_cap(const struct device *dev) +{ + ARG_UNUSED(dev); +#if defined(NU_USING_HW_CHECKSUM) + return ETHERNET_LINK_10BASE_T | ETHERNET_LINK_100BASE_T | ETHERNET_HW_RX_CHKSUM_OFFLOAD; +#else + return ETHERNET_LINK_10BASE_T | ETHERNET_LINK_100BASE_T; +#endif +} + +static const struct ethernet_api eth_numaker_driver_api = { + .iface_api.init = numaker_eth_if_init, + .get_capabilities = numaker_eth_get_cap, + .set_config = numaker_eth_set_config, + .send = numaker_eth_tx, +}; + +/* EMAC IRQ Handler */ +static void eth_numaker_isr(const struct device *dev) +{ + struct eth_numaker_data *data = dev->data; + synopGMACdevice *gmacdev = data->gmacdev; + uint32_t interrupt; + uint32_t dma_status_reg; + uint32_t mac_status_reg; + int status; + uint32_t dma_ie = DmaIntEnable; + + uint32_t volatile reg; + + /* Check GMAC interrupt */ + mac_status_reg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacInterruptStatus); + if (mac_status_reg & GmacTSIntSts) { + gmacdev->synopGMACNetStats.ts_int = 1; + status = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacTSStatus); + if (!(status & BIT(1))) { + LOG_WRN("TS alarm flag not set??"); + } else { + LOG_DBG("TS alarm"); + } + } + + if (mac_status_reg & GmacLPIIntSts) { + LOG_DBG("LPI"); + } + + if (mac_status_reg & GmacRgmiiIntSts) { + reg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacRgmiiCtrlSts); + } + + synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacInterruptStatus, mac_status_reg); + /* Read the Dma interrupt status to know whether the interrupt got generated by + * our device or not + */ + dma_status_reg = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaStatus); + LOG_DBG("i %08x %08x", mac_status_reg, dma_status_reg); + + if (dma_status_reg == 0) { + return; + } + + synopGMAC_disable_interrupt_all(gmacdev); + LOG_DBG("Dma Status Reg: 0x%08x", dma_status_reg); + if (dma_status_reg & GmacPmtIntr) { + LOG_DBG("Interrupt due to PMT module"); + synopGMAC_powerup_mac(gmacdev); + } + + if (dma_status_reg & GmacLineIntfIntr) { + LOG_DBG("Interrupt due to GMAC LINE module"); + } + + /* Now lets handle the DMA interrupts */ + interrupt = synopGMAC_get_interrupt_type(gmacdev); + LOG_DBG("Interrupts to be handled: 0x%08x", interrupt); + if (interrupt & synopGMACDmaError) { + LOG_DBG("Fatal Bus Error Interrupt Seen"); + synopGMAC_disable_dma_tx(gmacdev); + synopGMAC_disable_dma_rx(gmacdev); + + synopGMAC_take_desc_ownership_tx(gmacdev); + synopGMAC_take_desc_ownership_rx(gmacdev); + + synopGMAC_init_tx_rx_desc_queue(gmacdev); + + synopGMAC_reset(gmacdev); /* reset the DMA engine and the GMAC ip */ + synopGMAC_set_mac_address(NUMAKER_GMAC_INTF, data->mac_addr); + synopGMAC_dma_bus_mode_init(gmacdev, DmaFixedBurstEnable | DmaBurstLength8 | + DmaDescriptorSkip0); + synopGMAC_dma_control_init(gmacdev, DmaStoreAndForward); + synopGMAC_init_rx_desc_base(gmacdev); + synopGMAC_init_tx_desc_base(gmacdev); + synopGMAC_mac_init(gmacdev); + synopGMAC_enable_dma_rx(gmacdev); + synopGMAC_enable_dma_tx(gmacdev); + } + + if (interrupt & synopGMACDmaRxNormal) { + LOG_DBG("Rx Normal"); + /* disable RX interrupt */ + dma_ie &= ~DmaIntRxNormMask; + /* to handle received data */ + m_numaker_gmacdev_packet_rx(dev); + } + + if (interrupt & synopGMACDmaRxAbnormal) { + LOG_ERR("Abnormal Rx Interrupt Seen"); + /* If Mac is not in powerdown */ + if (gmacdev->GMAC_Power_down == 0) { + gmacdev->synopGMACNetStats.rx_over_errors++; + dma_ie &= ~DmaIntRxAbnMask; + /* To handle GBPS with 12 descriptors. */ + synopGMAC_resume_dma_rx(gmacdev); + } + } + + /* Receiver gone in to stopped state */ + if (interrupt & synopGMACDmaRxStopped) { + LOG_ERR("Receiver stopped seeing Rx interrupts"); + if (gmacdev->GMAC_Power_down == 0) { + gmacdev->synopGMACNetStats.rx_over_errors++; + synopGMAC_enable_dma_rx(gmacdev); + } + } + + if (interrupt & synopGMACDmaTxNormal) { + LOG_DBG("Finished Normal Transmission"); + synop_handle_transmit_over(0); + /* No-op at this stage for TX INT */ + } + + if (interrupt & synopGMACDmaTxAbnormal) { + LOG_ERR("Abnormal Tx Interrupt Seen"); + if (gmacdev->GMAC_Power_down == 0) { + synop_handle_transmit_over(0); + /* No-op at this stage for TX INT */ + } + } + + if (interrupt & synopGMACDmaTxStopped) { + LOG_ERR("Transmitter stopped sending the packets"); + if (gmacdev->GMAC_Power_down == 0) { + synopGMAC_disable_dma_tx(gmacdev); + synopGMAC_take_desc_ownership_tx(gmacdev); + synopGMAC_enable_dma_tx(gmacdev); + LOG_ERR("Transmission Resumed"); + } + } + + /* Enable the interrupt before returning from ISR*/ + synopGMAC_enable_interrupt(gmacdev, dma_ie); +} + +/* Declare pin-ctrl __pinctrl_dev_config__device_dts_ord_xx before + * PINCTRL_DT_INST_DEV_CONFIG_GET() + */ +PINCTRL_DT_INST_DEFINE(0); + +static int eth_numaker_init(const struct device *dev) +{ + const struct eth_numaker_config *cfg = dev->config; + struct eth_numaker_data *data = dev->data; + synopGMACdevice *gmacdev; + + /* Init MAC Address based on UUID*/ + uint8_t mac_addr[NU_HWADDR_SIZE]; + int ret = 0; + struct numaker_scc_subsys scc_subsys; + + gmacdev = &GMACdev[NUMAKER_GMAC_INTF]; + data->gmacdev = gmacdev; + + k_mutex_init(&data->tx_frame_buf_mutex); + + eth_phy_addr = cfg->phy_addr; + + /* 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() */ + ret = clock_control_on(cfg->clk_dev, (clock_control_subsys_t)&scc_subsys); + if (ret != 0) { + goto done; + } + + /* For EMAC, not need CLK_SetModuleClock() + * Validate this module's reset object + */ + if (!device_is_ready(cfg->reset.dev)) { + LOG_ERR("reset controller not ready"); + return -ENODEV; + } + + SYS_UnlockReg(); + + irq_disable(DT_INST_IRQN(0)); + ret = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT); + if (ret != 0) { + LOG_ERR("Failed to apply pinctrl state"); + goto done; + } + + /* Reset EMAC to default state, same as BSP's SYS_ResetModule(id_rst) */ + reset_line_toggle_dt(&cfg->reset); + + /* Read mac address */ + m_numaker_read_mac_addr(mac_addr); + + /* Configure GMAC device */ + ret = m_numaker_gmacdev_init(gmacdev, mac_addr, cfg->gmac_base); + if (ret != 0) { + LOG_ERR("GMAC failed to initialize"); + goto done; + } + + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), eth_numaker_isr, + DEVICE_DT_INST_GET(0), 0); + + irq_enable(DT_INST_IRQN(0)); + +done: + SYS_LockReg(); + return ret; +} + +static struct eth_numaker_data eth_numaker_data_inst; + +/* Set config based on DTS */ +static struct eth_numaker_config eth_numaker_cfg_inst = { + .gmac_base = (uint32_t)DT_INST_REG_ADDR(0), + .reset = RESET_DT_SPEC_INST_GET(0), + .phy_addr = DT_INST_PROP(0, phy_addr), + .clk_modidx = DT_INST_CLOCKS_CELL(0, clock_module_index), + .clk_src = DT_INST_CLOCKS_CELL(0, clock_source), + .clk_div = DT_INST_CLOCKS_CELL(0, clock_divider), + .clk_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(0))), + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), + .reset = RESET_DT_SPEC_INST_GET(0), +}; + +ETH_NET_DEVICE_DT_INST_DEFINE(0, eth_numaker_init, NULL, ð_numaker_data_inst, + ð_numaker_cfg_inst, CONFIG_ETH_INIT_PRIORITY, + ð_numaker_driver_api, NET_ETH_MTU); diff --git a/drivers/ethernet/eth_numaker_priv.h b/drivers/ethernet/eth_numaker_priv.h new file mode 100644 index 000000000000000..e3bec804b9808e4 --- /dev/null +++ b/drivers/ethernet/eth_numaker_priv.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_ETHERNET_ETH_NUMAKER_PRIV_H_ +#define ZEPHYR_DRIVERS_ETHERNET_ETH_NUMAKER_PRIV_H_ + +#include + +#define NU_ETH_MAX_FLEN (1518) + +#define NU_HWADDR_SIZE (6) + +#define NU_ETH_MTU_SIZE 1500 + +#endif /* ZEPHYR_DRIVERS_ETHERNET_ETH_NUMAKER_PRIV_H_ */ diff --git a/drivers/ethernet/eth_nxp_enet.c b/drivers/ethernet/eth_nxp_enet.c new file mode 100644 index 000000000000000..244867dddf6977c --- /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 423f2b1499e1a13..71e3e94c176253b 100644 --- a/drivers/ethernet/eth_nxp_s32_gmac.c +++ b/drivers/ethernet/eth_nxp_s32_gmac.c @@ -78,7 +78,7 @@ static inline struct net_if *get_iface(struct eth_nxp_s32_data *ctx, uint16_t vl #endif } -#if defined(CONFIG_SOC_PART_NUMBER_S32K3) +#if defined(CONFIG_SOC_SERIES_S32K3XX) static int select_phy_interface(Gmac_Ip_MiiModeType mode) { uint32_t regval; @@ -105,7 +105,7 @@ static int select_phy_interface(Gmac_Ip_MiiModeType mode) } #else #error "SoC not supported" -#endif /* CONFIG_SOC_PART_NUMBER_S32K3 */ +#endif /* CONFIG_SOC_SERIES_S32K3XX */ static int eth_nxp_s32_init(const struct device *dev) { @@ -564,7 +564,7 @@ BUILD_ASSERT((CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE % FEATURE_GMAC_DATA_BUS_WIDTH_ #define ETH_NXP_S32_MAC_SPEED(n) \ COND_CODE_1(ETH_NXP_S32_IS_FIXED_LINK(n), \ - (CONCAT(CONCAT(GMAC_SPEED_, ETH_NXP_S32_FIXED_LINK_SPEED(n)), M)), \ + (_CONCAT(_CONCAT(GMAC_SPEED_, ETH_NXP_S32_FIXED_LINK_SPEED(n)), M)), \ (GMAC_SPEED_100M)) #define ETH_NXP_S32_MAC_DUPLEX(n) \ @@ -574,7 +574,7 @@ BUILD_ASSERT((CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE % FEATURE_GMAC_DATA_BUS_WIDTH_ (GMAC_FULL_DUPLEX)) #define ETH_NXP_S32_MAC_MII(n) \ - CONCAT(CONCAT(GMAC_, DT_INST_STRING_UPPER_TOKEN(n, phy_connection_type)), _MODE) + _CONCAT(_CONCAT(GMAC_, DT_INST_STRING_UPPER_TOKEN(n, phy_connection_type)), _MODE) #define ETH_NXP_S32_IRQ_INIT(n, name) \ IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, name, irq), \ diff --git a/drivers/ethernet/eth_nxp_s32_netc.c b/drivers/ethernet/eth_nxp_s32_netc.c index c452a4b398ffd29..f5a3994a9c4cb69 100644 --- a/drivers/ethernet/eth_nxp_s32_netc.c +++ b/drivers/ethernet/eth_nxp_s32_netc.c @@ -18,7 +18,7 @@ LOG_MODULE_REGISTER(nxp_s32_eth); #include #include -#include +#include #include #include #include diff --git a/drivers/ethernet/eth_nxp_s32_netc_priv.h b/drivers/ethernet/eth_nxp_s32_netc_priv.h index c4948af3d53c2c3..4a3496ee58b461b 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 f35eb73ba283a3f..977825ddd7abbb8 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); @@ -18,7 +20,7 @@ LOG_MODULE_REGISTER(nxp_s32_eth_psi); #include #include -#include +#include #include #include #include @@ -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 b262250c226fa12..0847db8148cddca 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); @@ -18,7 +20,7 @@ LOG_MODULE_REGISTER(nxp_s32_eth_vsi); #include #include -#include +#include #include #include #include @@ -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 dec6ea6df20de09..80d43f3616c169d 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 755134359ebee2c..1808b59f23ba8c3 100644 --- a/drivers/ethernet/eth_stm32_hal.c +++ b/drivers/ethernet/eth_stm32_hal.c @@ -33,6 +33,10 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include +#if defined(CONFIG_NET_DSA) +#include +#endif + #if defined(CONFIG_PTP_CLOCK_STM32_HAL) #include #endif /* CONFIG_PTP_CLOCK_STM32_HAL */ @@ -80,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) @@ -867,6 +871,7 @@ static void rx_thread(void *arg1, void *unused1, void *unused2) uint16_t vlan_tag = NET_VLAN_TAG_UNSPEC; const struct device *dev; struct eth_stm32_hal_dev_data *dev_data; + struct net_if *iface; struct net_pkt *pkt; int res; uint32_t status; @@ -892,7 +897,11 @@ static void rx_thread(void *arg1, void *unused1, void *unused2) vlan_tag)); } while ((pkt = eth_rx(dev, &vlan_tag)) != NULL) { - res = net_recv_data(net_pkt_iface(pkt), pkt); + iface = net_pkt_iface(pkt); +#if defined(CONFIG_NET_DSA) + iface = dsa_net_recv(iface, &pkt); +#endif + res = net_recv_data(iface, pkt); if (res < 0) { eth_stats_update_errors_rx( net_pkt_iface(pkt)); @@ -1516,6 +1525,10 @@ static void eth_iface_init(struct net_if *iface) sizeof(dev_data->mac_addr), NET_LINK_ETHERNET); +#if defined(CONFIG_NET_DSA) + dsa_register_master_tx(iface, ð_tx); +#endif + ethernet_init(iface); net_if_carrier_off(iface); @@ -1559,6 +1572,9 @@ static enum ethernet_hw_caps eth_stm32_hal_get_capabilities(const struct device #if defined(CONFIG_ETH_STM32_HW_CHECKSUM) | ETHERNET_HW_RX_CHKSUM_OFFLOAD | ETHERNET_HW_TX_CHKSUM_OFFLOAD +#endif +#if defined(CONFIG_NET_DSA) + | ETHERNET_DSA_MASTER_PORT #endif ; } @@ -1638,7 +1654,11 @@ static const struct ethernet_api eth_api = { #endif /* CONFIG_PTP_CLOCK_STM32_HAL */ .get_capabilities = eth_stm32_hal_get_capabilities, .set_config = eth_stm32_hal_set_config, +#if defined(CONFIG_NET_DSA) + .send = dsa_tx, +#else .send = eth_tx, +#endif #if defined(CONFIG_NET_STATISTICS_ETHERNET) .get_stats = eth_stm32_hal_get_stats, #endif /* CONFIG_NET_STATISTICS_ETHERNET */ diff --git a/drivers/ethernet/eth_w5500.c b/drivers/ethernet/eth_w5500.c index 03b5cb752d167d7..88a2d710b72600b 100644 --- a/drivers/ethernet/eth_w5500.c +++ b/drivers/ethernet/eth_w5500.c @@ -275,8 +275,12 @@ static void w5500_rx(const struct device *dev) w5500_command(dev, S0_CR_RECV); } -static void w5500_thread(const struct device *dev) +static void w5500_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; uint8_t ir; struct w5500_runtime *ctx = dev->data; const struct w5500_config *config = dev->config; @@ -557,7 +561,7 @@ static int w5500_init(const struct device *dev) k_thread_create(&ctx->thread, ctx->thread_stack, CONFIG_ETH_W5500_RX_THREAD_STACK_SIZE, - (k_thread_entry_t)w5500_thread, + w5500_thread, (void *)dev, NULL, NULL, K_PRIO_COOP(CONFIG_ETH_W5500_RX_THREAD_PRIO), 0, K_NO_WAIT); diff --git a/drivers/ethernet/eth_xmc4xxx.c b/drivers/ethernet/eth_xmc4xxx.c new file mode 100644 index 000000000000000..ad2cee470f2d3d8 --- /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 new file mode 100644 index 000000000000000..2b1e017f0073ef1 --- /dev/null +++ b/drivers/ethernet/oa_tc6.c @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2023 DENX Software Engineering GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "oa_tc6.h" + +#include +LOG_MODULE_REGISTER(oa_tc6, CONFIG_ETHERNET_LOG_LEVEL); + +int oa_tc6_reg_read(struct oa_tc6 *tc6, const uint32_t reg, uint32_t *val) +{ + uint8_t buf[OA_TC6_HDR_SIZE + 12] = { 0 }; + struct spi_buf tx_buf = { .buf = buf, .len = sizeof(buf) }; + const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 }; + struct spi_buf rx_buf = { .buf = buf, .len = sizeof(buf) }; + const struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1 }; + uint32_t rv, rvn, hdr_bkp, *hdr = (uint32_t *) &buf[0]; + int ret = 0; + + /* + * Buffers are allocated for protected (larger) case (by 4 bytes). + * When non-protected case - we need to decrase them + */ + if (!tc6->protected) { + tx_buf.len -= sizeof(rvn); + rx_buf.len -= sizeof(rvn); + } + + *hdr = FIELD_PREP(OA_CTRL_HDR_DNC, 0) | + FIELD_PREP(OA_CTRL_HDR_WNR, 0) | + FIELD_PREP(OA_CTRL_HDR_AID, 0) | + FIELD_PREP(OA_CTRL_HDR_MMS, reg >> 16) | + FIELD_PREP(OA_CTRL_HDR_ADDR, reg) | + FIELD_PREP(OA_CTRL_HDR_LEN, 0); /* To read single register len = 0 */ + *hdr |= FIELD_PREP(OA_CTRL_HDR_P, oa_tc6_get_parity(*hdr)); + hdr_bkp = *hdr; + *hdr = sys_cpu_to_be32(*hdr); + + ret = spi_transceive_dt(tc6->spi, &tx, &rx); + if (ret < 0) { + return ret; + } + + /* Check if echoed control command header is correct */ + rv = sys_be32_to_cpu(*(uint32_t *)&buf[4]); + if (hdr_bkp != rv) { + LOG_ERR("Header transmission error!"); + return -1; + } + + rv = sys_be32_to_cpu(*(uint32_t *)&buf[8]); + + /* In protected mode read data is followed by its compliment value */ + if (tc6->protected) { + rvn = sys_be32_to_cpu(*(uint32_t *)&buf[12]); + if (rv != ~rvn) { + LOG_ERR("Protected mode transmission error!"); + return -1; + } + } + + *val = rv; + + return ret; +} + +int oa_tc6_reg_write(struct oa_tc6 *tc6, const uint32_t reg, uint32_t val) +{ + uint8_t buf_tx[OA_TC6_HDR_SIZE + 12] = { 0 }; + uint8_t buf_rx[OA_TC6_HDR_SIZE + 12] = { 0 }; + struct spi_buf tx_buf = { .buf = buf_tx, .len = sizeof(buf_tx) }; + const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 }; + struct spi_buf rx_buf = { .buf = buf_rx, .len = sizeof(buf_rx) }; + const struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1 }; + uint32_t rv, rvn, hdr_bkp, *hdr = (uint32_t *) &buf_tx[0]; + int ret; + + /* + * Buffers are allocated for protected (larger) case (by 4 bytes). + * When non-protected case - we need to decrase them + */ + if (!tc6->protected) { + tx_buf.len -= sizeof(rvn); + rx_buf.len -= sizeof(rvn); + } + + *hdr = FIELD_PREP(OA_CTRL_HDR_DNC, 0) | + FIELD_PREP(OA_CTRL_HDR_WNR, 1) | + FIELD_PREP(OA_CTRL_HDR_AID, 0) | + FIELD_PREP(OA_CTRL_HDR_MMS, reg >> 16) | + FIELD_PREP(OA_CTRL_HDR_ADDR, reg) | + FIELD_PREP(OA_CTRL_HDR_LEN, 0); /* To read single register len = 0 */ + *hdr |= FIELD_PREP(OA_CTRL_HDR_P, oa_tc6_get_parity(*hdr)); + hdr_bkp = *hdr; + *hdr = sys_cpu_to_be32(*hdr); + + *(uint32_t *)&buf_tx[4] = sys_cpu_to_be32(val); + if (tc6->protected) { + *(uint32_t *)&buf_tx[8] = sys_be32_to_cpu(~val); + } + + ret = spi_transceive_dt(tc6->spi, &tx, &rx); + if (ret < 0) { + return ret; + } + + /* Check if echoed control command header is correct */ + rv = sys_be32_to_cpu(*(uint32_t *)&buf_rx[4]); + if (hdr_bkp != rv) { + LOG_ERR("Header transmission error!"); + return -1; + } + + /* Check if echoed value is correct */ + rv = sys_be32_to_cpu(*(uint32_t *)&buf_rx[8]); + if (val != rv) { + LOG_ERR("Header transmission error!"); + return -1; + } + + /* + * In protected mode check if read value is followed by its + * compliment value + */ + if (tc6->protected) { + rvn = sys_be32_to_cpu(*(uint32_t *)&buf_rx[12]); + if (val != ~rvn) { + LOG_ERR("Protected mode transmission error!"); + return -1; + } + } + + return ret; +} + +int oa_tc6_reg_rmw(struct oa_tc6 *tc6, const uint32_t reg, + uint32_t mask, uint32_t val) +{ + uint32_t tmp; + int ret; + + ret = oa_tc6_reg_read(tc6, reg, &tmp); + if (ret < 0) { + return ret; + } + + tmp &= ~mask; + + if (val) { + tmp |= 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; + } + + tc6->protected = prote; + return 0; +} + +int oa_tc6_send_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) +{ + uint16_t len = net_pkt_get_len(pkt); + uint8_t oa_tx[tc6->cps]; + uint32_t hdr, ftr; + uint8_t chunks, i; + int ret; + + 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) { + return -EIO; + } + + /* Transform struct net_pkt content into chunks */ + for (i = 1; i <= chunks; i++) { + hdr = FIELD_PREP(OA_DATA_HDR_DNC, 1) | + FIELD_PREP(OA_DATA_HDR_DV, 1) | + FIELD_PREP(OA_DATA_HDR_NORX, 1) | + FIELD_PREP(OA_DATA_HDR_SWO, 0); + + if (i == 1) { + hdr |= FIELD_PREP(OA_DATA_HDR_SV, 1); + } + + if (i == chunks) { + hdr |= FIELD_PREP(OA_DATA_HDR_EBO, len - 1) | + FIELD_PREP(OA_DATA_HDR_EV, 1); + } + + hdr |= FIELD_PREP(OA_DATA_HDR_P, oa_tc6_get_parity(hdr)); + + ret = net_pkt_read(pkt, oa_tx, len > tc6->cps ? tc6->cps : len); + if (ret < 0) { + return ret; + } + + ret = oa_tc6_chunk_spi_transfer(tc6, NULL, oa_tx, hdr, &ftr); + if (ret < 0) { + return ret; + } + + len -= tc6->cps; + } + + return 0; +} + +int oa_tc6_check_status(struct oa_tc6 *tc6) +{ + 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; +} + +static int oa_tc6_update_status(struct oa_tc6 *tc6, uint32_t ftr) +{ + if (oa_tc6_get_parity(ftr)) { + LOG_DBG("OA Status Update: Footer parity error!"); + return -EIO; + } + + 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; +} + +int oa_tc6_chunk_spi_transfer(struct oa_tc6 *tc6, uint8_t *buf_rx, uint8_t *buf_tx, + uint32_t hdr, uint32_t *ftr) +{ + struct spi_buf tx_buf[2]; + struct spi_buf rx_buf[2]; + struct spi_buf_set tx; + struct spi_buf_set rx; + int ret; + + hdr = sys_cpu_to_be32(hdr); + tx_buf[0].buf = &hdr; + tx_buf[0].len = sizeof(hdr); + + tx_buf[1].buf = buf_tx; + tx_buf[1].len = tc6->cps; + + tx.buffers = tx_buf; + tx.count = ARRAY_SIZE(tx_buf); + + rx_buf[0].buf = buf_rx; + rx_buf[0].len = tc6->cps; + + rx_buf[1].buf = ftr; + rx_buf[1].len = sizeof(*ftr); + + rx.buffers = rx_buf; + rx.count = ARRAY_SIZE(rx_buf); + + ret = spi_transceive_dt(tc6->spi, &tx, &rx); + if (ret < 0) { + return ret; + } + *ftr = sys_be32_to_cpu(*ftr); + + return oa_tc6_update_status(tc6, *ftr); +} + +int oa_tc6_read_status(struct oa_tc6 *tc6, uint32_t *ftr) +{ + uint32_t hdr; + + hdr = FIELD_PREP(OA_DATA_HDR_DNC, 1) | + FIELD_PREP(OA_DATA_HDR_DV, 0) | + FIELD_PREP(OA_DATA_HDR_NORX, 1); + hdr |= FIELD_PREP(OA_DATA_HDR_P, oa_tc6_get_parity(hdr)); + + return oa_tc6_chunk_spi_transfer(tc6, NULL, NULL, hdr, ftr); +} + +int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) +{ + struct net_buf *buf_rx = NULL; + uint32_t hdr, ftr; + uint8_t sbo, ebo; + int ret; + + /* + * Special case - append already received data (extracted from previous + * chunk) to new packet. + */ + if (tc6->concat_buf) { + net_pkt_append_buffer(pkt, tc6->concat_buf); + tc6->concat_buf = NULL; + } + + 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!"); + return -ENOMEM; + } + + hdr = FIELD_PREP(OA_DATA_HDR_DNC, 1); + hdr |= FIELD_PREP(OA_DATA_HDR_P, oa_tc6_get_parity(hdr)); + + ret = oa_tc6_chunk_spi_transfer(tc6, buf_rx->data, NULL, hdr, &ftr); + if (ret < 0) { + LOG_ERR("OA RX: transmission error: %d!", ret); + goto unref_buf; + } + + ret = -EIO; + if (oa_tc6_get_parity(ftr)) { + LOG_ERR("OA RX: Footer parity error!"); + goto unref_buf; + } + + if (!FIELD_GET(OA_DATA_FTR_SYNC, ftr)) { + LOG_ERR("OA RX: Configuration not SYNC'ed!"); + goto unref_buf; + } + + if (!FIELD_GET(OA_DATA_FTR_DV, ftr)) { + LOG_DBG("OA RX: Data chunk not valid, skip!"); + goto unref_buf; + } + + sbo = FIELD_GET(OA_DATA_FTR_SWO, ftr) * sizeof(uint32_t); + ebo = FIELD_GET(OA_DATA_FTR_EBO, ftr) + 1; + + if (FIELD_GET(OA_DATA_FTR_SV, ftr)) { + /* + * Adjust beginning of the buffer with SWO only when + * we DO NOT have two frames concatenated together + * in one chunk. + */ + if (!(FIELD_GET(OA_DATA_FTR_EV, ftr) && (ebo <= sbo))) { + if (sbo) { + net_buf_pull(buf_rx, sbo); + } + } + } + + net_pkt_append_buffer(pkt, buf_rx); + buf_rx->len = tc6->cps; + + if (FIELD_GET(OA_DATA_FTR_EV, ftr)) { + /* + * Check if received frame shall be dropped - i.e. MAC has + * detected error condition, which shall result in frame drop + * by the SPI host. + */ + if (FIELD_GET(OA_DATA_FTR_FD, ftr)) { + ret = -EIO; + goto unref_buf; + } + + /* + * Concatenation of frames in a single chunk - one frame ends + * and second one starts just afterwards (ebo == sbo). + */ + if (FIELD_GET(OA_DATA_FTR_SV, ftr) && (ebo <= sbo)) { + tc6->concat_buf = net_buf_clone(buf_rx, OA_TC6_BUF_ALLOC_TIMEOUT); + if (!tc6->concat_buf) { + LOG_ERR("OA RX: Can't allocate RX buffer for data!"); + ret = -ENOMEM; + goto unref_buf; + } + net_buf_pull(tc6->concat_buf, sbo); + } + + /* Set final size of the buffer */ + buf_rx->len = ebo; + /* + * Exit when complete packet is read and added to + * struct net_pkt + */ + break; + } + } while (tc6->rca > 0); + + return 0; + + unref_buf: + net_buf_unref(buf_rx); + return ret; +} diff --git a/drivers/ethernet/oa_tc6.h b/drivers/ethernet/oa_tc6.h new file mode 100644 index 000000000000000..0918e1382fa060f --- /dev/null +++ b/drivers/ethernet/oa_tc6.h @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2023 DENX Software Engineering GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef OA_TC6_CFG_H__ +#define OA_TC6_CFG_H__ + +#include +#include +#include +#include +#include +#include + +#define MMS_REG(m, r) ((((m) & GENMASK(3, 0)) << 16) | ((r) & GENMASK(15, 0))) +/* Memory Map Sector (MMS) 0 */ +#define OA_ID MMS_REG(0x0, 0x000) /* expect 0x11 */ +#define OA_PHYID MMS_REG(0x0, 0x001) +#define OA_RESET MMS_REG(0x0, 0x003) +#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) +#define OA_STATUS1 MMS_REG(0x0, 0x009) +#define OA_BUFSTS MMS_REG(0x0, 0x00B) +#define OA_BUFSTS_TXC GENMASK(15, 8) +#define OA_BUFSTS_RCA GENMASK(7, 0) +#define OA_IMASK0 MMS_REG(0x0, 0x00C) +#define OA_IMASK0_TXPEM BIT(0) +#define OA_IMASK0_TXBOEM BIT(1) +#define OA_IMASK0_TXBUEM BIT(2) +#define OA_IMASK0_RXBOEM BIT(3) +#define OA_IMASK0_LOFEM BIT(4) +#define OA_IMASK0_HDREM BIT(5) +#define OA_IMASK1 MMS_REG(0x0, 0x00D) +#define OA_IMASK0_UV18M BIT(19) + +/* OA Control header */ +#define OA_CTRL_HDR_DNC BIT(31) +#define OA_CTRL_HDR_HDRB BIT(30) +#define OA_CTRL_HDR_WNR BIT(29) +#define OA_CTRL_HDR_AID BIT(28) +#define OA_CTRL_HDR_MMS GENMASK(27, 24) +#define OA_CTRL_HDR_ADDR GENMASK(23, 8) +#define OA_CTRL_HDR_LEN GENMASK(7, 1) +#define OA_CTRL_HDR_P BIT(0) + +/* OA Data header */ +#define OA_DATA_HDR_DNC BIT(31) +#define OA_DATA_HDR_SEQ BIT(30) +#define OA_DATA_HDR_NORX BIT(29) +#define OA_DATA_HDR_DV BIT(21) +#define OA_DATA_HDR_SV BIT(20) +#define OA_DATA_HDR_SWO GENMASK(19, 16) +#define OA_DATA_HDR_EV BIT(14) +#define OA_DATA_HDR_EBO GENMASK(13, 8) +#define OA_DATA_HDR_P BIT(0) + +/* OA Data footer */ +#define OA_DATA_FTR_EXST BIT(31) +#define OA_DATA_FTR_HDRB BIT(30) +#define OA_DATA_FTR_SYNC BIT(29) +#define OA_DATA_FTR_RCA GENMASK(28, 24) +#define OA_DATA_FTR_DV BIT(21) +#define OA_DATA_FTR_SV BIT(20) +#define OA_DATA_FTR_SWO GENMASK(19, 16) +#define OA_DATA_FTR_FD BIT(15) +#define OA_DATA_FTR_EV BIT(14) +#define OA_DATA_FTR_EBO GENMASK(13, 8) +#define OA_DATA_FTR_TXC GENMASK(5, 1) +#define OA_DATA_FTR_P BIT(0) + +#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. + */ +struct oa_tc6 { + /** Pointer to SPI device */ + const struct spi_dt_spec *spi; + + /** OA data payload (chunk) size */ + uint8_t cps; + + /** + * Number of available chunks buffers in OA TC6 device to store + * data for transmission + */ + uint8_t txc; + + /** Number of available chunks to read from OA TC6 device */ + uint8_t rca; + + /** Indication of pending interrupt in OA TC6 device */ + bool exst; + + /** Indication of OA TC6 device being ready for transmission */ + bool sync; + + /** Indication of protected control transmission mode */ + bool protected; + + /** Pointer to network buffer concatenated from received chunk */ + struct net_buf *concat_buf; +}; + +typedef struct { + uint32_t address; + uint32_t value; +} oa_mem_map_t; + +/** + * @brief Calculate parity bit from data + * + * @param x data to calculate parity + * + * @return 0 if number of ones is odd, 1 otherwise. + */ +static inline bool oa_tc6_get_parity(const uint32_t x) +{ + uint32_t y; + + y = x ^ (x >> 1); + y = y ^ (y >> 2); + y = y ^ (y >> 4); + y = y ^ (y >> 8); + y = y ^ (y >> 16); + + return !(y & 1); +} + +/** + * @brief Read OA TC6 compliant device single register + * + * @param tc6 OA TC6 specific data + * + * @param reg register to read + + * @param val pointer to variable to store read value + * + * @return 0 if read was successful, <0 otherwise. + */ +int oa_tc6_reg_read(struct oa_tc6 *tc6, const uint32_t reg, uint32_t *val); + +/** + * @brief Write to OA TC6 compliant device a single register + * + * @param tc6 OA TC6 specific data + * + * @param reg register to read + + * @param val data to send to device + * + * @return 0 if write was successful, <0 otherwise. + */ +int oa_tc6_reg_write(struct oa_tc6 *tc6, const uint32_t reg, uint32_t val); + +/** + * @brief Enable or disable the protected mode for control transactions + * + * @param tc6 OA TC6 specific data + * + * @param prote enable or disable protected control transactions + * + * @return 0 if operation was successful, <0 otherwise. + */ +int oa_tc6_set_protected_ctrl(struct oa_tc6 *tc6, bool prote); + +/** + * @brief Send OA TC6 data chunks to the device + * + * @param tc6 OA TC6 specific data + * + * @param pkt network packet to be send + * + * @return 0 if data send was successful, <0 otherwise. + */ +int oa_tc6_send_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt); + +/** + * @brief Read data chunks from OA TC6 device + * + * @param tc6 OA TC6 specific data + * + * @param pkt network packet to store received data + * + * @return 0 if read was successful, <0 otherwise. + */ +int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt); + +/** + * @brief Perform SPI transfer of single chunk from/to OA TC6 device + * + * @param tc6 OA TC6 specific data + * + * @param buf_rx buffer to store read data + * + * @param buf_tx buffer with data to send + * + * @param hdr OA TC6 data transmission header value + * + * @param ftr poniter to OA TC6 data received footer + * + * @return 0 if transmission was successful, <0 otherwise. + */ +int oa_tc6_chunk_spi_transfer(struct oa_tc6 *tc6, uint8_t *buf_rx, uint8_t *buf_tx, + uint32_t hdr, uint32_t *ftr); + +/** + * @brief Read status from OA TC6 device + * + * @param tc6 OA TC6 specific data + * + * @param ftr poniter to OA TC6 data received footer + * + * @return 0 if successful, <0 otherwise. + */ +int oa_tc6_read_status(struct oa_tc6 *tc6, uint32_t *ftr); + +/** + * @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_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 ce4cbe3e715f141..ff25a9a4fa39c28 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 ae1229de1fc72b3..ad7cef7bc177054 100644 --- a/drivers/ethernet/phy/Kconfig +++ b/drivers/ethernet/phy/Kconfig @@ -23,8 +23,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 +38,23 @@ config PHY_ADIN2111 help Enable ADIN2111 PHY driver. +config PHY_TJA1103 + bool "TJA1103 PHY driver" + default y + depends on DT_HAS_NXP_TJA1103_ENABLED + depends on MDIO + help + Enable TJA1103 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/phy_microchip_ksz8081.c b/drivers/ethernet/phy/phy_microchip_ksz8081.c new file mode 100644 index 000000000000000..10d7f78172c6799 --- /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 4ad961089e68c4b..041be3dafaa3221 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 000000000000000..946a4d16200a168 --- /dev/null +++ b/drivers/ethernet/phy/phy_tja1103.c @@ -0,0 +1,247 @@ +/* + * 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 +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) + +struct phy_tja1103_config { + const struct device *mdio; + uint8_t phy_addr; + uint8_t master_slave; +}; + +struct phy_tja1103_data { + struct phy_link_state state; + struct k_sem sem; +}; + +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 phy_tja1103_get_link_state(const struct device *dev, struct phy_link_state *state) +{ + struct phy_tja1103_data *const data = dev->data; + uint16_t val; + + k_sem_take(&data->sem, K_FOREVER); + + if (phy_tja1103_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_PHY_STATUS, &val) >= 0) { + + data->state.is_up = (val & TJA1103_PHY_STATUS_LINK_STAT) != 0; + + memcpy(state, &data->state, sizeof(struct phy_link_state)); + } + + k_sem_give(&data->sem); + + return 0; +} + +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->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; + } + + /* Wait for settings to go in affect before checking link */ + k_sleep(K_MSEC(400)); + + phy_tja1103_get_link_state(dev, &data->state); + return ret; +} + +static int phy_tja1103_link_cb_set(const struct device *dev, phy_callback_t cb, void *user_data) +{ + ARG_UNUSED(dev); + ARG_UNUSED(cb); + ARG_UNUSED(user_data); + return -ENOTSUP; +} + +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)), \ + .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), \ + }; \ + 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 e937d3ee5a9c630..6b896288d14402a 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -51,6 +51,8 @@ zephyr_library_sources_ifdef(CONFIG_FLASH_CAD_QSPI_NOR flash_cadence_qspi_nor.c 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") @@ -67,20 +69,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 8660bed13e40dd2..81b4cdbe40dc125 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -52,7 +52,7 @@ config FLASH_JESD216_API config FLASH_SHELL bool "Flash shell" depends on SHELL && FLASH_PAGE_LAYOUT - default y + select MPU_ALLOW_FLASH_WRITE if ARM_MPU help Enable the flash shell with flash related commands such as test, write, read and erase. @@ -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" @@ -158,4 +159,6 @@ source "drivers/flash/Kconfig.nxp_s32" source "drivers/flash/Kconfig.andes" +source "drivers/flash/Kconfig.ambiq" + endif # FLASH diff --git a/drivers/flash/Kconfig.ambiq b/drivers/flash/Kconfig.ambiq new file mode 100644 index 000000000000000..cc84c0faf39f133 --- /dev/null +++ b/drivers/flash/Kconfig.ambiq @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Ambiq Micro Inc. +# SPDX-License-Identifier: Apache-2.0 + +config FLASH_AMBIQ + bool "Ambiq flash driver on MRAM" + default y + depends on DT_HAS_AMBIQ_FLASH_CONTROLLER_ENABLED + select AMBIQ_HAL + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_DRIVER_ENABLED + help + Enables Ambiq flash driver on MRAM. diff --git a/drivers/flash/Kconfig.cadence_nand b/drivers/flash/Kconfig.cadence_nand new file mode 100644 index 000000000000000..52b7a1422b109ae --- /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.nor b/drivers/flash/Kconfig.nor index 622ded4225888bc..8263f7f6785da30 100644 --- a/drivers/flash/Kconfig.nor +++ b/drivers/flash/Kconfig.nor @@ -8,6 +8,7 @@ menuconfig SPI_NOR select FLASH_HAS_DRIVER_ENABLED select FLASH_HAS_PAGE_LAYOUT select FLASH_JESD216 + select FLASH_HAS_EX_OP select SPI if SPI_NOR @@ -19,7 +20,8 @@ choice SPI_NOR_SFDP config SPI_NOR_SFDP_MINIMAL bool "Fixed flash configuration" help - Synthesize a minimal configuration assuming 256 By page size and + Synthesize a minimal configuration assuming 256 By page size (or as + set by the page-size devicetree property) and standard 4 KiBy and 64 KiBy erase instructions. Requires the size and jedec-id properties in the devicetree jedec,spi-nor node. @@ -53,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 aac9830835a7cca..ff652f6082298bc 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.npcx_fiu b/drivers/flash/Kconfig.npcx_fiu index d46d7f2e0dcc207..e4ac74c9d444ead 100644 --- a/drivers/flash/Kconfig.npcx_fiu +++ b/drivers/flash/Kconfig.npcx_fiu @@ -24,6 +24,8 @@ config FLASH_NPCX_FIU_NOR This option enables the QSPI NOR Flash driver for NPCX family of processors. +if FLASH_NPCX_FIU_QSPI + config FLASH_NPCX_FIU_NOR_INIT bool "QSPI NOR flash feature during driver initialization" default y @@ -32,3 +34,33 @@ config FLASH_NPCX_FIU_NOR_INIT This option enables the QSPI NOR Flash features such as Quad-Enable, 4-byte address support and so on during driver initialization. Disable it if QSPI NOR devices are not ready during driver initialization. + +config FLASH_NPCX_FIU_DRA_V1 + bool "Direct Read Access version 1 support" + default y if SOC_SERIES_NPCX9 + help + This option enables DRA V1 support. + +config FLASH_NPCX_FIU_DRA_V2 + bool "Direct Read Access version 2 support" + default y if SOC_SERIES_NPCX4 + help + This option enables DRA V1 support. + +config FLASH_NPCX_FIU_SUPP_DRA_4B_ADDR + bool "4 byte address support in Direct Read Access mode" + default y if FLASH_NPCX_FIU_DRA_V1 || \ + FLASH_NPCX_FIU_DRA_V2 + help + Selected if NPCX series supports 4 byte address mode in Direct Read + Access mode. + +config FLASH_NPCX_FIU_SUPP_DRA_2_DEV + bool "4 byte address support in Direct Read Access mode" + default y if FLASH_NPCX_FIU_DRA_V1 || \ + FLASH_NPCX_FIU_DRA_V2 + help + Selected if NPCX series supports two external SPI devices in Direct + Read Access (DRA) on QSPI bus. + +endif #FLASH_NPCX_FIU_QSPI diff --git a/drivers/flash/Kconfig.sam b/drivers/flash/Kconfig.sam index bb014d652799003..64df895bd6ac0ee 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 aa7d24cbd6dc506..a452ab8b98d0f69 100644 --- a/drivers/flash/Kconfig.stm32 +++ b/drivers/flash/Kconfig.stm32 @@ -13,8 +13,9 @@ config SOC_FLASH_STM32 default y select FLASH_PAGE_LAYOUT select FLASH_HAS_PAGE_LAYOUT - select FLASH_HAS_EX_OP if SOC_SERIES_STM32F4X 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 @@ -23,6 +24,7 @@ if SOC_FLASH_STM32 config FLASH_STM32_WRITE_PROTECT bool "Extended operation for flash write protection control" depends on SOC_SERIES_STM32F4X + select FLASH_HAS_EX_OP default n help Enables flash extended operation for enabling/disabling flash write @@ -38,7 +40,8 @@ config FLASH_STM32_WRITE_PROTECT_DISABLE_PREVENTION config FLASH_STM32_READOUT_PROTECTION bool "Extended operation for flash readout protection control" - depends on SOC_SERIES_STM32F4X + depends on SOC_SERIES_STM32F4X || SOC_SERIES_STM32L4X || SOC_SERIES_STM32G4X + select FLASH_HAS_EX_OP default n help Enables flash extended operation for enabling/disabling flash readout diff --git a/drivers/flash/flash_ambiq.c b/drivers/flash/flash_ambiq.c new file mode 100644 index 000000000000000..fdc852c04ca8cfe --- /dev/null +++ b/drivers/flash/flash_ambiq.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ambiq_flash_controller + +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(flash_ambiq, CONFIG_FLASH_LOG_LEVEL); + +#define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash) +#define SOC_NV_FLASH_ADDR DT_REG_ADDR(SOC_NV_FLASH_NODE) +#define SOC_NV_FLASH_SIZE DT_REG_SIZE(SOC_NV_FLASH_NODE) +#define MIN_WRITE_SIZE 16 +#define FLASH_WRITE_BLOCK_SIZE MAX(DT_PROP(SOC_NV_FLASH_NODE, write_block_size), MIN_WRITE_SIZE) +#define FLASH_ERASE_BLOCK_SIZE DT_PROP(SOC_NV_FLASH_NODE, erase_block_size) + +BUILD_ASSERT((FLASH_WRITE_BLOCK_SIZE & (MIN_WRITE_SIZE - 1)) == 0, + "The flash write block size must be a multiple of 16!"); + +#define FLASH_ERASE_BYTE 0xFF +#define FLASH_ERASE_WORD \ + (((uint32_t)(FLASH_ERASE_BYTE << 24)) | ((uint32_t)(FLASH_ERASE_BYTE << 16)) | \ + ((uint32_t)(FLASH_ERASE_BYTE << 8)) | ((uint32_t)FLASH_ERASE_BYTE)) + +#if defined(CONFIG_MULTITHREADING) +static struct k_sem flash_ambiq_sem; +#define FLASH_SEM_INIT() k_sem_init(&flash_ambiq_sem, 1, 1) +#define FLASH_SEM_TAKE() k_sem_take(&flash_ambiq_sem, K_FOREVER) +#define FLASH_SEM_GIVE() k_sem_give(&flash_ambiq_sem) +#else +#define FLASH_SEM_INIT() +#define FLASH_SEM_TAKE() +#define FLASH_SEM_GIVE() +#endif /* CONFIG_MULTITHREADING */ + +static const struct flash_parameters flash_ambiq_parameters = { + .write_block_size = FLASH_WRITE_BLOCK_SIZE, + .erase_value = FLASH_ERASE_BYTE, +}; + +static bool flash_ambiq_valid_range(off_t offset, size_t len) +{ + if ((offset < 0) || offset >= SOC_NV_FLASH_SIZE || (SOC_NV_FLASH_SIZE - offset) < len) { + return false; + } + + return true; +} + +static int flash_ambiq_read(const struct device *dev, off_t offset, void *data, size_t len) +{ + ARG_UNUSED(dev); + + if (!flash_ambiq_valid_range(offset, len)) { + return -EINVAL; + } + + if (len == 0) { + return 0; + } + + memcpy(data, (uint8_t *)(SOC_NV_FLASH_ADDR + offset), len); + + return 0; +} + +static int flash_ambiq_write(const struct device *dev, off_t offset, const void *data, size_t len) +{ + ARG_UNUSED(dev); + + int ret = 0; + uint32_t critical = 0; + uint32_t aligned[FLASH_WRITE_BLOCK_SIZE / sizeof(uint32_t)] = {0}; + uint32_t *src = (uint32_t *)data; + + /* write address must be block size aligned and the write length must be multiple of block + * size. + */ + if (!flash_ambiq_valid_range(offset, len) || + ((uint32_t)offset & (FLASH_WRITE_BLOCK_SIZE - 1)) || + (len & (FLASH_WRITE_BLOCK_SIZE - 1))) { + return -EINVAL; + } + + if (len == 0) { + return 0; + } + + FLASH_SEM_TAKE(); + + critical = am_hal_interrupt_master_disable(); + for (int i = 0; i < len / FLASH_WRITE_BLOCK_SIZE; i++) { + for (int j = 0; j < FLASH_WRITE_BLOCK_SIZE / sizeof(uint32_t); j++) { + /* Make sure the source data is 4-byte aligned. */ + aligned[j] = UNALIGNED_GET((uint32_t *)src); + src++; + } + ret = am_hal_mram_main_program( + AM_HAL_MRAM_PROGRAM_KEY, aligned, + (uint32_t *)(SOC_NV_FLASH_ADDR + offset + i * FLASH_WRITE_BLOCK_SIZE), + FLASH_WRITE_BLOCK_SIZE / sizeof(uint32_t)); + if (ret) { + break; + } + } + am_hal_interrupt_master_set(critical); + + FLASH_SEM_GIVE(); + + return ret; +} + +static int flash_ambiq_erase(const struct device *dev, off_t offset, size_t len) +{ + ARG_UNUSED(dev); + + int ret = 0; + + if (!flash_ambiq_valid_range(offset, len)) { + return -EINVAL; + } + + /* The erase address and length alignment check will be done in HAL.*/ + + if (len == 0) { + return 0; + } + + FLASH_SEM_TAKE(); + + ret = am_hal_mram_main_fill(AM_HAL_MRAM_PROGRAM_KEY, FLASH_ERASE_WORD, + (uint32_t *)(SOC_NV_FLASH_ADDR + offset), + (len / sizeof(uint32_t))); + + FLASH_SEM_GIVE(); + + return ret; +} + +static const struct flash_parameters *flash_ambiq_get_parameters(const struct device *dev) +{ + ARG_UNUSED(dev); + + return &flash_ambiq_parameters; +} + +#if CONFIG_FLASH_PAGE_LAYOUT +static const struct flash_pages_layout pages_layout = { + .pages_count = SOC_NV_FLASH_SIZE / FLASH_ERASE_BLOCK_SIZE, + .pages_size = FLASH_ERASE_BLOCK_SIZE, +}; + +static void flash_ambiq_pages_layout(const struct device *dev, + const struct flash_pages_layout **layout, size_t *layout_size) +{ + ARG_UNUSED(dev); + + *layout = &pages_layout; + *layout_size = 1; +} +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +static const struct flash_driver_api flash_ambiq_driver_api = { + .read = flash_ambiq_read, + .write = flash_ambiq_write, + .erase = flash_ambiq_erase, + .get_parameters = flash_ambiq_get_parameters, +#ifdef CONFIG_FLASH_PAGE_LAYOUT + .page_layout = flash_ambiq_pages_layout, +#endif +}; + +static int flash_ambiq_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + FLASH_SEM_INIT(); + + return 0; +} + +DEVICE_DT_INST_DEFINE(0, flash_ambiq_init, NULL, NULL, NULL, POST_KERNEL, + CONFIG_FLASH_INIT_PRIORITY, &flash_ambiq_driver_api); diff --git a/drivers/flash/flash_cadence_nand.c b/drivers/flash/flash_cadence_nand.c new file mode 100644 index 000000000000000..b527a5082cef82e --- /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 000000000000000..a33eb42470926c9 --- /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 000000000000000..b52e7c9053532c2 --- /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 20a27b3d17bbda6..645e40fd5462347 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 6d639420294025b..8c047adbaf4a671 100644 --- a/drivers/flash/flash_handlers.c +++ b/drivers/flash/flash_handlers.c @@ -4,14 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include static inline int z_vrfy_flash_read(const struct device *dev, off_t offset, void *data, size_t len) { - Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, read)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(data, len)); + K_OOPS(K_SYSCALL_DRIVER_FLASH(dev, read)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(data, len)); return z_impl_flash_read((const struct device *)dev, offset, (void *)data, len); @@ -21,8 +21,8 @@ static inline int z_vrfy_flash_read(const struct device *dev, off_t offset, static inline int z_vrfy_flash_write(const struct device *dev, off_t offset, const void *data, size_t len) { - Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, write)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(data, len)); + K_OOPS(K_SYSCALL_DRIVER_FLASH(dev, write)); + K_OOPS(K_SYSCALL_MEMORY_READ(data, len)); return z_impl_flash_write((const struct device *)dev, offset, (const void *)data, len); } @@ -31,21 +31,21 @@ static inline int z_vrfy_flash_write(const struct device *dev, off_t offset, static inline int z_vrfy_flash_erase(const struct device *dev, off_t offset, size_t size) { - Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, erase)); + K_OOPS(K_SYSCALL_DRIVER_FLASH(dev, erase)); return z_impl_flash_erase((const struct device *)dev, offset, size); } #include static inline size_t z_vrfy_flash_get_write_block_size(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH)); return z_impl_flash_get_write_block_size(dev); } #include static inline const struct flash_parameters *z_vrfy_flash_get_parameters(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, get_parameters)); + K_OOPS(K_SYSCALL_DRIVER_FLASH(dev, get_parameters)); return z_impl_flash_get_parameters(dev); } #include @@ -55,8 +55,8 @@ static inline int z_vrfy_flash_get_page_info_by_offs(const struct device *dev, off_t offs, struct flash_pages_info *info) { - Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, page_layout)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(info, sizeof(struct flash_pages_info))); + K_OOPS(K_SYSCALL_DRIVER_FLASH(dev, page_layout)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(info, sizeof(struct flash_pages_info))); return z_impl_flash_get_page_info_by_offs((const struct device *)dev, offs, (struct flash_pages_info *)info); @@ -67,8 +67,8 @@ static inline int z_vrfy_flash_get_page_info_by_idx(const struct device *dev, uint32_t idx, struct flash_pages_info *info) { - Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, page_layout)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(info, sizeof(struct flash_pages_info))); + K_OOPS(K_SYSCALL_DRIVER_FLASH(dev, page_layout)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(info, sizeof(struct flash_pages_info))); return z_impl_flash_get_page_info_by_idx((const struct device *)dev, idx, (struct flash_pages_info *)info); @@ -77,7 +77,7 @@ static inline int z_vrfy_flash_get_page_info_by_idx(const struct device *dev, static inline size_t z_vrfy_flash_get_page_count(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, page_layout)); + K_OOPS(K_SYSCALL_DRIVER_FLASH(dev, page_layout)); return z_impl_flash_get_page_count((const struct device *)dev); } #include @@ -90,20 +90,20 @@ static inline int z_vrfy_flash_sfdp_read(const struct device *dev, off_t offset, void *data, size_t len) { - Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, sfdp_read)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(data, len)); + K_OOPS(K_SYSCALL_DRIVER_FLASH(dev, sfdp_read)); + 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) { - Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, read_jedec_id)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(id, 3)); + K_OOPS(K_SYSCALL_DRIVER_FLASH(dev, read_jedec_id)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(id, 3)); return z_impl_flash_read_jedec_id(dev, id); } -#include +#include #endif /* CONFIG_FLASH_JESD216_API */ @@ -112,7 +112,7 @@ static inline int z_vrfy_flash_read_jedec_id(const struct device *dev, static inline int z_vrfy_flash_ex_op(const struct device *dev, uint16_t code, const uintptr_t in, void *out) { - Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, ex_op)); + K_OOPS(K_SYSCALL_DRIVER_FLASH(dev, ex_op)); /* * If the code is a vendor code, then ex_op function have to perform diff --git a/drivers/flash/flash_mcux_flexspi_hyperflash.c b/drivers/flash/flash_mcux_flexspi_hyperflash.c index d1c6cb1ee06cb57..b0a04ee63ed690f 100644 --- a/drivers/flash/flash_mcux_flexspi_hyperflash.c +++ b/drivers/flash/flash_mcux_flexspi_hyperflash.c @@ -596,7 +596,6 @@ static int flash_flexspi_hyperflash_init(const struct device *dev) { const struct flash_flexspi_hyperflash_config *config = dev->config; struct flash_flexspi_hyperflash_data *data = dev->data; - uint32_t temp_lut[sizeof(flash_flexspi_hyperflash_lut) / sizeof(uint32_t)]; /* Since the controller variable may be used in critical sections, * copy the device pointer into a variable stored in RAM @@ -610,27 +609,15 @@ static int flash_flexspi_hyperflash_init(const struct device *dev) memc_flexspi_wait_bus_idle(&data->controller); - if (!memc_flexspi_is_running_xip(&data->controller) && - memc_flexspi_set_device_config(&data->controller, &data->config, - data->port)) { - LOG_ERR("Could not set device configuration"); - return -EINVAL; + if (memc_flexspi_is_running_xip(&data->controller)) { + /* Wait for bus idle before configuring */ + memc_flexspi_wait_bus_idle(&data->controller); } - - /* - * Using the LUT stored in the FlexSPI directly when updating - * the FlexSPI can result in an invalid LUT entry being stored, - * as the LUT itself describes how the FlexSPI should access the flash. - * To resolve this, copy the LUT to a array placed in RAM before - * updating the FlexSPI. - */ - memcpy(temp_lut, flash_flexspi_hyperflash_lut, - sizeof(flash_flexspi_hyperflash_lut)); - - if (memc_flexspi_update_lut(&data->controller, 0, - (const uint32_t *) temp_lut, - sizeof(temp_lut) / sizeof(uint32_t))) { - LOG_ERR("Could not update lut"); + if (memc_flexspi_set_device_config(&data->controller, &data->config, + (const uint32_t *)flash_flexspi_hyperflash_lut, + sizeof(flash_flexspi_hyperflash_lut) / MEMC_FLEXSPI_CMD_SIZE, + data->port)) { + LOG_ERR("Could not set device configuration"); return -EINVAL; } diff --git a/drivers/flash/flash_mcux_flexspi_mx25um51345g.c b/drivers/flash/flash_mcux_flexspi_mx25um51345g.c index be3b59dcf12815f..b72da49d1540a21 100644 --- a/drivers/flash/flash_mcux_flexspi_mx25um51345g.c +++ b/drivers/flash/flash_mcux_flexspi_mx25um51345g.c @@ -512,34 +512,22 @@ static int flash_flexspi_nor_init(const struct device *dev) { struct flash_flexspi_nor_data *data = dev->data; uint8_t vendor_id; - uint32_t temp_lut[sizeof(flash_flexspi_nor_lut) / sizeof(uint32_t)]; if (!device_is_ready(data->controller)) { LOG_ERR("Controller device not ready"); return -ENODEV; } - if (!memc_flexspi_is_running_xip(data->controller) && - memc_flexspi_set_device_config(data->controller, &data->config, - data->port)) { - LOG_ERR("Could not set device configuration"); - return -EINVAL; + if (memc_flexspi_is_running_xip(data->controller)) { + /* Wait for bus idle before configuring */ + memc_flexspi_wait_bus_idle(data->controller); } - /* - * Using the LUT stored in the FlexSPI directly when updating - * the FlexSPI can result in an invalid LUT entry being stored, - * as the LUT itself describes how the FlexSPI should access the flash. - * To resolve this, copy the LUT to a array placed in RAM before - * updating the FlexSPI. - */ - memcpy(temp_lut, flash_flexspi_nor_lut, - sizeof(flash_flexspi_nor_lut)); - - if (memc_flexspi_update_lut(data->controller, 0, - (const uint32_t *) temp_lut, - sizeof(temp_lut) / sizeof(uint32_t))) { - LOG_ERR("Could not update lut"); + 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; } diff --git a/drivers/flash/flash_mcux_flexspi_nor.c b/drivers/flash/flash_mcux_flexspi_nor.c index e863bc9b8db388b..8a9c4f182ade959 100644 --- a/drivers/flash/flash_mcux_flexspi_nor.c +++ b/drivers/flash/flash_mcux_flexspi_nor.c @@ -58,9 +58,17 @@ enum { ERASE_CHIP, }; +struct flash_flexspi_nor_config { + /* Note: don't use this controller reference in code. It is + * only used during init to copy the device structure from ROM + * into a RAM structure + */ + const struct device *controller; +}; + /* Device variables used in critical sections should be in this structure */ struct flash_flexspi_nor_data { - const struct device *controller; + struct device controller; flexspi_device_config_t config; flexspi_port_t port; struct flash_pages_layout layout; @@ -154,10 +162,9 @@ static const uint32_t flash_flexspi_nor_lut[][4] = { }, }; -static int flash_flexspi_nor_get_vendor_id(const struct device *dev, +static int flash_flexspi_nor_get_vendor_id(struct flash_flexspi_nor_data *data, uint8_t *vendor_id) { - struct flash_flexspi_nor_data *data = dev->data; uint32_t buffer = 0; int ret; @@ -173,17 +180,15 @@ static int flash_flexspi_nor_get_vendor_id(const struct device *dev, LOG_DBG("Reading id"); - ret = memc_flexspi_transfer(data->controller, &transfer); + ret = memc_flexspi_transfer(&data->controller, &transfer); *vendor_id = buffer; return ret; } -static int flash_flexspi_nor_read_status(const struct device *dev, +static int flash_flexspi_nor_read_status(struct flash_flexspi_nor_data *data, uint32_t *status) { - struct flash_flexspi_nor_data *data = dev->data; - flexspi_transfer_t transfer = { .deviceAddress = 0, .port = data->port, @@ -196,14 +201,12 @@ static int flash_flexspi_nor_read_status(const struct device *dev, LOG_DBG("Reading status register"); - return memc_flexspi_transfer(data->controller, &transfer); + return memc_flexspi_transfer(&data->controller, &transfer); } -static int flash_flexspi_nor_write_status(const struct device *dev, +static int flash_flexspi_nor_write_status(struct flash_flexspi_nor_data *data, uint32_t *status) { - struct flash_flexspi_nor_data *data = dev->data; - flexspi_transfer_t transfer = { .deviceAddress = 0, .port = data->port, @@ -216,13 +219,11 @@ static int flash_flexspi_nor_write_status(const struct device *dev, LOG_DBG("Writing status register"); - return memc_flexspi_transfer(data->controller, &transfer); + return memc_flexspi_transfer(&data->controller, &transfer); } -static int flash_flexspi_nor_write_enable(const struct device *dev) +static int flash_flexspi_nor_write_enable(struct flash_flexspi_nor_data *data) { - struct flash_flexspi_nor_data *data = dev->data; - flexspi_transfer_t transfer = { .deviceAddress = 0, .port = data->port, @@ -235,14 +236,12 @@ static int flash_flexspi_nor_write_enable(const struct device *dev) LOG_DBG("Enabling write"); - return memc_flexspi_transfer(data->controller, &transfer); + return memc_flexspi_transfer(&data->controller, &transfer); } -static int flash_flexspi_nor_erase_sector(const struct device *dev, +static int flash_flexspi_nor_erase_sector(struct flash_flexspi_nor_data *data, off_t offset) { - struct flash_flexspi_nor_data *data = dev->data; - flexspi_transfer_t transfer = { .deviceAddress = offset, .port = data->port, @@ -255,14 +254,12 @@ static int flash_flexspi_nor_erase_sector(const struct device *dev, LOG_DBG("Erasing sector at 0x%08zx", (ssize_t) offset); - return memc_flexspi_transfer(data->controller, &transfer); + return memc_flexspi_transfer(&data->controller, &transfer); } -static int flash_flexspi_nor_erase_block(const struct device *dev, +static int flash_flexspi_nor_erase_block(struct flash_flexspi_nor_data *data, off_t offset) { - struct flash_flexspi_nor_data *data = dev->data; - flexspi_transfer_t transfer = { .deviceAddress = offset, .port = data->port, @@ -275,13 +272,11 @@ static int flash_flexspi_nor_erase_block(const struct device *dev, LOG_DBG("Erasing block at 0x%08zx", (ssize_t) offset); - return memc_flexspi_transfer(data->controller, &transfer); + return memc_flexspi_transfer(&data->controller, &transfer); } -static int flash_flexspi_nor_erase_chip(const struct device *dev) +static int flash_flexspi_nor_erase_chip(struct flash_flexspi_nor_data *data) { - struct flash_flexspi_nor_data *data = dev->data; - flexspi_transfer_t transfer = { .deviceAddress = 0, .port = data->port, @@ -294,14 +289,12 @@ static int flash_flexspi_nor_erase_chip(const struct device *dev) LOG_DBG("Erasing chip"); - return memc_flexspi_transfer(data->controller, &transfer); + return memc_flexspi_transfer(&data->controller, &transfer); } -static int flash_flexspi_nor_page_program(const struct device *dev, +static int flash_flexspi_nor_page_program(struct flash_flexspi_nor_data *data, off_t offset, const void *buffer, size_t len) { - struct flash_flexspi_nor_data *data = dev->data; - flexspi_transfer_t transfer = { .deviceAddress = offset, .port = data->port, @@ -314,16 +307,16 @@ static int flash_flexspi_nor_page_program(const struct device *dev, LOG_DBG("Page programming %d bytes to 0x%08zx", len, (ssize_t) offset); - return memc_flexspi_transfer(data->controller, &transfer); + return memc_flexspi_transfer(&data->controller, &transfer); } -static int flash_flexspi_nor_wait_bus_busy(const struct device *dev) +static int flash_flexspi_nor_wait_bus_busy(struct flash_flexspi_nor_data *data) { uint32_t status = 0; int ret; do { - ret = flash_flexspi_nor_read_status(dev, &status); + ret = flash_flexspi_nor_read_status(data, &status); LOG_DBG("status: 0x%x", status); if (ret) { LOG_ERR("Could not read status"); @@ -334,14 +327,13 @@ static int flash_flexspi_nor_wait_bus_busy(const struct device *dev) return 0; } -static int flash_flexspi_nor_enable_quad_mode(const struct device *dev) +static int flash_flexspi_nor_enable_quad_mode(struct flash_flexspi_nor_data *data) { - struct flash_flexspi_nor_data *data = dev->data; uint32_t status = 0x40; - flash_flexspi_nor_write_status(dev, &status); - flash_flexspi_nor_wait_bus_busy(dev); - memc_flexspi_reset(data->controller); + flash_flexspi_nor_write_status(data, &status); + flash_flexspi_nor_wait_bus_busy(data); + memc_flexspi_reset(&data->controller); return 0; } @@ -350,7 +342,7 @@ static int flash_flexspi_nor_read(const struct device *dev, off_t offset, void *buffer, size_t len) { struct flash_flexspi_nor_data *data = dev->data; - uint8_t *src = memc_flexspi_get_ahb_address(data->controller, + uint8_t *src = memc_flexspi_get_ahb_address(&data->controller, data->port, offset); @@ -368,11 +360,11 @@ static int flash_flexspi_nor_write(const struct device *dev, off_t offset, int i; unsigned int key = 0; - uint8_t *dst = memc_flexspi_get_ahb_address(data->controller, + uint8_t *dst = memc_flexspi_get_ahb_address(&data->controller, data->port, offset); - if (memc_flexspi_is_running_xip(data->controller)) { + if (memc_flexspi_is_running_xip(&data->controller)) { /* * ==== ENTER CRITICAL SECTION ==== * No flash access should be performed in critical section. All @@ -390,20 +382,20 @@ static int flash_flexspi_nor_write(const struct device *dev, off_t offset, #ifdef CONFIG_FLASH_MCUX_FLEXSPI_NOR_WRITE_BUFFER memcpy(nor_write_buf, src, i); #endif - flash_flexspi_nor_write_enable(dev); + flash_flexspi_nor_write_enable(data); #ifdef CONFIG_FLASH_MCUX_FLEXSPI_NOR_WRITE_BUFFER - flash_flexspi_nor_page_program(dev, offset, nor_write_buf, i); + flash_flexspi_nor_page_program(data, offset, nor_write_buf, i); #else - flash_flexspi_nor_page_program(dev, offset, src, i); + flash_flexspi_nor_page_program(data, offset, src, i); #endif - flash_flexspi_nor_wait_bus_busy(dev); - memc_flexspi_reset(data->controller); + flash_flexspi_nor_wait_bus_busy(data); + memc_flexspi_reset(&data->controller); src += i; offset += i; len -= i; } - if (memc_flexspi_is_running_xip(data->controller)) { + if (memc_flexspi_is_running_xip(&data->controller)) { /* ==== EXIT CRITICAL SECTION ==== */ irq_unlock(key); } @@ -425,7 +417,7 @@ static int flash_flexspi_nor_erase(const struct device *dev, off_t offset, int i; unsigned int key = 0; - uint8_t *dst = memc_flexspi_get_ahb_address(data->controller, + uint8_t *dst = memc_flexspi_get_ahb_address(&data->controller, data->port, offset); @@ -439,7 +431,7 @@ static int flash_flexspi_nor_erase(const struct device *dev, off_t offset, return -EINVAL; } - if (memc_flexspi_is_running_xip(data->controller)) { + if (memc_flexspi_is_running_xip(&data->controller)) { /* * ==== ENTER CRITICAL SECTION ==== * No flash access should be performed in critical section. All @@ -449,29 +441,29 @@ static int flash_flexspi_nor_erase(const struct device *dev, off_t offset, } if ((offset == 0) && (size == data->config.flashSize * KB(1))) { - flash_flexspi_nor_write_enable(dev); - flash_flexspi_nor_erase_chip(dev); - flash_flexspi_nor_wait_bus_busy(dev); - memc_flexspi_reset(data->controller); + flash_flexspi_nor_write_enable(data); + flash_flexspi_nor_erase_chip(data); + flash_flexspi_nor_wait_bus_busy(data); + memc_flexspi_reset(&data->controller); } else if ((0 == (offset % SPI_NOR_BLOCK_SIZE)) && (0 == (size % SPI_NOR_BLOCK_SIZE))) { for (i = 0; i < num_blocks; i++) { - flash_flexspi_nor_write_enable(dev); - flash_flexspi_nor_erase_block(dev, offset); - flash_flexspi_nor_wait_bus_busy(dev); - memc_flexspi_reset(data->controller); + flash_flexspi_nor_write_enable(data); + flash_flexspi_nor_erase_block(data, offset); + flash_flexspi_nor_wait_bus_busy(data); + memc_flexspi_reset(&data->controller); offset += SPI_NOR_BLOCK_SIZE; } } else { for (i = 0; i < num_sectors; i++) { - flash_flexspi_nor_write_enable(dev); - flash_flexspi_nor_erase_sector(dev, offset); - flash_flexspi_nor_wait_bus_busy(dev); - memc_flexspi_reset(data->controller); + flash_flexspi_nor_write_enable(data); + flash_flexspi_nor_erase_sector(data, offset); + flash_flexspi_nor_wait_bus_busy(data); + memc_flexspi_reset(&data->controller); offset += SPI_NOR_SECTOR_SIZE; } } - if (memc_flexspi_is_running_xip(data->controller)) { + if (memc_flexspi_is_running_xip(&data->controller)) { /* ==== EXIT CRITICAL SECTION ==== */ irq_unlock(key); } @@ -504,48 +496,42 @@ static void flash_flexspi_nor_pages_layout(const struct device *dev, 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 temp_lut[sizeof(flash_flexspi_nor_lut) / sizeof(uint32_t)]; - if (!device_is_ready(data->controller)) { + /* First step- use ROM pointer to controller device to create + * a copy of the device structure in RAM we can use while in + * critical sections of code. + */ + memcpy(&data->controller, config->controller, sizeof(struct device)); + + if (!device_is_ready(&data->controller)) { LOG_ERR("Controller device is not ready"); return -ENODEV; } - if (!memc_flexspi_is_running_xip(data->controller) && - memc_flexspi_set_device_config(data->controller, &data->config, - data->port)) { - LOG_ERR("Could not set device configuration"); - return -EINVAL; + if (memc_flexspi_is_running_xip(&data->controller)) { + /* Wait for bus idle before configuring */ + memc_flexspi_wait_bus_idle(&data->controller); } - - /* - * Using the LUT stored in the FlexSPI directly when updating - * the FlexSPI can result in an invalid LUT entry being stored, - * as the LUT itself describes how the FlexSPI should access the flash. - * To resolve this, copy the LUT to a array placed in RAM before - * updating the FlexSPI. - */ - memcpy(temp_lut, flash_flexspi_nor_lut, - sizeof(flash_flexspi_nor_lut)); - - if (memc_flexspi_update_lut(data->controller, 0, - (const uint32_t *) temp_lut, - sizeof(temp_lut) / sizeof(uint32_t))) { - LOG_ERR("Could not update lut"); + 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; } - memc_flexspi_reset(data->controller); + memc_flexspi_reset(&data->controller); - if (flash_flexspi_nor_get_vendor_id(dev, &vendor_id)) { + if (flash_flexspi_nor_get_vendor_id(data, &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(dev)) { + if (flash_flexspi_nor_enable_quad_mode(data)) { LOG_ERR("Could not enable quad mode"); return -EIO; } @@ -596,9 +582,12 @@ static const struct flash_driver_api flash_flexspi_nor_api = { } \ #define FLASH_FLEXSPI_NOR(n) \ + static const struct flash_flexspi_nor_config \ + flash_flexspi_nor_config_##n = { \ + .controller = DEVICE_DT_GET(DT_INST_BUS(n)), \ + }; \ static struct flash_flexspi_nor_data \ flash_flexspi_nor_data_##n = { \ - .controller = DEVICE_DT_GET(DT_INST_BUS(n)), \ .config = FLASH_FLEXSPI_DEVICE_CONFIG(n), \ .port = DT_INST_REG_ADDR(n), \ .layout = { \ @@ -616,7 +605,7 @@ static const struct flash_driver_api flash_flexspi_nor_api = { flash_flexspi_nor_init, \ NULL, \ &flash_flexspi_nor_data_##n, \ - NULL, \ + &flash_flexspi_nor_config_##n, \ POST_KERNEL, \ CONFIG_FLASH_INIT_PRIORITY, \ &flash_flexspi_nor_api); diff --git a/drivers/flash/flash_npcx_fiu_nor.c b/drivers/flash/flash_npcx_fiu_nor.c index 6b99e832f248584..e42aa82f8966f89 100644 --- a/drivers/flash/flash_npcx_fiu_nor.c +++ b/drivers/flash/flash_npcx_fiu_nor.c @@ -14,7 +14,7 @@ #include #ifdef CONFIG_USERSPACE #include -#include +#include #endif #include "flash_npcx_fiu_qspi.h" @@ -453,7 +453,7 @@ static int flash_npcx_nor_ex_op(const struct device *dev, uint16_t code, struct npcx_ex_ops_uma_out out_copy; if (syscall_trap) { - Z_OOPS(z_user_from_copy(&in_copy, op_in, sizeof(in_copy))); + K_OOPS(k_usermode_from_copy(&in_copy, op_in, sizeof(in_copy))); op_in = &in_copy; op_out = &out_copy; } @@ -462,7 +462,7 @@ static int flash_npcx_nor_ex_op(const struct device *dev, uint16_t code, ret = flash_npcx_nor_ex_exec_uma(dev, op_in, op_out); #ifdef CONFIG_USERSPACE if (ret == 0 && syscall_trap) { - Z_OOPS(z_user_to_copy(out, op_out, sizeof(out_copy))); + K_OOPS(k_usermode_to_copy(out, op_out, sizeof(out_copy))); } #endif break; @@ -474,7 +474,7 @@ static int flash_npcx_nor_ex_op(const struct device *dev, uint16_t code, struct npcx_ex_ops_qspi_oper_in in_copy; if (syscall_trap) { - Z_OOPS(z_user_from_copy(&in_copy, op_in, sizeof(in_copy))); + K_OOPS(k_usermode_from_copy(&in_copy, op_in, sizeof(in_copy))); op_in = &in_copy; } #endif @@ -495,7 +495,7 @@ static int flash_npcx_nor_ex_op(const struct device *dev, uint16_t code, ret = flash_npcx_nor_ex_get_spi_spec(dev, op_out); #ifdef CONFIG_USERSPACE if (ret == 0 && syscall_trap) { - Z_OOPS(z_user_to_copy(out, op_out, sizeof(out_copy))); + K_OOPS(k_usermode_to_copy(out, op_out, sizeof(out_copy))); } #endif break; diff --git a/drivers/flash/flash_npcx_fiu_qspi.c b/drivers/flash/flash_npcx_fiu_qspi.c index 3af0d4092a6dd6b..39e699bbef9d3a6 100644 --- a/drivers/flash/flash_npcx_fiu_qspi.c +++ b/drivers/flash/flash_npcx_fiu_qspi.c @@ -99,10 +99,10 @@ static inline void qspi_npcx_config_uma_mode(const struct device *dev, static inline void qspi_npcx_config_dra_4byte_mode(const struct device *dev, const struct npcx_qspi_cfg *qspi_cfg) { -#if !defined(CONFIG_SOC_SERIES_NPCX7) /* NPCX7 doesn't support this feature */ +#if defined(CONFIG_FLASH_NPCX_FIU_SUPP_DRA_4B_ADDR) struct fiu_reg *const inst = HAL_INSTANCE(dev); -#if defined(CONFIG_SOC_SERIES_NPCX9) +#if defined(CONFIG_FLASH_NPCX_FIU_DRA_V1) if (qspi_cfg->enter_4ba != 0) { if ((qspi_cfg->flags & NPCX_QSPI_SEC_FLASH_SL) != 0) { inst->SPI1_DEV |= BIT(NPCX_SPI1_DEV_FOUR_BADDR_CS11); @@ -113,12 +113,12 @@ static inline void qspi_npcx_config_dra_4byte_mode(const struct device *dev, inst->SPI1_DEV &= ~(BIT(NPCX_SPI1_DEV_FOUR_BADDR_CS11) | BIT(NPCX_SPI1_DEV_FOUR_BADDR_CS10)); } -#elif defined(CONFIG_SOC_SERIES_NPCX4) +#elif defined(CONFIG_FLASH_NPCX_FIU_DRA_V2) if (qspi_cfg->enter_4ba != 0) { SET_FIELD(inst->SPI_DEV, NPCX_SPI_DEV_NADDRB, NPCX_DEV_NUM_ADDR_4BYTE); } #endif -#endif /* CONFIG_SOC_SERIES_NPCX7 */ +#endif /* CONFIG_FLASH_NPCX_FIU_SUPP_DRA_4B_ADDR */ } static inline void qspi_npcx_config_dra_mode(const struct device *dev, @@ -127,7 +127,7 @@ static inline void qspi_npcx_config_dra_mode(const struct device *dev, struct fiu_reg *const inst = HAL_INSTANCE(dev); /* Select SPI device number for DRA mode in npcx4 series */ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX4)) { + if (IS_ENABLED(CONFIG_FLASH_NPCX_FIU_DRA_V2)) { int spi_dev_num = (qspi_cfg->flags & NPCX_QSPI_SEC_FLASH_SL) != 0 ? 1 : 0; SET_FIELD(inst->BURST_CFG, NPCX_BURST_CFG_SPI_DEV_SEL, spi_dev_num); @@ -247,7 +247,6 @@ void qspi_npcx_fiu_mutex_unlock(const struct device *dev) static int qspi_npcx_fiu_init(const struct device *dev) { const struct npcx_qspi_fiu_config *const config = dev->config; - struct fiu_reg *const inst = HAL_INSTANCE(dev); struct npcx_qspi_fiu_data *const data = dev->data; const struct device *const clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE); int ret; @@ -270,9 +269,11 @@ static int qspi_npcx_fiu_init(const struct device *dev) /* Enable direct access for 2 external SPI devices */ if (config->en_direct_access_2dev) { - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX9) || IS_ENABLED(CONFIG_SOC_SERIES_NPCX4)) { - inst->FIU_EXT_CFG |= BIT(NPCX_FIU_EXT_CFG_SPI1_2DEV); - } +#if defined(CONFIG_FLASH_NPCX_FIU_SUPP_DRA_2_DEV) + struct fiu_reg *const inst = HAL_INSTANCE(dev); + + inst->FIU_EXT_CFG |= BIT(NPCX_FIU_EXT_CFG_SPI1_2DEV); +#endif } return 0; diff --git a/drivers/flash/flash_sam.c b/drivers/flash/flash_sam.c index 118775d29f30524..e4a807552fcdcdb 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_sam0.c b/drivers/flash/flash_sam0.c index b5fc5567cb85286..eb55c5d36a0ba31 100644 --- a/drivers/flash/flash_sam0.c +++ b/drivers/flash/flash_sam0.c @@ -5,6 +5,7 @@ */ #define DT_DRV_COMPAT atmel_sam0_nvmctrl +#define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash) #define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL #include @@ -17,6 +18,9 @@ LOG_MODULE_REGISTER(flash_sam0); #include #include +#define FLASH_WRITE_BLK_SZ DT_PROP(SOC_NV_FLASH_NODE, write_block_size) +BUILD_ASSERT((FLASH_WRITE_BLK_SZ % sizeof(uint32_t)) == 0, "unsupported write-block-size"); + /* * Zephyr and the SAM0 series use different and conflicting names for * the erasable units and programmable units: @@ -67,7 +71,7 @@ static const struct flash_parameters flash_sam0_parameters = { #if CONFIG_SOC_FLASH_SAM0_EMULATE_BYTE_PAGES .write_block_size = 1, #else - .write_block_size = DT_PROP(DT_INST(0, soc_nv_flash), write_block_size), + .write_block_size = FLASH_WRITE_BLK_SZ, #endif .erase_value = 0xff, }; @@ -147,11 +151,18 @@ static int flash_sam0_check_status(off_t offset) return 0; } +/* + * Data to be written to the NVM block are first written to and stored + * in an internal buffer called the page buffer. The page buffer contains + * the same number of bytes as an NVM page. Writes to the page buffer must + * be 16 or 32 bits. 8-bit writes to the page buffer are not allowed and + * will cause a system exception + */ static int flash_sam0_write_page(const struct device *dev, off_t offset, - const void *data) + const void *data, size_t len) { const uint32_t *src = data; - const uint32_t *end = src + FLASH_PAGE_SIZE / sizeof(*src); + const uint32_t *end = src + (len / sizeof(*src)); uint32_t *dst = FLASH_MEM(offset); int err; @@ -178,7 +189,7 @@ static int flash_sam0_write_page(const struct device *dev, off_t offset, return err; } - if (memcmp(data, FLASH_MEM(offset), FLASH_PAGE_SIZE) != 0) { + if (memcmp(data, FLASH_MEM(offset), len) != 0) { LOG_ERR("verify error at offset 0x%lx", (long)offset); return -EIO; } @@ -213,7 +224,7 @@ static int flash_sam0_commit(const struct device *dev, off_t base) for (page = 0; page < PAGES_PER_ROW; page++) { err = flash_sam0_write_page( dev, base + page * FLASH_PAGE_SIZE, - &ctx->buf[page * FLASH_PAGE_SIZE]); + &ctx->buf[page * FLASH_PAGE_SIZE], ROW_SIZE); if (err != 0) { return err; } @@ -280,19 +291,18 @@ static int flash_sam0_write(const struct device *dev, off_t offset, { const uint8_t *pdata = data; int err; - size_t idx; err = flash_sam0_valid_range(offset, len); if (err != 0) { return err; } - if ((offset % FLASH_PAGE_SIZE) != 0) { + if ((offset % FLASH_WRITE_BLK_SZ) != 0) { LOG_WRN("0x%lx: not on a write block boundary", (long)offset); return -EINVAL; } - if ((len % FLASH_PAGE_SIZE) != 0) { + if ((len % FLASH_WRITE_BLK_SZ) != 0) { LOG_WRN("%zu: not a integer number of write blocks", len); return -EINVAL; } @@ -301,12 +311,20 @@ static int flash_sam0_write(const struct device *dev, off_t offset, err = flash_sam0_write_protection(dev, false); if (err == 0) { - for (idx = 0; idx < len; idx += FLASH_PAGE_SIZE) { - err = flash_sam0_write_page(dev, offset + idx, - &pdata[idx]); + /* Maximum size without crossing a page */ + size_t eop_len = FLASH_PAGE_SIZE - (offset % FLASH_PAGE_SIZE); + size_t write_len = MIN(len, eop_len); + + while (len > 0) { + err = flash_sam0_write_page(dev, offset, pdata, write_len); if (err != 0) { break; } + + offset += write_len; + pdata += write_len; + len -= write_len; + write_len = MIN(len, FLASH_PAGE_SIZE); } } @@ -454,6 +472,9 @@ static int flash_sam0_init(const struct device *dev) #ifdef NVMCTRL_CTRLB_MANW /* Require an explicit write command */ NVMCTRL->CTRLB.bit.MANW = 1; +#elif NVMCTRL_CTRLA_WMODE + /* Set manual write mode */ + NVMCTRL->CTRLA.bit.WMODE = NVMCTRL_CTRLA_WMODE_MAN_Val; #endif return flash_sam0_write_protection(dev, false); diff --git a/drivers/flash/flash_simulator.c b/drivers/flash/flash_simulator.c index 7f753b534f54de5..ccbc28edfe4a4c4 100644 --- a/drivers/flash/flash_simulator.c +++ b/drivers/flash/flash_simulator.c @@ -481,12 +481,12 @@ void *z_impl_flash_simulator_get_memory(const struct device *dev, #ifdef CONFIG_USERSPACE -#include +#include void *z_vrfy_flash_simulator_get_memory(const struct device *dev, size_t *mock_size) { - Z_OOPS(Z_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_FLASH, &flash_sim_api)); + K_OOPS(K_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_FLASH, &flash_sim_api)); return z_impl_flash_simulator_get_memory(dev, mock_size); } diff --git a/drivers/flash/flash_simulator_native.c b/drivers/flash/flash_simulator_native.c index b31e42c05e07edd..44eebeba650bf63 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 cba4a76a9690562..2dcf63f32089376 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; } @@ -390,7 +390,7 @@ int flash_stm32_option_bytes_lock(const struct device *dev, bool enable) return 0; } -#if defined(CONFIG_FLASH_STM32_BLOCK_REGISTERS) +#if defined(CONFIG_FLASH_EX_OP_ENABLED) && defined(CONFIG_FLASH_STM32_BLOCK_REGISTERS) static int flash_stm32_control_register_disable(const struct device *dev) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); @@ -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 e0fba89a55039fa..3583a1379c6cd4a 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_ex_op.c b/drivers/flash/flash_stm32_ex_op.c index 1e2d801ffa59d33..623d4e23d6d07e9 100644 --- a/drivers/flash/flash_stm32_ex_op.c +++ b/drivers/flash/flash_stm32_ex_op.c @@ -11,7 +11,7 @@ #ifdef CONFIG_USERSPACE #include -#include +#include #endif #include @@ -36,7 +36,7 @@ int flash_stm32_ex_op_sector_wp(const struct device *dev, const uintptr_t in, struct flash_stm32_ex_op_sector_wp_in in_copy; if (syscall_trap) { - Z_OOPS(z_user_from_copy(&in_copy, request, + K_OOPS(k_usermode_from_copy(&in_copy, request, sizeof(in_copy))); request = &in_copy; } @@ -75,7 +75,7 @@ int flash_stm32_ex_op_sector_wp(const struct device *dev, const uintptr_t in, #ifdef CONFIG_USERSPACE if (syscall_trap) { - Z_OOPS(z_user_to_copy(out, result, sizeof(out_copy))); + K_OOPS(k_usermode_to_copy(out, result, sizeof(out_copy))); } #endif } @@ -102,7 +102,7 @@ int flash_stm32_ex_op_rdp(const struct device *dev, const uintptr_t in, if (request != NULL) { #ifdef CONFIG_USERSPACE if (syscall_trap) { - Z_OOPS(z_user_from_copy(©, request, sizeof(copy))); + K_OOPS(k_usermode_from_copy(©, request, sizeof(copy))); request = © } #endif @@ -132,7 +132,7 @@ int flash_stm32_ex_op_rdp(const struct device *dev, const uintptr_t in, #ifdef CONFIG_USERSPACE if (syscall_trap) { - Z_OOPS(z_user_to_copy(out, result, sizeof(copy))); + K_OOPS(k_usermode_to_copy(out, result, sizeof(copy))); } #endif } diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index 7e06f8ee2bede1a..9d2ed2412dc52e4 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -827,7 +827,7 @@ static int stm32_ospi_config_mem(const struct device *dev) } /* Wait that the configuration is effective and check that memory is ready */ - k_msleep(STM32_OSPI_WRITE_REG_MAX_TIME); + k_busy_wait(STM32_OSPI_WRITE_REG_MAX_TIME * USEC_PER_MSEC); /* Reconfigure the memory type of the peripheral */ dev_data->hospi.Init.MemoryType = HAL_OSPI_MEMTYPE_MACRONIX; @@ -949,8 +949,8 @@ static int stm32_ospi_mem_reset(const struct device *dev) } #endif - /* After SWreset CMD, wait in case SWReset occurred during erase operation */ - k_msleep(STM32_OSPI_RESET_MAX_TIME); + /* Wait after SWreset CMD, in case SWReset occurred during erase operation */ + k_busy_wait(STM32_OSPI_RESET_MAX_TIME * USEC_PER_MSEC); return 0; } @@ -1048,10 +1048,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 +1073,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 +1089,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); diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index 4090cd41bbbf4aa..6a9f8a585573734 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -336,8 +336,13 @@ static int qspi_read_jedec_id(const struct device *dev, uint8_t *id) static int qspi_read_sfdp(const struct device *dev, off_t addr, void *data, size_t size) { + struct flash_stm32_qspi_data *dev_data = dev->data; + HAL_StatusTypeDef hal_ret; + __ASSERT(data != NULL, "null destination"); + LOG_INF("Reading SFDP"); + QSPI_CommandTypeDef cmd = { .Instruction = JESD216_CMD_READ_SFDP, .Address = addr, @@ -346,9 +351,26 @@ static int qspi_read_sfdp(const struct device *dev, off_t addr, void *data, .InstructionMode = QSPI_INSTRUCTION_1_LINE, .AddressMode = QSPI_ADDRESS_1_LINE, .DataMode = QSPI_DATA_1_LINE, + .NbData = size, }; - return qspi_read_access(dev, &cmd, (uint8_t *)data, size); + hal_ret = HAL_QSPI_Command(&dev_data->hqspi, &cmd, + HAL_QSPI_TIMEOUT_DEFAULT_VALUE); + if (hal_ret != HAL_OK) { + LOG_ERR("%d: Failed to send SFDP instruction", hal_ret); + return -EIO; + } + + hal_ret = HAL_QSPI_Receive(&dev_data->hqspi, (uint8_t *)data, + HAL_QSPI_TIMEOUT_DEFAULT_VALUE); + if (hal_ret != HAL_OK) { + LOG_ERR("%d: Failed to read SFDP", hal_ret); + return -EIO; + } + + dev_data->cmd_status = 0; + + return 0; } static bool qspi_address_is_valid(const struct device *dev, off_t addr, @@ -615,6 +637,11 @@ static void qspi_dma_callback(const struct device *dev, void *arg, } #endif +__weak HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma) +{ + return HAL_OK; +} + __weak HAL_StatusTypeDef HAL_DMA_Abort_IT(DMA_HandleTypeDef *hdma) { return HAL_OK; diff --git a/drivers/flash/flash_stm32f1x.c b/drivers/flash/flash_stm32f1x.c index 0c54d3f69fef2e3..9a2c0bb4a903e59 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 f3781855f576cf7..a525aa8e90f0ca0 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 f94c1b2e97936a3..cc718be45936b41 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; } @@ -292,8 +313,7 @@ int flash_stm32_update_rdp(const struct device *dev, bool enable, switch (current_level) { case FLASH_STM32_RDP2: if (!enable || !permanent) { - __ASSERT(false, "RDP level 2 is permanent and can't be " - "changed!"); + LOG_ERR("RDP level 2 is permanent and can't be changed!"); return -ENOTSUP; } break; @@ -304,9 +324,8 @@ int flash_stm32_update_rdp(const struct device *dev, bool enable, #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) target_level = FLASH_STM32_RDP2; #else - __ASSERT(false, - "Permanent readout protection (RDP " - "level 0 -> 2) not allowed"); + LOG_ERR("Permanent readout protection (RDP " + "level 0 -> 2) not allowed"); return -ENOTSUP; #endif } @@ -317,8 +336,8 @@ int flash_stm32_update_rdp(const struct device *dev, bool enable, #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) target_level = FLASH_STM32_RDP2; #else - __ASSERT(false, "Permanent readout protection (RDP " - "level 1 -> 2) not allowed"); + LOG_ERR("Permanent readout protection (RDP " + "level 1 -> 2) not allowed"); return -ENOTSUP; #endif } @@ -326,8 +345,8 @@ int flash_stm32_update_rdp(const struct device *dev, bool enable, #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_DISABLE_ALLOW) target_level = FLASH_STM32_RDP0; #else - __ASSERT(false, "Disabling readout protection (RDP " - "level 1 -> 0) not allowed"); + LOG_ERR("Disabling readout protection (RDP " + "level 1 -> 0) not allowed"); return -EACCES; #endif } diff --git a/drivers/flash/flash_stm32f7x.c b/drivers/flash/flash_stm32f7x.c index b65bf25a07915c5..324b66d81979fe8 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 41a0e1da3bf8632..5c232dacc64c17c 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 e1f012c254b5e4d..631268a70c6aeba 100644 --- a/drivers/flash/flash_stm32g4x.c +++ b/drivers/flash/flash_stm32g4x.c @@ -13,6 +13,7 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #include #include #include +#include #include #include #include @@ -74,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; @@ -254,6 +255,155 @@ int flash_stm32_write_range(const struct device *dev, unsigned int offset, return rc; } +static __unused int write_optb(const struct device *dev, uint32_t mask, + uint32_t value) +{ + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + int rc; + + if (regs->CR & FLASH_CR_OPTLOCK) { + return -EIO; + } + + if ((regs->OPTR & mask) == value) { + return 0; + } + + rc = flash_stm32_wait_flash_idle(dev); + if (rc < 0) { + return rc; + } + + regs->OPTR = (regs->OPTR & ~mask) | value; + regs->CR |= FLASH_CR_OPTSTRT; + + /* Make sure previous write is completed. */ + barrier_dsync_fence_full(); + + rc = flash_stm32_wait_flash_idle(dev); + if (rc < 0) { + return rc; + } + + return 0; +} + +#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT) + +/* + * Remark for future development implementing Write Protection for the L4 parts: + * + * STM32L4 allows for 2 write protected memory areas, c.f. FLASH_WEP1AR, FLASH_WRP1BR + * which are defined by their start and end pages. + * + * Other STM32 parts (i.e. F4 series) uses bitmask to select sectors. + * + * To implement Write Protection for L4 one should thus add a new EX_OP like + * FLASH_STM32_EX_OP_SECTOR_WP_RANGED in stm32_flash_api_extensions.h + */ + +#endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */ + +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) +int flash_stm32_update_rdp(const struct device *dev, bool enable, + bool permanent) +{ + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + uint8_t current_level, target_level; + + current_level = + (regs->OPTR & FLASH_OPTR_RDP_Msk) >> FLASH_OPTR_RDP_Pos; + target_level = current_level; + + /* + * 0xAA = RDP level 0 (no protection) + * 0xCC = RDP level 2 (permanent protection) + * others = RDP level 1 (protection active) + */ + switch (current_level) { + case FLASH_STM32_RDP2: + if (!enable || !permanent) { + LOG_ERR("RDP level 2 is permanent and can't be changed!"); + return -ENOTSUP; + } + break; + case FLASH_STM32_RDP0: + if (enable) { + target_level = FLASH_STM32_RDP1; + if (permanent) { +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) + target_level = FLASH_STM32_RDP2; +#else + LOG_ERR("Permanent readout protection (RDP " + "level 0 -> 2) not allowed"); + return -ENOTSUP; +#endif + } + } + break; + default: /* FLASH_STM32_RDP1 */ + if (enable && permanent) { +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) + target_level = FLASH_STM32_RDP2; +#else + LOG_ERR("Permanent readout protection (RDP " + "level 1 -> 2) not allowed"); + return -ENOTSUP; +#endif + } + if (!enable) { +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_DISABLE_ALLOW) + target_level = FLASH_STM32_RDP0; +#else + LOG_ERR("Disabling readout protection (RDP " + "level 1 -> 0) not allowed"); + return -EACCES; +#endif + } + } + + /* Update RDP level if needed */ + if (current_level != target_level) { + LOG_INF("RDP changed from 0x%02x to 0x%02x", current_level, + target_level); + + write_optb(dev, FLASH_OPTR_RDP_Msk, + (uint32_t)target_level << FLASH_OPTR_RDP_Pos); + } + return 0; +} + +int flash_stm32_get_rdp(const struct device *dev, bool *enabled, + bool *permanent) +{ + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + uint8_t current_level; + + current_level = + (regs->OPTR & FLASH_OPTR_RDP_Msk) >> FLASH_OPTR_RDP_Pos; + + /* + * 0xAA = RDP level 0 (no protection) + * 0xCC = RDP level 2 (permanent protection) + * others = RDP level 1 (protection active) + */ + switch (current_level) { + case FLASH_STM32_RDP2: + *enabled = true; + *permanent = true; + break; + case FLASH_STM32_RDP0: + *enabled = false; + *permanent = false; + break; + default: /* FLASH_STM32_RDP1 */ + *enabled = true; + *permanent = false; + } + return 0; +} +#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */ + void flash_stm32_page_layout(const struct device *dev, const struct flash_pages_layout **layout, size_t *layout_size) diff --git a/drivers/flash/flash_stm32h7x.c b/drivers/flash/flash_stm32h7x.c index 61394164c1bdf45..271bb413194cd02 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 24644aba95e498b..d9b0fbbcbee22aa 100644 --- a/drivers/flash/flash_stm32l4x.c +++ b/drivers/flash/flash_stm32l4x.c @@ -15,6 +15,7 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #include #include #include +#include #include #include @@ -22,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 @@ -68,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; @@ -244,6 +245,157 @@ int flash_stm32_write_range(const struct device *dev, unsigned int offset, return rc; } +static __unused int write_optb(const struct device *dev, uint32_t mask, + uint32_t value) +{ + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + int rc; + + if (regs->CR & FLASH_CR_OPTLOCK) { + return -EIO; + } + + if ((regs->OPTR & mask) == value) { + return 0; + } + + rc = flash_stm32_wait_flash_idle(dev); + if (rc < 0) { + return rc; + } + + regs->OPTR = (regs->OPTR & ~mask) | value; + regs->CR |= FLASH_CR_OPTSTRT; + + /* Make sure previous write is completed. */ + barrier_dsync_fence_full(); + + rc = flash_stm32_wait_flash_idle(dev); + if (rc < 0) { + return rc; + } + + return 0; +} + +#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT) + +/* + * Remark for future development implementing Write Protection for the L4 parts: + * + * STM32L4 allows for 2 write protected memory areas, c.f. FLASH_WEP1AR, FLASH_WRP1BR + * which are defined by their start and end pages. + * + * Other STM32 parts (i.e. F4 series) uses bitmask to select sectors. + * + * To implement Write Protection for L4 one should thus add a new EX_OP like + * FLASH_STM32_EX_OP_SECTOR_WP_RANGED in stm32_flash_api_extensions.h + */ + +#endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */ + +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) +int flash_stm32_update_rdp(const struct device *dev, bool enable, + bool permanent) +{ + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + uint8_t current_level, target_level; + + current_level = + (regs->OPTR & FLASH_OPTR_RDP_Msk) >> FLASH_OPTR_RDP_Pos; + target_level = current_level; + + /* + * 0xAA = RDP level 0 (no protection) + * 0xCC = RDP level 2 (permanent protection) + * others = RDP level 1 (protection active) + */ + switch (current_level) { + case FLASH_STM32_RDP2: + if (!enable || !permanent) { + LOG_ERR("RDP level 2 is permanent and can't be changed!"); + return -ENOTSUP; + } + break; + case FLASH_STM32_RDP0: + if (enable) { + target_level = FLASH_STM32_RDP1; + if (permanent) { +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) + target_level = FLASH_STM32_RDP2; +#else + LOG_ERR("Permanent readout protection (RDP " + "level 0 -> 2) not allowed"); + return -ENOTSUP; +#endif + } + } + break; + default: /* FLASH_STM32_RDP1 */ + if (enable && permanent) { +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) + target_level = FLASH_STM32_RDP2; +#else + LOG_ERR("Permanent readout protection (RDP " + "level 1 -> 2) not allowed"); + return -ENOTSUP; +#endif + } + if (!enable) { +#if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_DISABLE_ALLOW) + target_level = FLASH_STM32_RDP0; +#else + LOG_ERR("Disabling readout protection (RDP " + "level 1 -> 0) not allowed"); + return -EACCES; +#endif + } + } + + /* Update RDP level if needed */ + if (current_level != target_level) { + LOG_INF("RDP changed from 0x%02x to 0x%02x", current_level, + target_level); + + write_optb(dev, FLASH_OPTR_RDP_Msk, + (uint32_t)target_level << FLASH_OPTR_RDP_Pos); + } + return 0; +} + +int flash_stm32_get_rdp(const struct device *dev, bool *enabled, + bool *permanent) +{ + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + uint8_t current_level; + + current_level = + (regs->OPTR & FLASH_OPTR_RDP_Msk) >> FLASH_OPTR_RDP_Pos; + + /* + * 0xAA = RDP level 0 (no protection) + * 0xCC = RDP level 2 (permanent protection) + * others = RDP level 1 (protection active) + */ + switch (current_level) { + case FLASH_STM32_RDP2: + *enabled = true; + *permanent = true; + break; + case FLASH_STM32_RDP0: + *enabled = false; + *permanent = false; + break; + default: /* FLASH_STM32_RDP1 */ + *enabled = true; + *permanent = false; + } + return 0; +} +#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */ + + + void flash_stm32_page_layout(const struct device *dev, const struct flash_pages_layout **layout, size_t *layout_size) diff --git a/drivers/flash/flash_stm32l5x.c b/drivers/flash/flash_stm32l5x.c index 8ece9b22492d2e5..59b649731e9486d 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 000000000000000..ff42c2643c533c2 --- /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 0796b9a5be40196..db158f71a9a273a 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 e72fddf756f7599..293d9c5a54ee80c 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 e2ce6e6a706808d..c0e8c397d8e9ce4 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -26,15 +26,15 @@ LOG_MODULE_REGISTER(qspi_nor, CONFIG_FLASH_LOG_LEVEL); #include struct qspi_nor_data { +#if !defined(CONFIG_PM_DEVICE_RUNTIME) && defined(CONFIG_MULTITHREADING) + /* A semaphore to control QSPI deactivation. */ + struct k_sem count; +#endif #ifdef CONFIG_MULTITHREADING - /* The semaphore to control exclusive access on write/erase. */ - struct k_sem trans; /* The semaphore to control exclusive access to the device. */ struct k_sem sem; /* The semaphore to indicate that transfer has completed. */ struct k_sem sync; - /* The semaphore to control driver init/uninit. */ - struct k_sem count; #else /* CONFIG_MULTITHREADING */ /* A flag that signals completed transfer when threads are * not enabled. @@ -173,12 +173,6 @@ BUILD_ASSERT(DT_INST_PROP(0, address_size_32), "After entering 4 byte addressing mode, 4 byte addressing is expected"); #endif -#ifndef CONFIG_PM_DEVICE_RUNTIME -static bool qspi_initialized; -#endif - -static int qspi_device_init(const struct device *dev); -static void qspi_device_uninit(const struct device *dev); void z_impl_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable); void z_vrfy_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable); @@ -245,72 +239,99 @@ static inline int qspi_get_zephyr_ret_code(nrfx_err_t res) static inline void qspi_lock(const struct device *dev) { +#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; - pm_device_busy_set(dev); - -#ifdef CONFIG_MULTITHREADING k_sem_take(&dev_data->sem, K_FOREVER); -#else /* CONFIG_MULTITHREADING */ - ARG_UNUSED(dev_data); -#endif /* CONFIG_MULTITHREADING */ - - /* - * Change the base clock divider only for the time the driver is locked - * to perform a QSPI operation, otherwise the power consumption would be - * increased also when the QSPI peripheral is idle. - * When XIP is enabled, there is nothing to do here as the changed - * divider is kept all the time. - */ -#if defined(CONFIG_SOC_SERIES_NRF53X) - if (!dev_data->xip_enabled) { - nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); - } #endif } static inline void qspi_unlock(const struct device *dev) { +#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; -#if defined(CONFIG_SOC_SERIES_NRF53X) - /* Restore the default base clock divider to reduce power consumption. - * Unless XIP is enabled, then the changed divider needs to be kept. - */ - if (!dev_data->xip_enabled) { - nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); - } + k_sem_give(&dev_data->sem); #endif +} -#ifdef CONFIG_MULTITHREADING - k_sem_give(&dev_data->sem); -#else - ARG_UNUSED(dev_data); +static inline void qspi_clock_div_change(void) +{ +#ifdef CONFIG_SOC_SERIES_NRF53X + /* Make sure the base clock divider is changed accordingly + * before a QSPI transfer is performed. + */ + nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); #endif +} - pm_device_busy_clear(dev); +static inline void qspi_clock_div_restore(void) +{ +#ifdef CONFIG_SOC_SERIES_NRF53X + /* Restore the default base clock divider to reduce power + * consumption when the QSPI peripheral is idle. + */ + nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); +#endif } -static inline void qspi_trans_lock(const struct device *dev) +static void qspi_acquire(const struct device *dev) { -#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; - k_sem_take(&dev_data->trans, K_FOREVER); -#else /* CONFIG_MULTITHREADING */ - ARG_UNUSED(dev); -#endif /* CONFIG_MULTITHREADING */ +#if defined(CONFIG_PM_DEVICE_RUNTIME) + int rc = pm_device_runtime_get(dev); + + if (rc < 0) { + LOG_ERR("pm_device_runtime_get failed: %d", rc); + } +#elif defined(CONFIG_MULTITHREADING) + /* In multithreading, the driver can call qspi_acquire more than once + * before calling qspi_release. Keeping count, so QSPI is deactivated + * only at the last call (count == 0). + */ + k_sem_give(&dev_data->count); +#endif + + qspi_lock(dev); + + if (!dev_data->xip_enabled) { + qspi_clock_div_change(); + + pm_device_busy_set(dev); + } } -static inline void qspi_trans_unlock(const struct device *dev) +static void qspi_release(const struct device *dev) { -#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; + bool deactivate = true; - k_sem_give(&dev_data->trans); -#else /* CONFIG_MULTITHREADING */ - ARG_UNUSED(dev); -#endif /* CONFIG_MULTITHREADING */ +#if !defined(CONFIG_PM_DEVICE_RUNTIME) && defined(CONFIG_MULTITHREADING) + /* The last thread to finish using the driver deactivates the QSPI */ + (void) k_sem_take(&dev_data->count, K_NO_WAIT); + deactivate = (k_sem_count_get(&dev_data->count) == 0); +#endif + + if (!dev_data->xip_enabled) { + qspi_clock_div_restore(); + + if (deactivate && !IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + (void) nrfx_qspi_deactivate(); + } + + pm_device_busy_clear(dev); + } + + qspi_unlock(dev); + +#if defined(CONFIG_PM_DEVICE_RUNTIME) + int rc = pm_device_runtime_put(dev); + + if (rc < 0) { + LOG_ERR("pm_device_runtime_put failed: %d", rc); + } +#endif } static inline void qspi_wait_for_completion(const struct device *dev, @@ -359,89 +380,6 @@ static void qspi_handler(nrfx_qspi_evt_t event, void *p_context) } } -static int qspi_device_init(const struct device *dev) -{ - struct qspi_nor_data *dev_data = dev->data; - - if (dev_data->xip_enabled) { - return 0; - } - -#ifdef CONFIG_PM_DEVICE_RUNTIME - return pm_device_runtime_get(dev); -#else - nrfx_err_t res; - int ret = 0; - - qspi_lock(dev); - - /* In multithreading, driver can call qspi_device_init more than once - * before calling qspi_device_uninit. Keepping count, so QSPI is - * uninitialized only at the last call (count == 0). - */ -#ifdef CONFIG_MULTITHREADING - k_sem_give(&dev_data->count); -#endif - - if (!qspi_initialized) { - const struct qspi_nor_config *dev_config = dev->config; - - res = nrfx_qspi_init(&dev_config->nrfx_cfg, - qspi_handler, - dev_data); - ret = qspi_get_zephyr_ret_code(res); - qspi_initialized = (ret == 0); - } - - qspi_unlock(dev); - - return ret; -#endif -} - -static void qspi_device_uninit(const struct device *dev) -{ - struct qspi_nor_data *dev_data = dev->data; - - if (dev_data->xip_enabled) { - return; - } - -#ifdef CONFIG_PM_DEVICE_RUNTIME - int ret = pm_device_runtime_put(dev); - - if (ret < 0) { - LOG_ERR("Failed to schedule device sleep: %d", ret); - } -#else - bool last = true; - - qspi_lock(dev); - -#ifdef CONFIG_MULTITHREADING - /* The last thread to finish using the driver uninit the QSPI */ - (void) k_sem_take(&dev_data->count, K_NO_WAIT); - last = (k_sem_count_get(&dev_data->count) == 0); -#endif - - if (last) { - while (nrfx_qspi_mem_busy_check() != NRFX_SUCCESS) { - if (IS_ENABLED(CONFIG_MULTITHREADING)) { - k_msleep(50); - } else { - k_busy_wait(50000); - } - } - - nrfx_qspi_uninit(); - - qspi_initialized = false; - } - - qspi_unlock(dev); -#endif -} - /* QSPI send custom command. * * If this is used for both send and receive the buffer sizes must be @@ -497,11 +435,8 @@ static int qspi_send_cmd(const struct device *dev, const struct qspi_cmd *cmd, .wren = wren, }; - qspi_lock(dev); - int res = nrfx_qspi_cinstr_xfer(&cinstr_cfg, tx_buf, rx_buf); - qspi_unlock(dev); return qspi_get_zephyr_ret_code(res); } @@ -526,27 +461,27 @@ static int qspi_rdsr(const struct device *dev, uint8_t sr_num) .op_code = opcode, .rx_buf = &sr_buf, }; - int ret = qspi_send_cmd(dev, &cmd, false); + int rc = qspi_send_cmd(dev, &cmd, false); - return (ret < 0) ? ret : sr; + return (rc < 0) ? rc : sr; } /* Wait until RDSR confirms write is not in progress. */ static int qspi_wait_while_writing(const struct device *dev) { - int ret; + int rc; do { - ret = qspi_rdsr(dev, 1); - } while ((ret >= 0) - && ((ret & SPI_NOR_WIP_BIT) != 0U)); + rc = qspi_rdsr(dev, 1); + } while ((rc >= 0) + && ((rc & SPI_NOR_WIP_BIT) != 0U)); - return (ret < 0) ? ret : 0; + return (rc < 0) ? rc : 0; } static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) { - int ret = 0; + int rc = 0; uint8_t opcode = SPI_NOR_CMD_WRSR; uint8_t length = 1; uint8_t sr_array[2] = {0}; @@ -559,12 +494,12 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) sr_array[0] = sr_val; #if SR1_WRITE_CLEARS_SR2 /* Writing sr1 clears sr2. need to read/modify/write both. */ - ret = qspi_rdsr(dev, 2); - if (ret < 0) { - LOG_ERR("RDSR for WRSR failed: %d", ret); - return ret; + rc = qspi_rdsr(dev, 2); + if (rc < 0) { + LOG_ERR("RDSR for WRSR failed: %d", rc); + return rc; } - sr_array[1] = ret; + sr_array[1] = rc; length = 2; #endif } else { /* sr_num == 2 */ @@ -574,12 +509,12 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) * Uses standard WRSR opcode */ sr_array[1] = sr_val; - ret = qspi_rdsr(dev, 1); - if (ret < 0) { - LOG_ERR("RDSR for WRSR failed: %d", ret); - return ret; + rc = qspi_rdsr(dev, 1); + if (rc < 0) { + LOG_ERR("RDSR for WRSR failed: %d", rc); + return rc; } - sr_array[0] = ret; + sr_array[0] = rc; length = 2; #elif IS_EQUAL(INST_0_QER, JESD216_DW15_QER_VAL_S2B1v6) /* Writing sr2 uses a dedicated WRSR2 command */ @@ -600,46 +535,30 @@ static int qspi_wrsr(const struct device *dev, uint8_t sr_val, uint8_t sr_num) .tx_buf = &sr_buf, }; - ret = qspi_send_cmd(dev, &cmd, true); + rc = qspi_send_cmd(dev, &cmd, true); /* Writing SR can take some time, and further * commands sent while it's happening can be * corrupted. Wait. */ - if (ret == 0) { - ret = qspi_wait_while_writing(dev); + if (rc == 0) { + rc = qspi_wait_while_writing(dev); } - return ret; + return rc; } #endif /* !IS_EQUAL(INST_0_QER, JESD216_DW15_QER_VAL_NONE) */ /* QSPI erase */ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) { - /* address must be sector-aligned */ - if ((addr % QSPI_SECTOR_SIZE) != 0) { - return -EINVAL; - } - - /* size must be a non-zero multiple of sectors */ - if ((size == 0) || (size % QSPI_SECTOR_SIZE) != 0) { - return -EINVAL; - } - - int rv = 0; const struct qspi_nor_config *params = dev->config; + int rc, rc2; - rv = qspi_device_init(dev); - if (rv != 0) { - goto out; - } - qspi_trans_lock(dev); - rv = qspi_nor_write_protection_set(dev, false); - if (rv != 0) { - goto out_trans_unlock; + rc = qspi_nor_write_protection_set(dev, false); + if (rc != 0) { + return rc; } - qspi_lock(dev); while (size > 0) { nrfx_err_t res = !NRFX_SUCCESS; uint32_t adj = 0; @@ -670,76 +589,20 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size) size -= adj; } else { LOG_ERR("erase error at 0x%lx size %zu", (long)addr, size); - rv = qspi_get_zephyr_ret_code(res); + rc = qspi_get_zephyr_ret_code(res); break; } } - qspi_unlock(dev); - - int rv2 = qspi_nor_write_protection_set(dev, true); - - if (!rv) { - rv = rv2; - } -out_trans_unlock: - qspi_trans_unlock(dev); + rc2 = qspi_nor_write_protection_set(dev, true); -out: - qspi_device_uninit(dev); - return rv; + return rc != 0 ? rc : rc2; } -/* Configures QSPI memory for the transfer */ -static int qspi_nrfx_configure(const struct device *dev) +static int configure_chip(const struct device *dev) { - struct qspi_nor_data *dev_data = dev->data; const struct qspi_nor_config *dev_config = dev->config; - -#if defined(CONFIG_SOC_SERIES_NRF53X) - /* When the QSPI peripheral is activated, during the nrfx_qspi driver - * initialization, it reads the status of the connected flash chip. - * Make sure this transaction is performed with a valid base clock - * divider. - */ - nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); -#endif - - nrfx_err_t res = nrfx_qspi_init(&dev_config->nrfx_cfg, - qspi_handler, - dev_data); - -#if defined(CONFIG_SOC_SERIES_NRF53X) - /* Restore the default /4 divider after the QSPI initialization. */ - nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); -#endif - - int ret = qspi_get_zephyr_ret_code(res); - if (ret < 0) { - return ret; - } - -#if DT_INST_NODE_HAS_PROP(0, rx_delay) - if (!nrf53_errata_121()) { - nrf_qspi_iftiming_set(NRF_QSPI, DT_INST_PROP(0, rx_delay)); - } -#endif - - /* It may happen that after the flash chip was previously put into - * the DPD mode, the system was reset but the flash chip was not. - * Consequently, the flash chip can be in the DPD mode at this point. - * Some flash chips will just exit the DPD mode on the first CS pulse, - * but some need to receive the dedicated command to do it, so send it. - * This can be the case even if the current image does not have - * CONFIG_PM_DEVICE set to enter DPD mode, as a previously executing image - * (for example the main image if the currently executing image is the - * bootloader) might have set DPD mode before reboot. As a result, - * attempt to exit DPD mode regardless of whether CONFIG_PM_DEVICE is set. - */ - ret = exit_dpd(dev); - if (ret < 0) { - return ret; - } + int rc = 0; /* Set QE to match transfer mode. If not using quad * it's OK to leave QE set, but doing so prevents use @@ -769,28 +632,28 @@ static int qspi_nrfx_configure(const struct device *dev) return -EINVAL; #endif - ret = qspi_rdsr(dev, sr_num); - if (ret < 0) { - LOG_ERR("RDSR failed: %d", ret); - return ret; + rc = qspi_rdsr(dev, sr_num); + if (rc < 0) { + LOG_ERR("RDSR failed: %d", rc); + return rc; } - uint8_t sr = (uint8_t)ret; + uint8_t sr = (uint8_t)rc; bool qe_state = ((sr & qe_mask) != 0U); LOG_DBG("RDSR %02x QE %d need %d: %s", sr, qe_state, qe_value, (qe_state != qe_value) ? "updating" : "no-change"); - ret = 0; + rc = 0; if (qe_state != qe_value) { sr ^= qe_mask; - ret = qspi_wrsr(dev, sr, sr_num); + rc = qspi_wrsr(dev, sr, sr_num); } - if (ret < 0) { + if (rc < 0) { LOG_ERR("QE %s failed: %d", qe_value ? "set" : "clear", - ret); - return ret; + rc); + return rc; } #endif @@ -802,20 +665,19 @@ static int qspi_nrfx_configure(const struct device *dev) /* Call will send write enable before instruction if that * requirement is encoded in INST_0_4BA. */ - ret = qspi_send_cmd(dev, &cmd, (INST_0_4BA & 0x02)); + rc = qspi_send_cmd(dev, &cmd, (INST_0_4BA & 0x02)); - if (ret < 0) { - LOG_ERR("E4BA cmd issue failed: %d.", ret); + if (rc < 0) { + LOG_ERR("E4BA cmd issue failed: %d.", rc); } else { LOG_DBG("E4BA cmd issued."); } } - return ret; + return rc; } -static int qspi_read_jedec_id(const struct device *dev, - uint8_t *id) +static int qspi_rdid(const struct device *dev, uint8_t *id) { const struct qspi_buf rx_buf = { .buf = id, @@ -826,18 +688,24 @@ static int qspi_read_jedec_id(const struct device *dev, .rx_buf = &rx_buf, }; - int ret = qspi_device_init(dev); - - if (ret == 0) { - ret = qspi_send_cmd(dev, &cmd, false); - } - qspi_device_uninit(dev); - - return ret; + return qspi_send_cmd(dev, &cmd, false); } #if defined(CONFIG_FLASH_JESD216_API) +static int qspi_read_jedec_id(const struct device *dev, uint8_t *id) +{ + int rc; + + qspi_acquire(dev); + + rc = qspi_rdid(dev, id); + + qspi_release(dev); + + return rc; +} + static int qspi_sfdp_read(const struct device *dev, off_t offset, void *data, size_t len) { @@ -855,17 +723,10 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, .io2_level = true, .io3_level = true, }; + nrfx_err_t res; - int ret = qspi_device_init(dev); - nrfx_err_t res = NRFX_SUCCESS; - - if (ret != 0) { - LOG_DBG("qspi_device_init: %d", ret); - qspi_device_uninit(dev); - return ret; - } + qspi_acquire(dev); - qspi_lock(dev); res = nrfx_qspi_lfm_start(&cinstr_cfg); if (res != NRFX_SUCCESS) { LOG_DBG("lfm_start: %x", res); @@ -885,40 +746,13 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset, } out: - qspi_unlock(dev); - qspi_device_uninit(dev); + qspi_release(dev); + return qspi_get_zephyr_ret_code(res); } #endif /* CONFIG_FLASH_JESD216_API */ -/** - * @brief Retrieve the Flash JEDEC ID and compare it with the one expected - * - * @param dev The device structure - * @return 0 on success, negative errno code otherwise - */ -static inline int qspi_nor_read_id(const struct device *dev) -{ - uint8_t id[SPI_NOR_MAX_ID_LEN]; - int ret = qspi_read_jedec_id(dev, id); - - if (ret != 0) { - return -EIO; - } - - const struct qspi_nor_config *qnc = dev->config; - - if (memcmp(qnc->id, id, SPI_NOR_MAX_ID_LEN) != 0) { - LOG_ERR("JEDEC id [%02x %02x %02x] expect [%02x %02x %02x]", - id[0], id[1], id[2], - qnc->id[0], qnc->id[1], qnc->id[2]); - return -ENODEV; - } - - return 0; -} - static inline nrfx_err_t read_non_aligned(const struct device *dev, off_t addr, void *dest, size_t size) @@ -993,6 +827,9 @@ static inline nrfx_err_t read_non_aligned(const struct device *dev, static int qspi_nor_read(const struct device *dev, off_t addr, void *dest, size_t size) { + const struct qspi_nor_config *params = dev->config; + nrfx_err_t res; + if (!dest) { return -EINVAL; } @@ -1002,8 +839,6 @@ static int qspi_nor_read(const struct device *dev, off_t addr, void *dest, return 0; } - const struct qspi_nor_config *params = dev->config; - /* affected region should be within device */ if (addr < 0 || (addr + size) > params->size) { @@ -1013,23 +848,13 @@ static int qspi_nor_read(const struct device *dev, off_t addr, void *dest, return -EINVAL; } - int rc = qspi_device_init(dev); - - if (rc != 0) { - goto out; - } - - qspi_lock(dev); + qspi_acquire(dev); - nrfx_err_t res = read_non_aligned(dev, addr, dest, size); + res = read_non_aligned(dev, addr, dest, size); - qspi_unlock(dev); + qspi_release(dev); - rc = qspi_get_zephyr_ret_code(res); - -out: - qspi_device_uninit(dev); - return rc; + return qspi_get_zephyr_ret_code(res); } /* addr aligned, sptr not null, slen less than 4 */ @@ -1094,6 +919,9 @@ static int qspi_nor_write(const struct device *dev, off_t addr, const void *src, size_t size) { + const struct qspi_nor_config *params = dev->config; + int rc, rc2; + if (!src) { return -EINVAL; } @@ -1108,8 +936,6 @@ static int qspi_nor_write(const struct device *dev, off_t addr, return -EINVAL; } - const struct qspi_nor_config *params = dev->config; - /* affected region should be within device */ if (addr < 0 || (addr + size) > params->size) { @@ -1119,18 +945,12 @@ static int qspi_nor_write(const struct device *dev, off_t addr, return -EINVAL; } - nrfx_err_t res = NRFX_SUCCESS; + qspi_acquire(dev); - int rc = qspi_device_init(dev); - - if (rc != 0) { - goto out; - } + rc = qspi_nor_write_protection_set(dev, false); + if (rc == 0) { + nrfx_err_t res; - qspi_trans_lock(dev); - res = qspi_nor_write_protection_set(dev, false); - qspi_lock(dev); - if (!res) { if (size < 4U) { res = write_sub_word(dev, addr, src, size); } else if (!nrfx_is_in_ram(src) || @@ -1140,25 +960,31 @@ static int qspi_nor_write(const struct device *dev, off_t addr, res = nrfx_qspi_write(src, size, addr); qspi_wait_for_completion(dev, res); } + + rc = qspi_get_zephyr_ret_code(res); } - qspi_unlock(dev); - int res2 = qspi_nor_write_protection_set(dev, true); + rc2 = qspi_nor_write_protection_set(dev, true); - qspi_trans_unlock(dev); - if (!res) { - res = res2; - } + qspi_release(dev); - rc = qspi_get_zephyr_ret_code(res); -out: - qspi_device_uninit(dev); - return rc; + return rc != 0 ? rc : rc2; } static int qspi_nor_erase(const struct device *dev, off_t addr, size_t size) { const struct qspi_nor_config *params = dev->config; + int rc; + + /* address must be sector-aligned */ + if ((addr % QSPI_SECTOR_SIZE) != 0) { + return -EINVAL; + } + + /* size must be a non-zero multiple of sectors */ + if ((size == 0) || (size % QSPI_SECTOR_SIZE) != 0) { + return -EINVAL; + } /* affected region should be within device */ if (addr < 0 || @@ -1169,83 +995,117 @@ static int qspi_nor_erase(const struct device *dev, off_t addr, size_t size) return -EINVAL; } - int ret = qspi_erase(dev, addr, size); + qspi_acquire(dev); + + rc = qspi_erase(dev, addr, size); - return ret; + qspi_release(dev); + + return rc; } static int qspi_nor_write_protection_set(const struct device *dev, bool write_protect) { - int ret = 0; + int rc = 0; struct qspi_cmd cmd = { .op_code = ((write_protect) ? SPI_NOR_CMD_WRDI : SPI_NOR_CMD_WREN), }; if (qspi_send_cmd(dev, &cmd, false) != 0) { - ret = -EIO; + rc = -EIO; } - return ret; + return rc; } -/** - * @brief Configure the flash - * - * @param dev The flash device structure - * @param info The flash info structure - * @return 0 on success, negative errno code otherwise - */ -static int qspi_nor_configure(const struct device *dev) +static int qspi_init(const struct device *dev) { - int ret = qspi_nrfx_configure(dev); + const struct qspi_nor_config *dev_config = dev->config; + uint8_t id[SPI_NOR_MAX_ID_LEN]; + nrfx_err_t res; + int rc; - if (ret != 0) { - return ret; + res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev->data); + rc = qspi_get_zephyr_ret_code(res); + if (rc < 0) { + return rc; } -#ifdef CONFIG_PM_DEVICE_RUNTIME - ret = pm_device_runtime_enable(dev); - if (ret < 0) { - LOG_ERR("Failed to enable runtime power management: %d", ret); - } else { - LOG_DBG("Runtime power management enabled"); +#if DT_INST_NODE_HAS_PROP(0, rx_delay) + if (!nrf53_errata_121()) { + nrf_qspi_iftiming_set(NRF_QSPI, DT_INST_PROP(0, rx_delay)); } -#else - qspi_device_uninit(dev); #endif - /* now the spi bus is configured, we can verify the flash id */ - if (qspi_nor_read_id(dev) != 0) { + /* It may happen that after the flash chip was previously put into + * the DPD mode, the system was reset but the flash chip was not. + * Consequently, the flash chip can be in the DPD mode at this point. + * Some flash chips will just exit the DPD mode on the first CS pulse, + * but some need to receive the dedicated command to do it, so send it. + * This can be the case even if the current image does not have + * CONFIG_PM_DEVICE set to enter DPD mode, as a previously executing image + * (for example the main image if the currently executing image is the + * bootloader) might have set DPD mode before reboot. As a result, + * attempt to exit DPD mode regardless of whether CONFIG_PM_DEVICE is set. + */ + rc = exit_dpd(dev); + if (rc < 0) { + return rc; + } + + /* Retrieve the Flash JEDEC ID and compare it with the one expected. */ + rc = qspi_rdid(dev, id); + if (rc < 0) { + return rc; + } + + if (memcmp(dev_config->id, id, SPI_NOR_MAX_ID_LEN) != 0) { + LOG_ERR("JEDEC id [%02x %02x %02x] expect [%02x %02x %02x]", + id[0], id[1], id[2], dev_config->id[0], + dev_config->id[1], dev_config->id[2]); return -ENODEV; } - return 0; + /* The chip is correct, it can be configured now. */ + return configure_chip(dev); } -/** - * @brief Initialize and configure the flash - * - * @param name The flash name - * @return 0 on success, negative errno code otherwise - */ static int qspi_nor_init(const struct device *dev) { - int rc; const struct qspi_nor_config *dev_config = dev->config; - int ret = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); + int rc; - if (ret < 0) { - return ret; + rc = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); + if (rc < 0) { + return rc; } IRQ_CONNECT(DT_IRQN(QSPI_NODE), DT_IRQ(QSPI_NODE, priority), nrfx_isr, nrfx_qspi_irq_handler, 0); - rc = qspi_nor_configure(dev); + qspi_clock_div_change(); + + rc = qspi_init(dev); + + qspi_clock_div_restore(); + + if (!IS_ENABLED(CONFIG_NORDIC_QSPI_NOR_XIP) && nrfx_qspi_init_check()) { + (void)nrfx_qspi_deactivate(); + } + +#ifdef CONFIG_PM_DEVICE_RUNTIME + int rc2 = pm_device_runtime_enable(dev); + + if (rc2 < 0) { + LOG_ERR("Failed to enable runtime power management: %d", rc2); + } else { + LOG_DBG("Runtime power management enabled"); + } +#endif #ifdef CONFIG_NORDIC_QSPI_NOR_XIP - if (!rc) { + if (rc == 0) { /* Enable XIP mode for QSPI NOR flash, this will prevent the * flash from being powered down */ @@ -1317,11 +1177,11 @@ static int enter_dpd(const struct device *const dev) .op_code = SPI_NOR_CMD_DPD, }; uint32_t t_enter_dpd = DT_INST_PROP_OR(0, t_enter_dpd, 0); - int ret; + int rc; - ret = qspi_send_cmd(dev, &cmd, false); - if (ret < 0) { - return ret; + rc = qspi_send_cmd(dev, &cmd, false); + if (rc < 0) { + return rc; } if (t_enter_dpd) { @@ -1339,15 +1199,34 @@ static int enter_dpd(const struct device *const dev) static int exit_dpd(const struct device *const dev) { if (IS_ENABLED(DT_INST_PROP(0, has_dpd))) { + nrf_qspi_pins_t pins; + nrf_qspi_pins_t disconnected_pins = { + .sck_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .csn_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .io0_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .io1_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .io2_pin = NRF_QSPI_PIN_NOT_CONNECTED, + .io3_pin = NRF_QSPI_PIN_NOT_CONNECTED, + }; struct qspi_cmd cmd = { .op_code = SPI_NOR_CMD_RDPD, }; uint32_t t_exit_dpd = DT_INST_PROP_OR(0, t_exit_dpd, 0); - int ret; + nrfx_err_t res; + int rc; + + nrf_qspi_pins_get(NRF_QSPI, &pins); + nrf_qspi_pins_set(NRF_QSPI, &disconnected_pins); + res = nrfx_qspi_activate(true); + nrf_qspi_pins_set(NRF_QSPI, &pins); + + if (res != NRFX_SUCCESS) { + return -EIO; + } - ret = qspi_send_cmd(dev, &cmd, false); - if (ret < 0) { - return ret; + rc = qspi_send_cmd(dev, &cmd, false); + if (rc < 0) { + return rc; } if (t_exit_dpd) { @@ -1362,113 +1241,105 @@ static int exit_dpd(const struct device *const dev) } #ifdef CONFIG_PM_DEVICE -static int qspi_nor_pm_action(const struct device *dev, - enum pm_device_action action) +static int qspi_suspend(const struct device *dev) { - struct qspi_nor_data *dev_data = dev->data; const struct qspi_nor_config *dev_config = dev->config; - int ret; - nrfx_err_t err; + nrfx_err_t res; + int rc; - if (pm_device_is_busy(dev)) { + res = nrfx_qspi_mem_busy_check(); + if (res != NRFX_SUCCESS) { return -EBUSY; } - switch (action) { - case PM_DEVICE_ACTION_SUSPEND: -#ifndef CONFIG_PM_DEVICE_RUNTIME - /* If PM_DEVICE_RUNTIME, we don't uninit after RESUME */ - ret = qspi_device_init(dev); - if (ret < 0) { - return ret; - } -#endif + rc = enter_dpd(dev); + if (rc < 0) { + return rc; + } - if (dev_data->xip_enabled) { - return -EBUSY; - } + nrfx_qspi_uninit(); - if (nrfx_qspi_mem_busy_check() != NRFX_SUCCESS) { - return -EBUSY; - } + return pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); +} - ret = enter_dpd(dev); - if (ret < 0) { - return ret; - } +static int qspi_resume(const struct device *dev) +{ + const struct qspi_nor_config *dev_config = dev->config; + nrfx_err_t res; + int rc; - nrfx_qspi_uninit(); - ret = pinctrl_apply_state(dev_config->pcfg, - PINCTRL_STATE_SLEEP); - if (ret < 0) { - return ret; - } - break; + rc = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); + if (rc < 0) { + return rc; + } - case PM_DEVICE_ACTION_RESUME: - ret = pinctrl_apply_state(dev_config->pcfg, - PINCTRL_STATE_DEFAULT); - if (ret < 0) { - return ret; - } - err = nrfx_qspi_init(&dev_config->nrfx_cfg, - qspi_handler, - dev_data); - if (err != NRFX_SUCCESS) { - return -EIO; - } + res = nrfx_qspi_init(&dev_config->nrfx_cfg, qspi_handler, dev->data); + if (res != NRFX_SUCCESS) { + return -EIO; + } - ret = exit_dpd(dev); - if (ret < 0) { - return ret; - } + return exit_dpd(dev); +} -#ifndef CONFIG_PM_DEVICE_RUNTIME - /* If PM_DEVICE_RUNTIME, we're immediately going to use the device */ - qspi_device_uninit(dev); -#endif +static int qspi_nor_pm_action(const struct device *dev, + enum pm_device_action action) +{ + int rc; + + if (pm_device_is_busy(dev)) { + return -EBUSY; + } + + qspi_lock(dev); + qspi_clock_div_change(); + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + rc = qspi_suspend(dev); + break; + + case PM_DEVICE_ACTION_RESUME: + rc = qspi_resume(dev); break; default: - return -ENOTSUP; + rc = -ENOTSUP; } - return 0; + qspi_clock_div_restore(); + qspi_unlock(dev); + + return rc; } #endif /* CONFIG_PM_DEVICE */ void z_impl_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable) { struct qspi_nor_data *dev_data = dev->data; - int ret; if (dev_data->xip_enabled == enable) { return; } - ret = qspi_device_init(dev); - - if (ret != 0) { - LOG_ERR("NRF QSPI NOR XIP %s failed with %d\n", enable ? "enable" : "disable", ret); - return; - } + qspi_acquire(dev); #if NRF_QSPI_HAS_XIPEN nrf_qspi_xip_set(NRF_QSPI, enable); #endif - qspi_lock(dev); + if (enable) { + (void)nrfx_qspi_activate(false); + } dev_data->xip_enabled = enable; - qspi_unlock(dev); - qspi_device_uninit(dev); + qspi_release(dev); } #ifdef CONFIG_USERSPACE -#include +#include void z_vrfy_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable) { - Z_OOPS(Z_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_FLASH, + K_OOPS(K_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_FLASH, &qspi_nor_api)); z_impl_nrf_qspi_nor_xip_enable(dev, enable); @@ -1478,11 +1349,12 @@ void z_vrfy_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable) #endif /* CONFIG_USERSPACE */ static struct qspi_nor_data qspi_nor_dev_data = { +#if !defined(CONFIG_PM_DEVICE_RUNTIME) && defined(CONFIG_MULTITHREADING) + .count = Z_SEM_INITIALIZER(qspi_nor_dev_data.count, 0, K_SEM_MAX_LIMIT), +#endif #ifdef CONFIG_MULTITHREADING - .trans = Z_SEM_INITIALIZER(qspi_nor_dev_data.trans, 1, 1), .sem = Z_SEM_INITIALIZER(qspi_nor_dev_data.sem, 1, 1), .sync = Z_SEM_INITIALIZER(qspi_nor_dev_data.sync, 0, 1), - .count = Z_SEM_INITIALIZER(qspi_nor_dev_data.count, 0, K_SEM_MAX_LIMIT), #endif /* CONFIG_MULTITHREADING */ }; @@ -1514,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 88d9725168e05f8..065795d4924c1db 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); @@ -226,7 +233,7 @@ static inline uint32_t dev_flash_size(const struct device *dev) static inline uint16_t dev_page_size(const struct device *dev) { #ifdef CONFIG_SPI_NOR_SFDP_MINIMAL - return 256; + return DT_INST_PROP_OR(0, page_size, 256); #else /* CONFIG_SPI_NOR_SFDP_MINIMAL */ const struct spi_nor_data *data = dev->data; @@ -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; @@ -702,6 +720,34 @@ static int spi_nor_read(const struct device *dev, off_t addr, void *dest, return ret; } +#if defined(CONFIG_FLASH_EX_OP_ENABLED) +static int flash_spi_nor_ex_op(const struct device *dev, uint16_t code, + const uintptr_t in, void *out) +{ + int ret; + + ARG_UNUSED(in); + ARG_UNUSED(out); + + acquire_device(dev); + + switch (code) { + case FLASH_EX_OP_RESET: + ret = spi_nor_cmd_write(dev, SPI_NOR_CMD_RESET_EN); + if (ret == 0) { + ret = spi_nor_cmd_write(dev, SPI_NOR_CMD_RESET_MEM); + } + break; + default: + ret = -ENOTSUP; + break; + } + + release_device(dev); + return ret; +} +#endif + static int spi_nor_write(const struct device *dev, off_t addr, const void *src, size_t size) @@ -743,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); } } @@ -825,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); @@ -1029,10 +1075,10 @@ static int spi_nor_process_sfdp(const struct device *dev) /* We only process BFP so use one parameter block */ uint8_t raw[JESD216_SFDP_SIZE(decl_nph)]; struct jesd216_sfdp_header sfdp; - } u; - const struct jesd216_sfdp_header *hp = &u.sfdp; + } u_header; + const struct jesd216_sfdp_header *hp = &u_header.sfdp; - rc = spi_nor_sfdp_read(dev, 0, u.raw, sizeof(u.raw)); + rc = spi_nor_sfdp_read(dev, 0, u_header.raw, sizeof(u_header.raw)); if (rc != 0) { LOG_ERR("SFDP read failed: %d", rc); return rc; @@ -1062,10 +1108,11 @@ static int spi_nor_process_sfdp(const struct device *dev) union { uint32_t dw[MIN(php->len_dw, 20)]; struct jesd216_bfp bfp; - } u; - const struct jesd216_bfp *bfp = &u.bfp; + } u_param; + const struct jesd216_bfp *bfp = &u_param.bfp; - rc = spi_nor_sfdp_read(dev, jesd216_param_addr(php), u.dw, sizeof(u.dw)); + rc = spi_nor_sfdp_read(dev, jesd216_param_addr(php), + u_param.dw, sizeof(u_param.dw)); if (rc == 0) { rc = spi_nor_process_bfp(dev, php, bfp); } @@ -1202,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); @@ -1251,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 @@ -1330,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; @@ -1426,6 +1484,9 @@ static const struct flash_driver_api spi_nor_api = { .sfdp_read = spi_nor_sfdp_read, .read_jedec_id = spi_nor_read_jedec_id, #endif +#if defined(CONFIG_FLASH_EX_OP_ENABLED) + .ex_op = flash_spi_nor_ex_op, +#endif }; #ifndef CONFIG_SPI_NOR_SFDP_RUNTIME diff --git a/drivers/fpga/fpga_zynqmp.c b/drivers/fpga/fpga_zynqmp.c index 8da54462fae6b14..8181edf5c75b065 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/emul_fuel_gauge_syscall_handlers.c b/drivers/fuel_gauge/emul_fuel_gauge_syscall_handlers.c index a6b8ce6ee02c6e6..2382fcad77b4019 100644 --- a/drivers/fuel_gauge/emul_fuel_gauge_syscall_handlers.c +++ b/drivers/fuel_gauge/emul_fuel_gauge_syscall_handlers.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include /* Emulator syscalls just need to exist as stubs as these are only called by tests. */ diff --git a/drivers/fuel_gauge/fuel_gauge_syscall_handlers.c b/drivers/fuel_gauge/fuel_gauge_syscall_handlers.c index 6bcd5bd22055101..312564c35a62fa7 100644 --- a/drivers/fuel_gauge/fuel_gauge_syscall_handlers.c +++ b/drivers/fuel_gauge/fuel_gauge_syscall_handlers.c @@ -5,7 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include static inline int z_vrfy_fuel_gauge_get_prop(const struct device *dev, fuel_gauge_prop_t prop, @@ -13,13 +13,13 @@ static inline int z_vrfy_fuel_gauge_get_prop(const struct device *dev, fuel_gaug { union fuel_gauge_prop_val k_val; - Z_OOPS(Z_SYSCALL_DRIVER_FUEL_GAUGE(dev, get_property)); + K_OOPS(K_SYSCALL_DRIVER_FUEL_GAUGE(dev, get_property)); - Z_OOPS(z_user_from_copy(&k_val, val, sizeof(union fuel_gauge_prop_val))); + K_OOPS(k_usermode_from_copy(&k_val, val, sizeof(union fuel_gauge_prop_val))); int ret = z_impl_fuel_gauge_get_prop(dev, prop, &k_val); - Z_OOPS(z_user_to_copy(val, &k_val, sizeof(union fuel_gauge_prop_val))); + K_OOPS(k_usermode_to_copy(val, &k_val, sizeof(union fuel_gauge_prop_val))); return ret; } @@ -32,14 +32,14 @@ static inline int z_vrfy_fuel_gauge_get_props(const struct device *dev, fuel_gau union fuel_gauge_prop_val k_vals[len]; fuel_gauge_prop_t k_props[len]; - Z_OOPS(Z_SYSCALL_DRIVER_FUEL_GAUGE(dev, get_property)); + K_OOPS(K_SYSCALL_DRIVER_FUEL_GAUGE(dev, get_property)); - Z_OOPS(z_user_from_copy(k_vals, vals, len * sizeof(union fuel_gauge_prop_val))); - Z_OOPS(z_user_from_copy(k_props, props, len * sizeof(fuel_gauge_prop_t))); + K_OOPS(k_usermode_from_copy(k_vals, vals, len * sizeof(union fuel_gauge_prop_val))); + K_OOPS(k_usermode_from_copy(k_props, props, len * sizeof(fuel_gauge_prop_t))); int ret = z_impl_fuel_gauge_get_props(dev, k_props, k_vals, len); - Z_OOPS(z_user_to_copy(vals, k_vals, len * sizeof(union fuel_gauge_prop_val))); + K_OOPS(k_usermode_to_copy(vals, k_vals, len * sizeof(union fuel_gauge_prop_val))); return ret; } @@ -49,7 +49,7 @@ static inline int z_vrfy_fuel_gauge_get_props(const struct device *dev, fuel_gau static inline int z_vrfy_fuel_gauge_set_prop(const struct device *dev, fuel_gauge_prop_t prop, union fuel_gauge_prop_val val) { - Z_OOPS(Z_SYSCALL_DRIVER_FUEL_GAUGE(dev, set_property)); + K_OOPS(K_SYSCALL_DRIVER_FUEL_GAUGE(dev, set_property)); int ret = z_impl_fuel_gauge_set_prop(dev, prop, val); @@ -64,15 +64,15 @@ static inline int z_vrfy_fuel_gauge_set_props(const struct device *dev, fuel_gau union fuel_gauge_prop_val k_vals[len]; fuel_gauge_prop_t k_props[len]; - Z_OOPS(Z_SYSCALL_DRIVER_FUEL_GAUGE(dev, set_property)); + K_OOPS(K_SYSCALL_DRIVER_FUEL_GAUGE(dev, set_property)); - Z_OOPS(z_user_from_copy(k_vals, vals, len * sizeof(union fuel_gauge_prop_val))); - Z_OOPS(z_user_from_copy(k_props, props, len * sizeof(fuel_gauge_prop_t))); + K_OOPS(k_usermode_from_copy(k_vals, vals, len * sizeof(union fuel_gauge_prop_val))); + K_OOPS(k_usermode_from_copy(k_props, props, len * sizeof(fuel_gauge_prop_t))); int ret = z_impl_fuel_gauge_set_props(dev, k_props, k_vals, len); /* We only copy back vals because props will never be modified */ - Z_OOPS(z_user_to_copy(vals, k_vals, len * sizeof(union fuel_gauge_prop_val))); + K_OOPS(k_usermode_to_copy(vals, k_vals, len * sizeof(union fuel_gauge_prop_val))); return ret; } @@ -83,9 +83,9 @@ static inline int z_vrfy_fuel_gauge_get_buffer_prop(const struct device *dev, fuel_gauge_prop_t prop, void *dst, size_t dst_len) { - Z_OOPS(Z_SYSCALL_DRIVER_FUEL_GAUGE(dev, get_buffer_property)); + K_OOPS(K_SYSCALL_DRIVER_FUEL_GAUGE(dev, get_buffer_property)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(dst, dst_len)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(dst, dst_len)); int ret = z_impl_fuel_gauge_get_buffer_prop(dev, prop, dst, dst_len); @@ -96,7 +96,7 @@ static inline int z_vrfy_fuel_gauge_get_buffer_prop(const struct device *dev, static inline int z_vrfy_fuel_gauge_battery_cutoff(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_FUEL_GAUGE(dev, battery_cutoff)); + K_OOPS(K_SYSCALL_DRIVER_FUEL_GAUGE(dev, battery_cutoff)); return z_impl_fuel_gauge_battery_cutoff(dev); } diff --git a/drivers/fuel_gauge/sbs_gauge/sbs_gauge.c b/drivers/fuel_gauge/sbs_gauge/sbs_gauge.c index 4c9ba6702aadae2..79537d2f50978b5 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 new file mode 100644 index 000000000000000..cfa5c6ed210a066 --- /dev/null +++ b/drivers/gnss/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(gnss_publish.c) +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 new file mode 100644 index 000000000000000..2ff552940a34b54 --- /dev/null +++ b/drivers/gnss/Kconfig @@ -0,0 +1,70 @@ +# Copyright (c) 2023 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +menuconfig GNSS + bool "GNSS drivers" + select EXPERIMENTAL + help + Enable GNSS drivers and configuration. + +if GNSS + +config GNSS_SATELLITES + bool "GNSS satellites support" + help + Enable GNSS sattelites callback. + +config GNSS_DUMP + bool "GNSS dump support" + depends on LOG + help + Enable GNSS dump library + +config GNSS_DUMP_TO_LOG + bool "Dump GNSS events to log" + select GNSS_DUMP + help + Enable GNSS dump to log. + +if GNSS_DUMP_TO_LOG + +config GNSS_DUMP_TO_LOG_BUF_SIZE + int "GNSS log dump buffer size" + default 128 + help + Size of GNSS log dump buffer + +endif + +config GNSS_PARSE + bool "GNSS parsing utilities" + help + Enable GNSS parsing utilities. + +config GNSS_NMEA0183 + bool "NMEA0183 parsing utilities" + select GNSS_PARSE + help + Enable NMEA0183 parsing utilities. + +config GNSS_NMEA0183_MATCH + bool "GNSS NMEA0183 match utilities" + select GNSS_NMEA0183 + help + Enable NMEA0183 match utilities. + +config GNSS_INIT_PRIORITY + int "GNSS driver initialization priority" + default 80 + range 0 99 + help + Driver initialization priority for GNSS drivers. + +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 000000000000000..47fbd4a7c6c887d --- /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 new file mode 100644 index 000000000000000..3036f76d05be199 --- /dev/null +++ b/drivers/gnss/Kconfig.quectel_lcx6g @@ -0,0 +1,37 @@ +# Copyright (c) 2023 Trackunit Corporation +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +config GNSS_QUECTEL_LCX6G + bool "Quectel LCX6G GNSS modem driver" + default y + depends on GNSS + depends on DT_HAS_QUECTEL_LC26G_ENABLED || DT_HAS_QUECTEL_LC76G_ENABLED || DT_HAS_QUECTEL_LC86G_ENABLED + select MODEM_MODULES + select MODEM_BACKEND_UART + select MODEM_CHAT + select GNSS_PARSE + select GNSS_NMEA0183 + 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 new file mode 100644 index 000000000000000..f87b64a4946f81f --- /dev/null +++ b/drivers/gnss/gnss_dump.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2023 Bjarki Arge Andreasen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "gnss_dump.h" +#include +#include +#include + +#include + +#if CONFIG_GNSS_DUMP_TO_LOG +static char dump_buf[CONFIG_GNSS_DUMP_TO_LOG_BUF_SIZE]; +#endif /* CONFIG_GNSS_DUMP_TO_LOG */ + +static const char *gnss_fix_status_to_str(enum gnss_fix_status fix_status) +{ + switch (fix_status) { + case GNSS_FIX_STATUS_NO_FIX: + return "NO_FIX"; + case GNSS_FIX_STATUS_GNSS_FIX: + return "GNSS_FIX"; + case GNSS_FIX_STATUS_DGNSS_FIX: + return "DGNSS_FIX"; + case GNSS_FIX_STATUS_ESTIMATED_FIX: + return "ESTIMATED_FIX"; + } + + return "unknown"; +} + +static const char *gnss_fix_quality_to_str(enum gnss_fix_quality fix_quality) +{ + switch (fix_quality) { + case GNSS_FIX_QUALITY_INVALID: + return "INVALID"; + case GNSS_FIX_QUALITY_GNSS_SPS: + return "GNSS_SPS"; + case GNSS_FIX_QUALITY_DGNSS: + return "DGNSS"; + case GNSS_FIX_QUALITY_GNSS_PPS: + return "GNSS_PPS"; + case GNSS_FIX_QUALITY_RTK: + return "RTK"; + case GNSS_FIX_QUALITY_FLOAT_RTK: + return "FLOAT_RTK"; + case GNSS_FIX_QUALITY_ESTIMATED: + return "ESTIMATED"; + } + + return "unknown"; +} + +#if CONFIG_GNSS_SATELLITES +static const char *gnss_system_to_str(enum gnss_system system) +{ + switch (system) { + case GNSS_SYSTEM_GPS: + return "GPS"; + case GNSS_SYSTEM_GLONASS: + return "GLONASS"; + case GNSS_SYSTEM_GALILEO: + return "GALILEO"; + case GNSS_SYSTEM_BEIDOU: + return "BEIDOU"; + case GNSS_SYSTEM_QZSS: + return "QZSS"; + case GNSS_SYSTEM_IRNSS: + return "IRNSS"; + case GNSS_SYSTEM_SBAS: + return "SBAS"; + case GNSS_SYSTEM_IMES: + return "IMES"; + } + + return "unknown"; +} +#endif + +int gnss_dump_info(char *str, uint16_t strsize, const struct gnss_info *info) +{ + int ret; + const char *fmt = "gnss_info: {satellites_cnt: %u, hdop: %u.%u, fix_status: %s, " + "fix_quality: %s}"; + + ret = snprintk(str, strsize, fmt, info->satellites_cnt, info->hdop / 1000, + info->hdop % 1000, gnss_fix_status_to_str(info->fix_status), + gnss_fix_quality_to_str(info->fix_quality)); + + return (strsize < ret) ? -ENOMEM : 0; +} + +int gnss_dump_nav_data(char *str, uint16_t strsize, const struct navigation_data *nav_data) +{ + int ret; + 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; +} + +int gnss_dump_time(char *str, uint16_t strsize, const struct gnss_time *utc) +{ + int ret; + const char *fmt = "gnss_time: {hour: %u, minute: %u, millisecond %u, month_day %u, " + "month: %u, century_year: %u}"; + + ret = snprintk(str, strsize, fmt, utc->hour, utc->minute, utc->millisecond, + utc->month_day, utc->month, utc->century_year); + + return (strsize < ret) ? -ENOMEM : 0; +} + +#if CONFIG_GNSS_SATELLITES +int gnss_dump_satellite(char *str, uint16_t strsize, const struct gnss_satellite *satellite) +{ + int ret; + const char *fmt = "gnss_satellite: {prn: %u, snr: %u, elevation %u, azimuth %u, " + "system: %s, is_tracked: %u}"; + + ret = snprintk(str, strsize, fmt, satellite->prn, satellite->snr, satellite->elevation, + satellite->azimuth, gnss_system_to_str(satellite->system), + satellite->is_tracked); + + return (strsize < ret) ? -ENOMEM : 0; +} +#endif + +#if CONFIG_GNSS_DUMP_TO_LOG +static void gnss_dump_data_to_log(const struct device *dev, const struct gnss_data *data) +{ + if (gnss_dump_info(dump_buf, sizeof(dump_buf), &data->info) < 0) { + return; + } + + LOG_PRINTK("%s: %s\r\n", dev->name, dump_buf); + + if (gnss_dump_nav_data(dump_buf, sizeof(dump_buf), &data->nav_data) < 0) { + return; + } + + LOG_PRINTK("%s: %s\r\n", dev->name, dump_buf); + + if (gnss_dump_time(dump_buf, sizeof(dump_buf), &data->utc) < 0) { + return; + } + + LOG_PRINTK("%s: %s\r\n", dev->name, dump_buf); +} + +GNSS_DATA_CALLBACK_DEFINE(NULL, gnss_dump_data_to_log); +#endif + +#if defined(CONFIG_GNSS_DUMP_TO_LOG) && defined(CONFIG_GNSS_SATELLITES) +static void gnss_dump_satellites_to_log(const struct device *dev, + const struct gnss_satellite *satellites, uint16_t size) +{ + for (uint16_t i = 0; i < size; i++) { + if (gnss_dump_satellite(dump_buf, sizeof(dump_buf), &satellites[i]) < 0) { + return; + } + + LOG_PRINTK("%s: %s\r\n", dev->name, dump_buf); + } +} + +GNSS_SATELLITES_CALLBACK_DEFINE(NULL, gnss_dump_satellites_to_log); +#endif diff --git a/drivers/gnss/gnss_dump.h b/drivers/gnss/gnss_dump.h new file mode 100644 index 000000000000000..ba02b085cd2b109 --- /dev/null +++ b/drivers/gnss/gnss_dump.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Bjarki Arge Andreasen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_GNSS_GNSS_DUMP_H_ +#define ZEPHYR_DRIVERS_GNSS_GNSS_DUMP_H_ + +#include + +/** + * @brief Dump struct gnss_info as string + * + * @param str Destination for dumped GNSS info + * @param strsize Size of str + * @param info GNSS info to dump + * + * @retval 0 if GNSS info successfully dumped + * @retval -ENOMEM if strsize too small + */ +int gnss_dump_info(char *str, uint16_t strsize, const struct gnss_info *info); + +/** + * @brief Dump struct navigation_data as string + * + * @param str Destination for dumped navigation data + * @param strsize Size of str + * @param nav_data Navigation data to dump + * + * @retval 0 if navigation data successfully dumped + * @retval -ENOMEM if strsize too small + */ +int gnss_dump_nav_data(char *str, uint16_t strsize, const struct navigation_data *nav_data); + +/** + * @brief Dump struct gnss_time as string + * + * @param str Destination for dumped GNSS time + * @param strsize Size of str + * @param utc GNSS time to dump + * + * @retval 0 if GNSS time successfully dumped + * @retval -ENOMEM if strsize too small + */ +int gnss_dump_time(char *str, uint16_t strsize, const struct gnss_time *utc); + +/** + * @brief Dump struct gnss_satellite as string + * + * @param str Destination for dumped GNSS satellite + * @param strsize Size of str + * @param utc GNSS satellite to dump + * + * @retval 0 if GNSS satellite successfully dumped + * @retval -ENOMEM if strsize too small + */ +int gnss_dump_satellite(char *str, uint16_t strsize, const struct gnss_satellite *satellite); + +#endif /* ZEPHYR_DRIVERS_GNSS_GNSS_DUMP_H_ */ diff --git a/drivers/gnss/gnss_nmea0183.c b/drivers/gnss/gnss_nmea0183.c new file mode 100644 index 000000000000000..f69dd347a9f1fd4 --- /dev/null +++ b/drivers/gnss/gnss_nmea0183.c @@ -0,0 +1,678 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#include "gnss_nmea0183.h" +#include "gnss_parse.h" + +#define GNSS_NMEA0183_PICO_DEGREES_IN_DEGREE (1000000000000ULL) +#define GNSS_NMEA0183_PICO_DEGREES_IN_MINUTE (GNSS_NMEA0183_PICO_DEGREES_IN_DEGREE / 60ULL) +#define GNSS_NMEA0183_PICO_DEGREES_IN_NANO_DEGREE (1000ULL) +#define GNSS_NMEA0183_NANO_KNOTS_IN_MMS (1943861LL) + +#define GNSS_NMEA0183_MESSAGE_SIZE_MIN (6) +#define GNSS_NMEA0183_MESSAGE_CHECKSUM_SIZE (3) + +#define GNSS_NMEA0183_GSV_HDR_ARG_CNT (4) +#define GNSS_NMEA0183_GSV_SV_ARG_CNT (4) + +#define GNSS_NMEA0183_GSV_PRN_GPS_RANGE (32) +#define GNSS_NMEA0183_GSV_PRN_SBAS_OFFSET (87) +#define GNSS_NMEA0183_GSV_PRN_GLONASS_OFFSET (64) +#define GNSS_NMEA0183_GSV_PRN_BEIDOU_OFFSET (100) + +struct gsv_header_args { + const char *message_id; + const char *number_of_messages; + const char *message_number; + const char *numver_of_svs; +}; + +struct gsv_sv_args { + const char *prn; + const char *elevation; + const char *azimuth; + const char *snr; +}; + +static int gnss_system_from_gsv_header_args(const struct gsv_header_args *args, + enum gnss_system *sv_system) +{ + switch (args->message_id[2]) { + case 'A': + *sv_system = GNSS_SYSTEM_GALILEO; + break; + case 'B': + *sv_system = GNSS_SYSTEM_BEIDOU; + break; + case 'P': + *sv_system = GNSS_SYSTEM_GPS; + break; + case 'L': + *sv_system = GNSS_SYSTEM_GLONASS; + break; + case 'Q': + *sv_system = GNSS_SYSTEM_QZSS; + break; + default: + return -EINVAL; + } + + return 0; +} + +static void align_satellite_with_gnss_system(enum gnss_system sv_system, + struct gnss_satellite *satellite) +{ + switch (sv_system) { + case GNSS_SYSTEM_GPS: + if (satellite->prn > GNSS_NMEA0183_GSV_PRN_GPS_RANGE) { + satellite->system = GNSS_SYSTEM_SBAS; + satellite->prn += GNSS_NMEA0183_GSV_PRN_SBAS_OFFSET; + break; + } + + satellite->system = GNSS_SYSTEM_GPS; + break; + + case GNSS_SYSTEM_GLONASS: + satellite->system = GNSS_SYSTEM_GLONASS; + satellite->prn -= GNSS_NMEA0183_GSV_PRN_GLONASS_OFFSET; + break; + + case GNSS_SYSTEM_GALILEO: + satellite->system = GNSS_SYSTEM_GALILEO; + break; + + case GNSS_SYSTEM_BEIDOU: + satellite->system = GNSS_SYSTEM_BEIDOU; + satellite->prn -= GNSS_NMEA0183_GSV_PRN_BEIDOU_OFFSET; + break; + + case GNSS_SYSTEM_QZSS: + satellite->system = GNSS_SYSTEM_QZSS; + break; + + case GNSS_SYSTEM_IRNSS: + case GNSS_SYSTEM_IMES: + case GNSS_SYSTEM_SBAS: + break; + } +} + +uint8_t gnss_nmea0183_checksum(const char *str) +{ + uint8_t checksum = 0; + size_t end; + + __ASSERT(str != NULL, "str argument must be provided"); + + end = strlen(str); + for (size_t i = 0; i < end; i++) { + checksum = checksum ^ str[i]; + } + + return checksum; +} + +int gnss_nmea0183_snprintk(char *str, size_t size, const char *fmt, ...) +{ + va_list ap; + uint8_t checksum; + int pos; + int len; + + __ASSERT(str != NULL, "str argument must be provided"); + __ASSERT(fmt != NULL, "fmt argument must be provided"); + + if (size < GNSS_NMEA0183_MESSAGE_SIZE_MIN) { + return -ENOMEM; + } + + str[0] = '$'; + + va_start(ap, fmt); + pos = vsnprintk(&str[1], size - 1, fmt, ap) + 1; + va_end(ap); + + if (pos < 0) { + return -EINVAL; + } + + len = pos + GNSS_NMEA0183_MESSAGE_CHECKSUM_SIZE; + + if ((size - 1) < len) { + return -ENOMEM; + } + + checksum = gnss_nmea0183_checksum(&str[1]); + pos = snprintk(&str[pos], size - pos, "*%02X", checksum); + if (pos != 3) { + return -EINVAL; + } + + str[len] = '\0'; + return len; +} + +int gnss_nmea0183_ddmm_mmmm_to_ndeg(const char *ddmm_mmmm, int64_t *ndeg) +{ + uint64_t pico_degrees = 0; + int8_t decimal = -1; + int8_t pos = 0; + uint64_t increment; + + __ASSERT(ddmm_mmmm != NULL, "ddmm_mmmm argument must be provided"); + __ASSERT(ndeg != NULL, "ndeg argument must be provided"); + + /* Find decimal */ + while (ddmm_mmmm[pos] != '\0') { + /* Verify if char is decimal */ + if (ddmm_mmmm[pos] == '.') { + decimal = pos; + break; + } + + /* Advance position */ + pos++; + } + + /* Verify decimal was found and placed correctly */ + if (decimal < 1) { + return -EINVAL; + } + + /* Validate potential degree fraction is within bounds */ + if (decimal > 1 && ddmm_mmmm[decimal - 2] > '5') { + return -EINVAL; + } + + /* Convert minute fraction to pico degrees and add it to pico_degrees */ + pos = decimal + 1; + increment = (GNSS_NMEA0183_PICO_DEGREES_IN_MINUTE / 10); + while (ddmm_mmmm[pos] != '\0') { + /* Verify char is decimal */ + if (ddmm_mmmm[pos] < '0' || ddmm_mmmm[pos] > '9') { + return -EINVAL; + } + + /* Add increment to pico_degrees */ + pico_degrees += (ddmm_mmmm[pos] - '0') * increment; + + /* Update unit */ + increment /= 10; + + /* Increment position */ + pos++; + } + + /* Convert minutes and degrees to pico_degrees */ + pos = decimal - 1; + increment = GNSS_NMEA0183_PICO_DEGREES_IN_MINUTE; + while (pos >= 0) { + /* Check if digit switched from minutes to degrees */ + if ((decimal - pos) == 3) { + /* Reset increment to degrees */ + increment = GNSS_NMEA0183_PICO_DEGREES_IN_DEGREE; + } + + /* Verify char is decimal */ + if (ddmm_mmmm[pos] < '0' || ddmm_mmmm[pos] > '9') { + return -EINVAL; + } + + /* Add increment to pico_degrees */ + pico_degrees += (ddmm_mmmm[pos] - '0') * increment; + + /* Update unit */ + increment *= 10; + + /* Decrement position */ + pos--; + } + + /* Convert to nano degrees */ + *ndeg = (int64_t)(pico_degrees / GNSS_NMEA0183_PICO_DEGREES_IN_NANO_DEGREE); + return 0; +} + +bool gnss_nmea0183_validate_message(char **argv, uint16_t argc) +{ + int32_t tmp = 0; + uint8_t checksum = 0; + size_t len; + + __ASSERT(argv != NULL, "argv argument must be provided"); + + /* Message must contain message id and checksum */ + if (argc < 2) { + return false; + } + + /* First argument should start with '$' which is not covered by checksum */ + if ((argc < 1) || (argv[0][0] != '$')) { + return false; + } + + len = strlen(argv[0]); + for (uint16_t u = 1; u < len; u++) { + checksum ^= argv[0][u]; + } + checksum ^= ','; + + /* Cover all except last argument which contains the checksum*/ + for (uint16_t i = 1; i < (argc - 1); i++) { + len = strlen(argv[i]); + for (uint16_t u = 0; u < len; u++) { + checksum ^= argv[i][u]; + } + checksum ^= ','; + } + + if ((gnss_parse_atoi(argv[argc - 1], 16, &tmp) < 0) || + (tmp > UINT8_MAX) || + (tmp < 0)) { + return false; + } + + return checksum == (uint8_t)tmp; +} + +int gnss_nmea0183_knots_to_mms(const char *str, int64_t *mms) +{ + int ret; + + __ASSERT(str != NULL, "str argument must be provided"); + __ASSERT(mms != NULL, "mms argument must be provided"); + + ret = gnss_parse_dec_to_nano(str, mms); + if (ret < 0) { + return ret; + } + + *mms = (*mms) / GNSS_NMEA0183_NANO_KNOTS_IN_MMS; + return 0; +} + +int gnss_nmea0183_parse_hhmmss(const char *hhmmss, struct gnss_time *utc) +{ + int64_t i64; + int32_t i32; + char part[3] = {0}; + + __ASSERT(hhmmss != NULL, "hhmmss argument must be provided"); + __ASSERT(utc != NULL, "utc argument must be provided"); + + if (strlen(hhmmss) < 6) { + return -EINVAL; + } + + memcpy(part, hhmmss, 2); + if ((gnss_parse_atoi(part, 10, &i32) < 0) || + (i32 < 0) || + (i32 > 23)) { + return -EINVAL; + } + + utc->hour = (uint8_t)i32; + + memcpy(part, &hhmmss[2], 2); + if ((gnss_parse_atoi(part, 10, &i32) < 0) || + (i32 < 0) || + (i32 > 59)) { + return -EINVAL; + } + + utc->minute = (uint8_t)i32; + + if ((gnss_parse_dec_to_milli(&hhmmss[4], &i64) < 0) || + (i64 < 0) || + (i64 > 59999)) { + return -EINVAL; + } + + utc->millisecond = (uint16_t)i64; + return 0; +} + +int gnss_nmea0183_parse_ddmmyy(const char *ddmmyy, struct gnss_time *utc) +{ + int32_t i32; + char part[3] = {0}; + + __ASSERT(ddmmyy != NULL, "ddmmyy argument must be provided"); + __ASSERT(utc != NULL, "utc argument must be provided"); + + if (strlen(ddmmyy) != 6) { + return -EINVAL; + } + + memcpy(part, ddmmyy, 2); + if ((gnss_parse_atoi(part, 10, &i32) < 0) || + (i32 < 1) || + (i32 > 31)) { + return -EINVAL; + } + + utc->month_day = (uint8_t)i32; + + memcpy(part, &ddmmyy[2], 2); + if ((gnss_parse_atoi(part, 10, &i32) < 0) || + (i32 < 1) || + (i32 > 12)) { + return -EINVAL; + } + + utc->month = (uint8_t)i32; + + memcpy(part, &ddmmyy[4], 2); + if ((gnss_parse_atoi(part, 10, &i32) < 0) || + (i32 < 0) || + (i32 > 99)) { + return -EINVAL; + } + + utc->century_year = (uint8_t)i32; + return 0; +} + +int gnss_nmea0183_parse_rmc(const char **argv, uint16_t argc, struct gnss_data *data) +{ + int64_t tmp; + + __ASSERT(argv != NULL, "argv argument must be provided"); + __ASSERT(data != NULL, "data argument must be provided"); + + if (argc < 10) { + return -EINVAL; + } + + /* Validate GNSS has fix */ + if (argv[2][0] == 'V') { + return 0; + } + + if (argv[2][0] != 'A') { + return -EINVAL; + } + + /* Parse UTC time */ + if ((gnss_nmea0183_parse_hhmmss(argv[1], &data->utc) < 0)) { + return -EINVAL; + } + + /* Validate cardinal directions */ + if (((argv[4][0] != 'N') && (argv[4][0] != 'S')) || + ((argv[6][0] != 'E') && (argv[6][0] != 'W'))) { + return -EINVAL; + } + + /* Parse coordinates */ + if ((gnss_nmea0183_ddmm_mmmm_to_ndeg(argv[3], &data->nav_data.latitude) < 0) || + (gnss_nmea0183_ddmm_mmmm_to_ndeg(argv[5], &data->nav_data.longitude) < 0)) { + return -EINVAL; + } + + /* Align sign of coordinates with cardinal directions */ + data->nav_data.latitude = argv[4][0] == 'N' + ? data->nav_data.latitude + : -data->nav_data.latitude; + + data->nav_data.longitude = argv[6][0] == 'E' + ? data->nav_data.longitude + : -data->nav_data.longitude; + + /* Parse speed */ + if ((gnss_nmea0183_knots_to_mms(argv[7], &tmp) < 0) || + (tmp > UINT32_MAX)) { + return -EINVAL; + } + + data->nav_data.speed = (uint32_t)tmp; + + /* Parse bearing */ + if ((gnss_parse_dec_to_milli(argv[8], &tmp) < 0) || + (tmp > 359999) || + (tmp < 0)) { + return -EINVAL; + } + + data->nav_data.bearing = (uint32_t)tmp; + + /* Parse UTC date */ + if ((gnss_nmea0183_parse_ddmmyy(argv[9], &data->utc) < 0)) { + return -EINVAL; + } + + return 0; +} + +static int parse_gga_fix_quality(const char *str, enum gnss_fix_quality *fix_quality) +{ + __ASSERT(str != NULL, "str argument must be provided"); + __ASSERT(fix_quality != NULL, "fix_quality argument must be provided"); + + if ((str[1] != ((char)'\0')) || (str[0] < ((char)'0')) || (((char)'6') < str[0])) { + return -EINVAL; + } + + (*fix_quality) = (enum gnss_fix_quality)(str[0] - ((char)'0')); + return 0; +} + +static enum gnss_fix_status fix_status_from_fix_quality(enum gnss_fix_quality fix_quality) +{ + enum gnss_fix_status fix_status = GNSS_FIX_STATUS_NO_FIX; + + switch (fix_quality) { + case GNSS_FIX_QUALITY_GNSS_SPS: + case GNSS_FIX_QUALITY_GNSS_PPS: + fix_status = GNSS_FIX_STATUS_GNSS_FIX; + break; + + case GNSS_FIX_QUALITY_DGNSS: + case GNSS_FIX_QUALITY_RTK: + case GNSS_FIX_QUALITY_FLOAT_RTK: + fix_status = GNSS_FIX_STATUS_DGNSS_FIX; + break; + + case GNSS_FIX_QUALITY_ESTIMATED: + fix_status = GNSS_FIX_STATUS_ESTIMATED_FIX; + break; + + default: + break; + } + + return fix_status; +} + +int gnss_nmea0183_parse_gga(const char **argv, uint16_t argc, struct gnss_data *data) +{ + int32_t tmp32; + int64_t tmp64; + + __ASSERT(argv != NULL, "argv argument must be provided"); + __ASSERT(data != NULL, "data argument must be provided"); + + if (argc < 12) { + return -EINVAL; + } + + /* Parse fix quality and status */ + if (parse_gga_fix_quality(argv[6], &data->info.fix_quality) < 0) { + return -EINVAL; + } + + data->info.fix_status = fix_status_from_fix_quality(data->info.fix_quality); + + /* Validate GNSS has fix */ + if (data->info.fix_status == GNSS_FIX_STATUS_NO_FIX) { + return 0; + } + + /* Parse number of satellites */ + if ((gnss_parse_atoi(argv[7], 10, &tmp32) < 0) || + (tmp32 > UINT16_MAX) || + (tmp32 < 0)) { + return -EINVAL; + } + + data->info.satellites_cnt = (uint16_t)tmp32; + + /* Parse HDOP */ + if ((gnss_parse_dec_to_milli(argv[8], &tmp64) < 0) || + (tmp64 > UINT16_MAX) || + (tmp64 < 0)) { + return -EINVAL; + } + + data->info.hdop = (uint16_t)tmp64; + + /* Parse altitude */ + if ((gnss_parse_dec_to_milli(argv[11], &tmp64) < 0) || + (tmp64 > INT32_MAX) || + (tmp64 < INT32_MIN)) { + return -EINVAL; + } + + data->nav_data.altitude = (int32_t)tmp64; + return 0; +} + +static int parse_gsv_svs(struct gnss_satellite *satellites, const struct gsv_sv_args *svs, + uint16_t svs_size) +{ + int32_t i32; + + for (uint16_t i = 0; i < svs_size; i++) { + /* Parse PRN */ + if ((gnss_parse_atoi(svs[i].prn, 10, &i32) < 0) || + (i32 < 0) || (i32 > UINT16_MAX)) { + return -EINVAL; + } + + satellites[i].prn = (uint16_t)i32; + + /* Parse elevation */ + if ((gnss_parse_atoi(svs[i].elevation, 10, &i32) < 0) || + (i32 < 0) || (i32 > 90)) { + return -EINVAL; + } + + satellites[i].elevation = (uint8_t)i32; + + /* Parse azimuth */ + if ((gnss_parse_atoi(svs[i].azimuth, 10, &i32) < 0) || + (i32 < 0) || (i32 > 359)) { + return -EINVAL; + } + + satellites[i].azimuth = (uint16_t)i32; + + /* Parse SNR */ + if (strlen(svs[i].snr) == 0) { + satellites[i].snr = 0; + satellites[i].is_tracked = false; + continue; + } + + if ((gnss_parse_atoi(svs[i].snr, 10, &i32) < 0) || + (i32 < 0) || (i32 > 99)) { + return -EINVAL; + } + + satellites[i].snr = (uint16_t)i32; + satellites[i].is_tracked = true; + } + + return 0; +} + +int gnss_nmea0183_parse_gsv_header(const char **argv, uint16_t argc, + struct gnss_nmea0183_gsv_header *header) +{ + const struct gsv_header_args *args = (const struct gsv_header_args *)argv; + int i32; + + __ASSERT(argv != NULL, "argv argument must be provided"); + __ASSERT(header != NULL, "header argument must be provided"); + + if (argc < 4) { + return -EINVAL; + } + + /* Parse GNSS sv_system */ + if (gnss_system_from_gsv_header_args(args, &header->system) < 0) { + return -EINVAL; + } + + /* Parse number of messages */ + if ((gnss_parse_atoi(args->number_of_messages, 10, &i32) < 0) || + (i32 < 0) || (i32 > UINT16_MAX)) { + return -EINVAL; + } + + header->number_of_messages = (uint16_t)i32; + + /* Parse message number */ + if ((gnss_parse_atoi(args->message_number, 10, &i32) < 0) || + (i32 < 0) || (i32 > UINT16_MAX)) { + return -EINVAL; + } + + header->message_number = (uint16_t)i32; + + /* Parse message number */ + if ((gnss_parse_atoi(args->numver_of_svs, 10, &i32) < 0) || + (i32 < 0) || (i32 > UINT16_MAX)) { + return -EINVAL; + } + + header->number_of_svs = (uint16_t)i32; + return 0; +} + +int gnss_nmea0183_parse_gsv_svs(const char **argv, uint16_t argc, + struct gnss_satellite *satellites, uint16_t size) +{ + const struct gsv_header_args *header_args = (const struct gsv_header_args *)argv; + const struct gsv_sv_args *sv_args = (const struct gsv_sv_args *)(argv + 4); + uint16_t sv_args_size; + enum gnss_system sv_system; + + __ASSERT(argv != NULL, "argv argument must be provided"); + __ASSERT(satellites != NULL, "satellites argument must be provided"); + + if (argc < 9) { + return 0; + } + + sv_args_size = (argc - GNSS_NMEA0183_GSV_HDR_ARG_CNT) / GNSS_NMEA0183_GSV_SV_ARG_CNT; + + if (size < sv_args_size) { + return -ENOMEM; + } + + if (parse_gsv_svs(satellites, sv_args, sv_args_size) < 0) { + return -EINVAL; + } + + if (gnss_system_from_gsv_header_args(header_args, &sv_system) < 0) { + return -EINVAL; + } + + for (uint16_t i = 0; i < sv_args_size; i++) { + align_satellite_with_gnss_system(sv_system, &satellites[i]); + } + + return (int)sv_args_size; +} diff --git a/drivers/gnss/gnss_nmea0183.h b/drivers/gnss/gnss_nmea0183.h new file mode 100644 index 000000000000000..6a3fa177f444e6d --- /dev/null +++ b/drivers/gnss/gnss_nmea0183.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_GNSS_GNSS_NMEA0183_H_ +#define ZEPHYR_DRIVERS_GNSS_GNSS_NMEA0183_H_ + +#include + +/** + * @brief Compute NMEA0183 checksum + * + * @example "PAIR002" -> 0x38 + * + * @param str String from which checksum is computed + * + * @retval checksum + */ +uint8_t gnss_nmea0183_checksum(const char *str); + +/** + * @brief Encapsulate str in NMEA0183 message format + * + * @example "PAIR%03u", 2 -> "$PAIR002*38" + * + * @param str Destination for encapsulated string + * @param size Size of destination for encapsulated string + * @param fmt Format of string to encapsulate + * @param ... Arguments + * + * @retval checksum + */ +int gnss_nmea0183_snprintk(char *str, size_t size, const char *fmt, ...); + +/** + * @brief Computes and validates checksum + * + * @param argv Array of arguments split by ',' including message id and checksum + * @param argc Number of arguments in argv + * + * @retval true if message is intact + * @retval false if message is corrupted + */ +bool gnss_nmea0183_validate_message(char **argv, uint16_t argc); + +/** + * @brief Parse a ddmm.mmmm formatted angle to nano degrees + * + * @example "5610.9928" -> 56183214000 + * + * @param ddmm_mmmm String representation of angle in ddmm.mmmm format + * @param ndeg Result in nano degrees + * + * @retval -EINVAL if ddmm_mmmm argument is invalid + * @retval 0 if parsed successfully + */ +int gnss_nmea0183_ddmm_mmmm_to_ndeg(const char *ddmm_mmmm, int64_t *ndeg); + +/** + * @brief Parse knots to millimeters pr second + * + * @example "15.231" -> 7835 + * + * @param str String representation of speed in knots + * @param mms Destination for speed in millimeters pr second + * + * @retval -EINVAL if str could not be parsed or if speed is negative + * @retval 0 if parsed successfully + */ +int gnss_nmea0183_knots_to_mms(const char *str, int64_t *mms); + +/** + * @brief Parse hhmmss.sss to struct gnss_time + * + * @example "133243.012" -> { .hour = 13, .minute = 32, .ms = 43012 } + * @example "133243" -> { .hour = 13, .minute = 32, .ms = 43000 } + * + * @param str String representation of hours, minutes, seconds and subseconds + * @param utc Destination for parsed time + * + * @retval -EINVAL if str could not be parsed + * @retval 0 if parsed successfully + */ +int gnss_nmea0183_parse_hhmmss(const char *hhmmss, struct gnss_time *utc); + +/** + * @brief Parse ddmmyy to unsigned integers + * + * @example "041122" -> { .mday = 4, .month = 11, .year = 22 } + * + * @param str String representation of speed in knots + * @param utc Destination for parsed time + * + * @retval -EINVAL if str could not be parsed + * @retval 0 if parsed successfully + */ +int gnss_nmea0183_parse_ddmmyy(const char *ddmmyy, struct gnss_time *utc); + +/** + * @brief Parses NMEA0183 RMC message + * + * @details Parses the time, date, latitude, longitude, speed, and bearing + * from the NMEA0183 RMC message provided as an array of strings split by ',' + * + * @param argv Array of arguments split by ',' including message id and checksum + * @param argc Number of arguments in argv' + * @param data Destination for data parsed from NMEA0183 RMC message + * + * @retval 0 if successful + * @retval -EINVAL if input is invalid + */ +int gnss_nmea0183_parse_rmc(const char **argv, uint16_t argc, struct gnss_data *data); + +/** + * @brief Parses NMEA0183 GGA message + * + * @details Parses the GNSS fix quality and status, number of satellites used for + * fix, HDOP, and altitude (geoid separation) from the NMEA0183 GGA message provided + * as an array of strings split by ',' + * + * @param argv Array of arguments split by ',' including message id and checksum + * @param argc Number of arguments in argv' + * @param data Destination for data parsed from NMEA0183 GGA message + * + * @retval 0 if successful + * @retval -EINVAL if input is invalid + */ +int gnss_nmea0183_parse_gga(const char **argv, uint16_t argc, struct gnss_data *data); + +/** GSV header structure */ +struct gnss_nmea0183_gsv_header { + /** Indicates the system of the space-vehicles contained in the message */ + enum gnss_system system; + /** Number of GSV messages in total */ + uint16_t number_of_messages; + /** Number of this GSV message */ + uint16_t message_number; + /** Number of visible space-vehicles */ + uint16_t number_of_svs; +}; + +/** + * @brief Parses header of NMEA0183 GSV message + * + * @details The GSV messages are part of a list of messages sent in ascending + * order, split by GNSS system. + * + * @param argv Array of arguments split by ',' including message id and checksum + * @param argc Number of arguments in argv + * @param header Destination for parsed NMEA0183 GGA message header + * + * @retval 0 if successful + * @retval -EINVAL if input is invalid + */ +int gnss_nmea0183_parse_gsv_header(const char **argv, uint16_t argc, + struct gnss_nmea0183_gsv_header *header); + +/** + * @brief Parses space-vehicles in NMEA0183 GSV message + * + * @details The NMEA0183 GSV message contains up to 4 space-vehicles which follow + * the header. + * + * @param argv Array of arguments split by ',' including message id and checksum + * @param argc Number of arguments in argv + * @param satellites Destination for parsed satellites from NMEA0183 GGA message + * @param size Size of destination for parsed satellites from NMEA0183 GGA message + * + * @retval Number of parsed space-vehicles stored at destination if successful + * @retval -ENOMEM if all space-vehicles in message could not be stored at destination + * @retval -EINVAL if input is invalid + */ +int gnss_nmea0183_parse_gsv_svs(const char **argv, uint16_t argc, + struct gnss_satellite *satellites, uint16_t size); + +#endif /* ZEPHYR_DRIVERS_GNSS_GNSS_NMEA0183_H_ */ diff --git a/drivers/gnss/gnss_nmea0183_match.c b/drivers/gnss/gnss_nmea0183_match.c new file mode 100644 index 000000000000000..cd82c552ee41050 --- /dev/null +++ b/drivers/gnss/gnss_nmea0183_match.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +#include "gnss_parse.h" +#include "gnss_nmea0183.h" +#include "gnss_nmea0183_match.h" + +static int gnss_nmea0183_match_parse_utc(char **argv, uint16_t argc, uint32_t *utc) +{ + int64_t i64; + + 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 +static void gnss_nmea0183_match_reset_gsv(struct gnss_nmea0183_match_data *data) +{ + data->satellites_length = 0; + data->gsv_message_number = 1; +} +#endif + +static void gnss_nmea0183_match_publish(struct gnss_nmea0183_match_data *data) +{ + 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, + void *user_data) +{ + struct gnss_nmea0183_match_data *data = user_data; + + if (gnss_nmea0183_parse_gga((const char **)argv, argc, &data->data) < 0) { + return; + } + + 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, + void *user_data) +{ + struct gnss_nmea0183_match_data *data = user_data; + + if (gnss_nmea0183_parse_rmc((const char **)argv, argc, &data->data) < 0) { + return; + } + + if (gnss_nmea0183_match_parse_utc(argv, argc, &data->rmc_utc) < 0) { + return; + } + + gnss_nmea0183_match_publish(data); +} + +#if CONFIG_GNSS_SATELLITES +void gnss_nmea0183_match_gsv_callback(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data) +{ + struct gnss_nmea0183_match_data *data = user_data; + struct gnss_nmea0183_gsv_header header; + int ret; + + if (gnss_nmea0183_parse_gsv_header((const char **)argv, argc, &header) < 0) { + return; + } + + if (header.number_of_svs == 0) { + return; + } + + if (header.message_number != data->gsv_message_number) { + gnss_nmea0183_match_reset_gsv(data); + return; + } + + data->gsv_message_number++; + + ret = gnss_nmea0183_parse_gsv_svs((const char **)argv, argc, + &data->satellites[data->satellites_length], + data->satellites_size - data->satellites_length); + if (ret < 0) { + gnss_nmea0183_match_reset_gsv(data); + return; + } + + data->satellites_length += (uint16_t)ret; + + if (data->satellites_length == header.number_of_svs) { + gnss_publish_satellites(data->gnss, data->satellites, data->satellites_length); + gnss_nmea0183_match_reset_gsv(data); + } +} +#endif + +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, "config argument must be provided"); + + memset(data, 0, sizeof(struct gnss_nmea0183_match_data)); + data->gnss = config->gnss; +#if CONFIG_GNSS_SATELLITES + data->satellites = config->satellites; + data->satellites_size = config->satellites_size; +#endif + return 0; +} diff --git a/drivers/gnss/gnss_nmea0183_match.h b/drivers/gnss/gnss_nmea0183_match.h new file mode 100644 index 000000000000000..28ed395320bdf7a --- /dev/null +++ b/drivers/gnss/gnss_nmea0183_match.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * The GNSS NMEA0183 match is a set of modem_chat match handlers and a context to be + * passed to said handlers, to parse the NMEA0183 messages received from a NMEA0183 + * based GNSS device. + * + * The context struct gnss_nmea0183_match_data *data is placed as the first member + * of the data structure which is passed to the modem_chat instance through the + * user_data member. + * + * struct my_gnss_nmea0183_driver { + * gnss_nmea0183_match_data match_data; + * ... + * }; + * + * The struct gnss_nmea0183_match_data context must be initialized using + * gnss_nmea0183_match_init(). + * + * When initializing the modem_chat instance, the three match callbacks must be added + * as part of the unsolicited matches. + * + * 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 + * + */ + +#ifndef ZEPHYR_DRIVERS_GNSS_GNSS_NMEA0183_MATCH_H_ +#define ZEPHYR_DRIVERS_GNSS_GNSS_NMEA0183_MATCH_H_ + +#include +#include +#include +#include + +struct gnss_nmea0183_match_data { + const struct device *gnss; + struct gnss_data data; +#if CONFIG_GNSS_SATELLITES + struct gnss_satellite *satellites; + uint16_t satellites_size; + uint16_t satellites_length; +#endif + uint32_t gga_utc; + uint32_t rmc_utc; + uint8_t gsv_message_number; +}; + +/** GNSS NMEA0183 match configuration structure */ +struct gnss_nmea0183_match_config { + /** The GNSS device from which the data is published */ + const struct device *gnss; +#if CONFIG_GNSS_SATELLITES + /** Buffer for parsed satellites */ + struct gnss_satellite *satellites; + /** Number of elements in buffer for parsed satellites */ + uint16_t satellites_size; +#endif +}; + +/** + * @brief Match callback for the NMEA GGA NMEA0183 message + * + * @details Should be used as the callback of a modem_chat match which matches "$??GGA," + */ +void gnss_nmea0183_match_gga_callback(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data); + +/** + * @brief Match callback for the NMEA RMC NMEA0183 message + * + * @details Should be used as the callback of a modem_chat match which matches "$??RMC," + */ +void gnss_nmea0183_match_rmc_callback(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data); + +/** + * @brief Match callback for the NMEA GSV NMEA0183 message + * + * @details Should be used as the callback of a modem_chat match which matches "$??GSV," + */ +void gnss_nmea0183_match_gsv_callback(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data); + +/** + * @brief Initialize a GNSS NMEA0183 match instance + * + * @param data GNSS NMEA0183 match instance to initialize + * @param config Configuration to apply to GNSS NMEA0183 match instance + */ +int gnss_nmea0183_match_init(struct gnss_nmea0183_match_data *data, + const struct gnss_nmea0183_match_config *config); + +#endif /* ZEPHYR_DRIVERS_GNSS_GNSS_NMEA0183_MATCH_H_ */ diff --git a/drivers/gnss/gnss_nmea_generic.c b/drivers/gnss/gnss_nmea_generic.c new file mode 100644 index 000000000000000..2f23f4d73530fb6 --- /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_parse.c b/drivers/gnss/gnss_parse.c new file mode 100644 index 000000000000000..29808dd74f22af5 --- /dev/null +++ b/drivers/gnss/gnss_parse.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#include "gnss_parse.h" + +#define GNSS_PARSE_NANO_KNOTS_IN_MMS (1943840LL) +#define GNSS_PARSE_NANO (1000000000LL) +#define GNSS_PARSE_MICRO (1000000LL) +#define GNSS_PARSE_MILLI (1000LL) + +int gnss_parse_dec_to_nano(const char *str, int64_t *nano) +{ + int64_t sum = 0; + int8_t decimal = -1; + int8_t pos = 0; + int8_t start = 0; + int64_t increment; + + __ASSERT(str != NULL, "str argument must be provided"); + __ASSERT(nano != NULL, "nano argument must be provided"); + + /* Find decimal */ + while (str[pos] != '\0') { + /* Verify if char is decimal */ + if (str[pos] == '.') { + decimal = pos; + break; + } + + /* Advance position */ + pos++; + } + + /* Determine starting position based on decimal location */ + pos = decimal < 0 ? pos - 1 : decimal - 1; + + /* Skip sign if it exists */ + start = str[0] == '-' ? 1 : 0; + + /* Add whole value to sum */ + increment = GNSS_PARSE_NANO; + while (start <= pos) { + /* Verify char is decimal */ + if (str[pos] < '0' || str[pos] > '9') { + return -EINVAL; + } + + /* Add value to sum */ + sum += (str[pos] - '0') * increment; + + /* Update increment */ + increment *= 10; + + /* Degrement position */ + pos--; + } + + /* Check if decimal was found */ + if (decimal < 0) { + /* Set sign of sum */ + sum = start == 1 ? -sum : sum; + + *nano = sum; + return 0; + } + + /* Convert decimal part to nano fractions and add it to sum */ + pos = decimal + 1; + increment = GNSS_PARSE_NANO / 10LL; + while (str[pos] != '\0') { + /* Verify char is decimal */ + if (str[pos] < '0' || str[pos] > '9') { + return -EINVAL; + } + + /* Add value to micro_degrees */ + sum += (str[pos] - '0') * increment; + + /* Update unit */ + increment /= 10; + + /* Increment position */ + pos++; + } + + /* Set sign of sum */ + sum = start == 1 ? -sum : sum; + + *nano = sum; + return 0; +} + +int gnss_parse_dec_to_micro(const char *str, uint64_t *micro) +{ + int ret; + + __ASSERT(str != NULL, "str argument must be provided"); + __ASSERT(micro != NULL, "micro argument must be provided"); + + ret = gnss_parse_dec_to_nano(str, micro); + if (ret < 0) { + return ret; + } + + *micro = (*micro) / GNSS_PARSE_MILLI; + return 0; +} + + +int gnss_parse_dec_to_milli(const char *str, int64_t *milli) +{ + int ret; + + __ASSERT(str != NULL, "str argument must be provided"); + __ASSERT(milli != NULL, "milli argument must be provided"); + + ret = gnss_parse_dec_to_nano(str, milli); + if (ret < 0) { + return ret; + } + + (*milli) = (*milli) / GNSS_PARSE_MICRO; + return 0; +} + +int gnss_parse_atoi(const char *str, uint8_t base, int32_t *integer) +{ + char *end; + + __ASSERT(str != NULL, "str argument must be provided"); + __ASSERT(integer != NULL, "integer argument must be provided"); + + *integer = (int32_t)strtol(str, &end, (int)base); + + if ('\0' != (*end)) { + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gnss/gnss_parse.h b/drivers/gnss/gnss_parse.h new file mode 100644 index 000000000000000..443363cfa6e761d --- /dev/null +++ b/drivers/gnss/gnss_parse.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_GNSS_GNSS_PARSE_H_ +#define ZEPHYR_DRIVERS_GNSS_GNSS_PARSE_H_ + +#include + +/** + * @brief Parse decimal string to nano parts + * + * @example "-1231.3512" -> -1231351200000 + * + * @param str The decimal string to be parsed + * @param nano Destination for parsed decimal + * + * @retval -EINVAL if str could not be parsed + * @retval 0 if str successfully parsed + */ +int gnss_parse_dec_to_nano(const char *str, int64_t *nano); + +/** + * @brief Parse decimal string to micro parts + * + * @example "-1231.3512" -> -1231351200 + * + * @param str The decimal string to be parsed + * @param milli Destination for parsed decimal + * + * @retval -EINVAL if str could not be parsed + * @retval 0 if str successfully parsed + */ +int gnss_parse_dec_to_micro(const char *str, uint64_t *micro); + +/** + * @brief Parse decimal string to milli parts + * + * @example "-1231.3512" -> -1231351 + * + * @param str The decimal string to be parsed + * @param milli Destination for parsed decimal + * + * @retval -EINVAL if str could not be parsed + * @retval 0 if str successfully parsed + */ +int gnss_parse_dec_to_milli(const char *str, int64_t *milli); + +/** + * @brief Parse integer string of configurable base to integer + * + * @example "-1231" -> -1231 + * + * @param str Decimal string to be parsed + * @param base Base of decimal string to be parsed + * @param integer Destination for parsed integer + * + * @retval -EINVAL if str could not be parsed + * @retval 0 if str successfully parsed + */ +int gnss_parse_atoi(const char *str, uint8_t base, int32_t *integer); + +#endif /* ZEPHYR_DRIVERS_GNSS_GNSS_PARSE_H_ */ diff --git a/drivers/gnss/gnss_publish.c b/drivers/gnss/gnss_publish.c new file mode 100644 index 000000000000000..7ddfa5e09fe059f --- /dev/null +++ b/drivers/gnss/gnss_publish.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +static struct k_spinlock lock; + +void gnss_publish_data(const struct device *dev, const struct gnss_data *data) +{ + K_SPINLOCK(&lock) { + STRUCT_SECTION_FOREACH(gnss_data_callback, callback) { + if (callback->dev == NULL || callback->dev == dev) { + callback->callback(dev, data); + } + } + } +} + +#if CONFIG_GNSS_SATELLITES +void gnss_publish_satellites(const struct device *dev, const struct gnss_satellite *satellites, + uint16_t size) +{ + K_SPINLOCK(&lock) { + STRUCT_SECTION_FOREACH(gnss_satellites_callback, callback) { + if (callback->dev == NULL || callback->dev == dev) { + callback->callback(dev, satellites, size); + } + } + } +} +#endif diff --git a/drivers/gnss/gnss_quectel_lcx6g.c b/drivers/gnss/gnss_quectel_lcx6g.c new file mode 100644 index 000000000000000..09fa8fd8e4abfc1 --- /dev/null +++ b/drivers/gnss/gnss_quectel_lcx6g.c @@ -0,0 +1,823 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * Copyright (c) 2023 Bjarki Arge Andreasen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gnss_nmea0183.h" +#include "gnss_nmea0183_match.h" +#include "gnss_parse.h" + +#include +LOG_MODULE_REGISTER(quectel_lcx6g, CONFIG_GNSS_LOG_LEVEL); + +#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_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; + const enum gnss_pps_mode pps_mode; + const uint16_t pps_pulse_width; +}; + +struct quectel_lcx6g_data { + struct gnss_nmea0183_match_data match_data; +#if CONFIG_GNSS_SATELLITES + 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[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; + uint8_t chat_receive_buf[256]; + uint8_t chat_delimiter[2]; + uint8_t *chat_argv[32]; + + /* Dynamic chat script */ + uint8_t dynamic_match_buf[32]; + uint8_t dynamic_separators_buf[2]; + uint8_t dynamic_request_buf[32]; + struct modem_chat_match dynamic_match; + struct modem_chat_script_chat dynamic_script_chat; + struct modem_chat_script dynamic_script; + + /* Allocation for responses from GNSS modem */ + union { + uint16_t fix_rate_response; + gnss_systems_t enabled_systems_response; + enum gnss_navigation_mode navigation_mode_response; + }; + + struct k_spinlock lock; + k_timeout_t pm_timeout; +}; + +#define MODEM_CHAT_SCRIPT_NO_ABORT_DEFINE(_sym, _script_chats, _callback, _timeout) \ + static struct modem_chat_script _sym = { \ + .name = #_sym, \ + .script_chats = _script_chats, \ + .script_chats_size = ARRAY_SIZE(_script_chats), \ + .abort_matches = NULL, \ + .abort_matches_size = 0, \ + .callback = _callback, \ + .timeout = _timeout, \ + } + +#ifdef CONFIG_PM_DEVICE +MODEM_CHAT_MATCH_DEFINE(pair003_success_match, "$PAIR001,003,0*38", "", NULL); +MODEM_CHAT_SCRIPT_CMDS_DEFINE( + suspend_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("$PAIR003*39", pair003_success_match) +); + +MODEM_CHAT_SCRIPT_NO_ABORT_DEFINE(suspend_script, suspend_script_cmds, + NULL, QUECTEL_LCX6G_SCRIPT_TIMEOUT_S); +#endif /* CONFIG_PM_DEVICE */ + +MODEM_CHAT_MATCH_DEFINE(any_match, "", "", NULL); +MODEM_CHAT_MATCH_DEFINE(pair062_ack_match, "$PAIR001,062,0*3F", "", NULL); +MODEM_CHAT_SCRIPT_CMDS_DEFINE( + resume_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("$PAIR002*38", any_match), + MODEM_CHAT_SCRIPT_CMD_RESP("$PAIR062,0,1*3F", pair062_ack_match), + MODEM_CHAT_SCRIPT_CMD_RESP("$PAIR062,1,0*3F", pair062_ack_match), + MODEM_CHAT_SCRIPT_CMD_RESP("$PAIR062,2,0*3C", pair062_ack_match), +#if CONFIG_GNSS_SATELLITES + MODEM_CHAT_SCRIPT_CMD_RESP("$PAIR062,3,5*38", pair062_ack_match), +#else + MODEM_CHAT_SCRIPT_CMD_RESP("$PAIR062,3,0*3D", pair062_ack_match), +#endif + MODEM_CHAT_SCRIPT_CMD_RESP("$PAIR062,4,1*3B", pair062_ack_match), + MODEM_CHAT_SCRIPT_CMD_RESP("$PAIR062,5,0*3B", pair062_ack_match), +); + +MODEM_CHAT_SCRIPT_NO_ABORT_DEFINE(resume_script, resume_script_cmds, + NULL, QUECTEL_LCX6G_SCRIPT_TIMEOUT_S); + +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 quectel_lcx6g_configure_pps(const struct device *dev) +{ + const struct quectel_lcx6g_config *config = dev->config; + struct quectel_lcx6g_data *data = dev->data; + uint8_t pps_mode = 0; + int ret; + + switch (config->pps_mode) { + case GNSS_PPS_MODE_DISABLED: + pps_mode = QUECTEL_LCX6G_PAIR_PPS_MODE_DISABLED; + break; + + case GNSS_PPS_MODE_ENABLED: + pps_mode = QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED; + break; + + case GNSS_PPS_MODE_ENABLED_AFTER_LOCK: + pps_mode = QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED_AFTER_LOCK; + break; + + case GNSS_PPS_MODE_ENABLED_WHILE_LOCKED: + pps_mode = QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED_WHILE_LOCKED; + break; + } + + ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), + "PAIR752,%u,%u", pps_mode, config->pps_pulse_width); + if (ret < 0) { + return ret; + } + + data->dynamic_script_chat.request_size = ret; + + ret = gnss_nmea0183_snprintk(data->dynamic_match_buf, sizeof(data->dynamic_match_buf), + "PAIR001,752,0"); + if (ret < 0) { + return ret; + } + + data->dynamic_match.match_size = ret; + + 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; + } + + 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; +} + +#ifdef CONFIG_PM_DEVICE +static int quectel_lcx6g_suspend(const struct device *dev) +{ + struct quectel_lcx6g_data *data = dev->data; + int ret; + + LOG_INF("Suspending"); + + quectel_lcx6g_await_pm_ready(dev); + + ret = modem_chat_run_script(&data->chat, &suspend_script); + if (ret < 0) { + 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); +} + +static int quectel_lcx6g_pm_action(const struct device *dev, enum pm_device_action action) +{ + struct quectel_lcx6g_data *data = dev->data; + k_spinlock_key_t key; + int ret = -ENOTSUP; + + key = k_spin_lock(&data->lock); + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + ret = quectel_lcx6g_suspend(dev); + break; + + case PM_DEVICE_ACTION_RESUME: + ret = quectel_lcx6g_resume(dev); + break; + + case PM_DEVICE_ACTION_TURN_ON: + quectel_lcx6g_turn_on(dev); + ret = 0; + break; + + case PM_DEVICE_ACTION_TURN_OFF: + ret = quectel_lcx6g_turn_off(dev); + break; + + default: + break; + } + + quectel_lcx6g_pm_changed(dev); + + k_spin_unlock(&data->lock, key); + return ret; +} +#endif /* CONFIG_PM_DEVICE */ + +static int quectel_lcx6g_set_fix_rate(const struct device *dev, uint32_t fix_interval_ms) +{ + struct quectel_lcx6g_data *data = dev->data; + k_spinlock_key_t key; + int ret; + + if (fix_interval_ms < 100 || fix_interval_ms > 1000) { + return -EINVAL; + } + + key = k_spin_lock(&data->lock); + + ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), + "PAIR050,%u", fix_interval_ms); + if (ret < 0) { + goto unlock_return; + } + + data->dynamic_script_chat.request_size = ret; + + ret = gnss_nmea0183_snprintk(data->dynamic_match_buf, sizeof(data->dynamic_match_buf), + "PAIR001,050,0"); + if (ret < 0) { + goto unlock_return; + } + + data->dynamic_match.match_size = ret; + + ret = modem_chat_run_script(&data->chat, &data->dynamic_script); + if (ret < 0) { + goto unlock_return; + } + +unlock_return: + k_spin_unlock(&data->lock, key); + return ret; +} + +static void quectel_lcx6g_get_fix_rate_callback(struct modem_chat *chat, char **argv, + uint16_t argc, void *user_data) +{ + struct quectel_lcx6g_data *data = user_data; + int32_t tmp; + + if (argc != 3) { + return; + } + + if ((gnss_parse_atoi(argv[1], 10, &tmp) < 0) || (tmp < 0) || (tmp > 1000)) { + return; + } + + data->fix_rate_response = (uint16_t)tmp; +} + +static int quectel_lcx6g_get_fix_rate(const struct device *dev, uint32_t *fix_interval_ms) +{ + struct quectel_lcx6g_data *data = dev->data; + k_spinlock_key_t key; + int ret; + + key = k_spin_lock(&data->lock); + + ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), + "PAIR051"); + if (ret < 0) { + goto unlock_return; + } + + data->dynamic_script_chat.request_size = ret; + + strncpy(data->dynamic_match_buf, "$PAIR051,", sizeof(data->dynamic_match_buf)); + data->dynamic_match.match_size = sizeof("$PAIR051,") - 1; + data->dynamic_match.callback = quectel_lcx6g_get_fix_rate_callback; + + ret = modem_chat_run_script(&data->chat, &data->dynamic_script); + data->dynamic_match.callback = NULL; + if (ret < 0) { + goto unlock_return; + } + + *fix_interval_ms = data->fix_rate_response; + +unlock_return: + k_spin_unlock(&data->lock, key); + return 0; +} + +static int quectel_lcx6g_set_navigation_mode(const struct device *dev, + enum gnss_navigation_mode mode) +{ + struct quectel_lcx6g_data *data = dev->data; + k_spinlock_key_t key; + uint8_t navigation_mode = 0; + int ret; + + switch (mode) { + case GNSS_NAVIGATION_MODE_ZERO_DYNAMICS: + navigation_mode = QUECTEL_LCX6G_PAIR_NAV_MODE_STATIONARY; + break; + + case GNSS_NAVIGATION_MODE_LOW_DYNAMICS: + navigation_mode = QUECTEL_LCX6G_PAIR_NAV_MODE_FITNESS; + break; + + case GNSS_NAVIGATION_MODE_BALANCED_DYNAMICS: + navigation_mode = QUECTEL_LCX6G_PAIR_NAV_MODE_NORMAL; + break; + + case GNSS_NAVIGATION_MODE_HIGH_DYNAMICS: + navigation_mode = QUECTEL_LCX6G_PAIR_NAV_MODE_DRONE; + break; + } + + key = k_spin_lock(&data->lock); + + ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), + "PAIR080,%u", navigation_mode); + if (ret < 0) { + goto unlock_return; + } + + data->dynamic_script_chat.request_size = ret; + + ret = gnss_nmea0183_snprintk(data->dynamic_match_buf, sizeof(data->dynamic_match_buf), + "PAIR001,080,0"); + if (ret < 0) { + goto unlock_return; + } + + data->dynamic_match.match_size = ret; + + ret = modem_chat_run_script(&data->chat, &data->dynamic_script); + if (ret < 0) { + goto unlock_return; + } + +unlock_return: + k_spin_unlock(&data->lock, key); + return ret; +} + +static void quectel_lcx6g_get_navigation_mode_callback(struct modem_chat *chat, char **argv, + uint16_t argc, void *user_data) +{ + struct quectel_lcx6g_data *data = user_data; + int32_t tmp; + + if (argc != 3) { + return; + } + + if ((gnss_parse_atoi(argv[1], 10, &tmp) < 0) || (tmp < 0) || (tmp > 7)) { + return; + } + + switch (tmp) { + case QUECTEL_LCX6G_PAIR_NAV_MODE_FITNESS: + data->navigation_mode_response = GNSS_NAVIGATION_MODE_LOW_DYNAMICS; + break; + + case QUECTEL_LCX6G_PAIR_NAV_MODE_STATIONARY: + data->navigation_mode_response = GNSS_NAVIGATION_MODE_ZERO_DYNAMICS; + break; + + case QUECTEL_LCX6G_PAIR_NAV_MODE_DRONE: + data->navigation_mode_response = GNSS_NAVIGATION_MODE_HIGH_DYNAMICS; + break; + + default: + data->navigation_mode_response = GNSS_NAVIGATION_MODE_BALANCED_DYNAMICS; + break; + } +} + +static int quectel_lcx6g_get_navigation_mode(const struct device *dev, + enum gnss_navigation_mode *mode) +{ + struct quectel_lcx6g_data *data = dev->data; + k_spinlock_key_t key; + int ret; + + key = k_spin_lock(&data->lock); + + ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), + "PAIR081"); + if (ret < 0) { + goto unlock_return; + } + + data->dynamic_script_chat.request_size = ret; + + strncpy(data->dynamic_match_buf, "$PAIR081,", sizeof(data->dynamic_match_buf)); + data->dynamic_match.match_size = sizeof("$PAIR081,") - 1; + data->dynamic_match.callback = quectel_lcx6g_get_navigation_mode_callback; + + ret = modem_chat_run_script(&data->chat, &data->dynamic_script); + data->dynamic_match.callback = NULL; + if (ret < 0) { + goto unlock_return; + } + + *mode = data->navigation_mode_response; + +unlock_return: + k_spin_unlock(&data->lock, key); + return ret; +} + +static int quectel_lcx6g_set_enabled_systems(const struct device *dev, gnss_systems_t systems) +{ + struct quectel_lcx6g_data *data = dev->data; + gnss_systems_t supported_systems; + k_spinlock_key_t key; + int ret; + + supported_systems = (GNSS_SYSTEM_GPS | GNSS_SYSTEM_GLONASS | GNSS_SYSTEM_GALILEO | + GNSS_SYSTEM_BEIDOU | GNSS_SYSTEM_QZSS | GNSS_SYSTEM_SBAS); + + if ((~supported_systems) & systems) { + return -EINVAL; + } + + key = k_spin_lock(&data->lock); + + ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), + "PAIR066,%u,%u,%u,%u,%u,0", + (0 < (systems & GNSS_SYSTEM_GPS)), + (0 < (systems & GNSS_SYSTEM_GLONASS)), + (0 < (systems & GNSS_SYSTEM_GALILEO)), + (0 < (systems & GNSS_SYSTEM_BEIDOU)), + (0 < (systems & GNSS_SYSTEM_QZSS))); + if (ret < 0) { + goto unlock_return; + } + + data->dynamic_script_chat.request_size = ret; + + ret = gnss_nmea0183_snprintk(data->dynamic_match_buf, sizeof(data->dynamic_match_buf), + "PAIR001,066,0"); + if (ret < 0) { + goto unlock_return; + } + + data->dynamic_match.match_size = ret; + + ret = modem_chat_run_script(&data->chat, &data->dynamic_script); + if (ret < 0) { + goto unlock_return; + } + + ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), + "PAIR410,%u", (0 < (systems & GNSS_SYSTEM_SBAS))); + if (ret < 0) { + goto unlock_return; + } + + data->dynamic_script_chat.request_size = ret; + + ret = gnss_nmea0183_snprintk(data->dynamic_match_buf, sizeof(data->dynamic_match_buf), + "PAIR001,410,0"); + if (ret < 0) { + goto unlock_return; + } + + data->dynamic_match.match_size = ret; + + ret = modem_chat_run_script(&data->chat, &data->dynamic_script); + if (ret < 0) { + goto unlock_return; + } + +unlock_return: + k_spin_unlock(&data->lock, key); + return ret; +} + +static inline bool search_mode_enabled(const char *arg) +{ + return arg[0] == '1'; +} + +static void quectel_lcx6g_get_search_mode_callback(struct modem_chat *chat, char **argv, + uint16_t argc, void *user_data) +{ + struct quectel_lcx6g_data *data = user_data; + + if (argc != 8) { + return; + } + + data->enabled_systems_response = search_mode_enabled(argv[1]) ? GNSS_SYSTEM_GPS : 0; + data->enabled_systems_response |= search_mode_enabled(argv[2]) ? GNSS_SYSTEM_GLONASS : 0; + data->enabled_systems_response |= search_mode_enabled(argv[3]) ? GNSS_SYSTEM_GALILEO : 0; + data->enabled_systems_response |= search_mode_enabled(argv[4]) ? GNSS_SYSTEM_BEIDOU : 0; + data->enabled_systems_response |= search_mode_enabled(argv[5]) ? GNSS_SYSTEM_QZSS : 0; +} + +static void quectel_lcx6g_get_sbas_status_callback(struct modem_chat *chat, char **argv, + uint16_t argc, void *user_data) +{ + struct quectel_lcx6g_data *data = user_data; + + if (argc != 3) { + return; + } + + data->enabled_systems_response |= ('1' == argv[1][0]) ? GNSS_SYSTEM_SBAS : 0; +} + + +static int quectel_lcx6g_get_enabled_systems(const struct device *dev, gnss_systems_t *systems) +{ + struct quectel_lcx6g_data *data = dev->data; + k_spinlock_key_t key; + int ret; + + key = k_spin_lock(&data->lock); + + ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), + "PAIR067"); + if (ret < 0) { + goto unlock_return; + } + + data->dynamic_script_chat.request_size = ret; + + strncpy(data->dynamic_match_buf, "$PAIR067,", sizeof(data->dynamic_match_buf)); + data->dynamic_match.match_size = sizeof("$PAIR067,") - 1; + data->dynamic_match.callback = quectel_lcx6g_get_search_mode_callback; + + ret = modem_chat_run_script(&data->chat, &data->dynamic_script); + data->dynamic_match.callback = NULL; + if (ret < 0) { + goto unlock_return; + } + + ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), + "PAIR411"); + if (ret < 0) { + goto unlock_return; + } + + data->dynamic_script_chat.request_size = ret; + + strncpy(data->dynamic_match_buf, "$PAIR411,", sizeof(data->dynamic_match_buf)); + data->dynamic_match.match_size = sizeof("$PAIR411,") - 1; + data->dynamic_match.callback = quectel_lcx6g_get_sbas_status_callback; + + ret = modem_chat_run_script(&data->chat, &data->dynamic_script); + data->dynamic_match.callback = NULL; + if (ret < 0) { + goto unlock_return; + } + + *systems = data->enabled_systems_response; + +unlock_return: + k_spin_unlock(&data->lock, key); + return ret; +} + +static int quectel_lcx6g_get_supported_systems(const struct device *dev, gnss_systems_t *systems) +{ + *systems = (GNSS_SYSTEM_GPS | GNSS_SYSTEM_GLONASS | GNSS_SYSTEM_GALILEO | + GNSS_SYSTEM_BEIDOU | GNSS_SYSTEM_QZSS | GNSS_SYSTEM_SBAS); + return 0; +} + +static struct gnss_driver_api gnss_api = { + .set_fix_rate = quectel_lcx6g_set_fix_rate, + .get_fix_rate = quectel_lcx6g_get_fix_rate, + .set_navigation_mode = quectel_lcx6g_set_navigation_mode, + .get_navigation_mode = quectel_lcx6g_get_navigation_mode, + .set_enabled_systems = quectel_lcx6g_set_enabled_systems, + .get_enabled_systems = quectel_lcx6g_get_enabled_systems, + .get_supported_systems = quectel_lcx6g_get_supported_systems, +}; + +static int quectel_lcx6g_init_nmea0183_match(const struct device *dev) +{ + struct quectel_lcx6g_data *data = dev->data; + + const struct gnss_nmea0183_match_config 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, &config); +} + +static void quectel_lcx6g_init_pipe(const struct device *dev) +{ + const struct quectel_lcx6g_config *config = dev->config; + struct quectel_lcx6g_data *data = dev->data; + + const struct modem_backend_uart_config uart_backend_config = { + .uart = config->uart, + .receive_buf = data->uart_backend_receive_buf, + .receive_buf_size = ARRAY_SIZE(data->uart_backend_receive_buf), + .transmit_buf = data->uart_backend_transmit_buf, + .transmit_buf_size = ARRAY_SIZE(data->uart_backend_transmit_buf), + }; + + data->uart_pipe = modem_backend_uart_init(&data->uart_backend, &uart_backend_config); +} + +static int quectel_lcx6g_init_chat(const struct device *dev) +{ + struct quectel_lcx6g_data *data = dev->data; + + const struct modem_chat_config chat_config = { + .user_data = data, + .receive_buf = data->chat_receive_buf, + .receive_buf_size = ARRAY_SIZE(data->chat_receive_buf), + .delimiter = data->chat_delimiter, + .delimiter_size = ARRAY_SIZE(data->chat_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 void quectel_lcx6g_init_dynamic_script(const struct device *dev) +{ + struct quectel_lcx6g_data *data = dev->data; + + data->dynamic_match.match = data->dynamic_match_buf; + data->dynamic_match.separators = data->dynamic_separators_buf; + data->dynamic_match.separators_size = sizeof(data->dynamic_separators_buf); + data->dynamic_match.wildcards = false; + data->dynamic_match.partial = false; + + data->dynamic_script_chat.request = data->dynamic_request_buf; + data->dynamic_script_chat.response_matches = &data->dynamic_match; + data->dynamic_script_chat.response_matches_size = 1; + data->dynamic_script_chat.timeout = 0; + + data->dynamic_script.name = "pair"; + data->dynamic_script.script_chats = &data->dynamic_script_chat; + data->dynamic_script.script_chats_size = 1; + data->dynamic_script.abort_matches = NULL; + data->dynamic_script.abort_matches_size = 0; + data->dynamic_script.callback = NULL; + data->dynamic_script.timeout = 10; +} + +static int quectel_lcx6g_init(const struct device *dev) +{ + int ret; + + ret = quectel_lcx6g_init_nmea0183_match(dev); + if (ret < 0) { + return ret; + } + + quectel_lcx6g_init_pipe(dev); + + ret = quectel_lcx6g_init_chat(dev); + if (ret < 0) { + return ret; + } + + quectel_lcx6g_init_dynamic_script(dev); + + 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); + } + + return pm_device_runtime_enable(dev); +} + +#define LCX6G_INST_NAME(inst, name) \ + _CONCAT(_CONCAT(_CONCAT(name, _), DT_DRV_COMPAT), inst) + +#define LCX6G_DEVICE(inst) \ + static struct quectel_lcx6g_config LCX6G_INST_NAME(inst, config) = { \ + .uart = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + .pps_mode = DT_INST_STRING_UPPER_TOKEN(inst, pps_mode), \ + .pps_pulse_width = DT_INST_PROP(inst, pps_pulse_width), \ + }; \ + \ + static struct quectel_lcx6g_data LCX6G_INST_NAME(inst, data) = { \ + .chat_delimiter = {'\r', '\n'}, \ + .dynamic_separators_buf = {',', '*'}, \ + }; \ + \ + PM_DEVICE_DT_INST_DEFINE(inst, quectel_lcx6g_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(inst, quectel_lcx6g_init, PM_DEVICE_DT_INST_GET(inst), \ + &LCX6G_INST_NAME(inst, data), &LCX6G_INST_NAME(inst, config), \ + POST_KERNEL, CONFIG_GNSS_INIT_PRIORITY, &gnss_api); + +#define DT_DRV_COMPAT quectel_lc26g +DT_INST_FOREACH_STATUS_OKAY(LCX6G_DEVICE) +#undef DT_DRV_COMPAT + +#define DT_DRV_COMPAT quectel_lc76g +DT_INST_FOREACH_STATUS_OKAY(LCX6G_DEVICE) +#undef DT_DRV_COMPAT + +#define DT_DRV_COMPAT quectel_lc86g +DT_INST_FOREACH_STATUS_OKAY(LCX6G_DEVICE) +#undef DT_DRV_COMPAT diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index c503bcd5e00f4bc..529c171699bafe1 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/gpio.h) zephyr_library() +zephyr_library_sources_ifdef(CONFIG_GPIO_AD5592 gpio_ad5592.c) zephyr_library_sources_ifdef(CONFIG_GPIO_AXP192 gpio_axp192.c) zephyr_library_sources_ifdef(CONFIG_GPIO_TELINK_B91 gpio_b91.c) zephyr_library_sources_ifdef(CONFIG_GPIO_INFINEON_CAT1 gpio_ifx_cat1.c) @@ -26,6 +27,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 +58,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) @@ -84,7 +86,12 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_NUMAKER gpio_numaker.c) zephyr_library_sources_ifdef(CONFIG_GPIO_EFINIX_SAPPHIRE gpio_efinix_sapphire.c) zephyr_library_sources_ifdef(CONFIG_GPIO_DAVINCI gpio_davinci.c) 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_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 7eac8c7aa894e36..0c7d5820dea770f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -20,6 +20,24 @@ config GPIO_SHELL help Enable GPIO Shell for testing. +config GPIO_SHELL_INFO_CMD + bool "GPIO Shell info command" + default y + depends on GPIO_SHELL + help + Enable GPIO Shell information command. + This command provides a shell user extra information about gpio + controller reserved pins and line names. + +config GPIO_SHELL_BLINK_CMD + bool "GPIO Shell blink command" + default y + depends on GPIO_SHELL + help + Enable GPIO Shell blink command. + This command provides a shell user the ability to 'blink' a pin + at 1Hz. + config GPIO_INIT_PRIORITY int "GPIO init priority" default KERNEL_INIT_PRIORITY_DEFAULT @@ -69,6 +87,8 @@ config GPIO_ENABLE_DISABLE_INTERRUPT pending register, etc. The driver must implement it to work. +source "drivers/gpio/Kconfig.ad5592" + source "drivers/gpio/Kconfig.axp192" source "drivers/gpio/Kconfig.b91" @@ -85,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" @@ -161,7 +183,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" @@ -208,6 +230,16 @@ source "drivers/gpio/Kconfig.efinix_sapphire" source "drivers/gpio/Kconfig.davinci" source "drivers/gpio/Kconfig.sedi" +source "drivers/gpio/Kconfig.tle9104" + source "drivers/gpio/Kconfig.altera" +source "drivers/gpio/Kconfig.bcm2711" + +source "drivers/gpio/Kconfig.renesas_ra" + +source "drivers/gpio/Kconfig.rzt2m" + +source "drivers/gpio/Kconfig.ambiq" + endif # GPIO diff --git a/drivers/gpio/Kconfig.ad5592 b/drivers/gpio/Kconfig.ad5592 new file mode 100644 index 000000000000000..c2654d1857bdea8 --- /dev/null +++ b/drivers/gpio/Kconfig.ad5592 @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Grinn +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_AD5592 + bool "AD5592 GPIO driver" + default y + depends on DT_HAS_ADI_AD5592_GPIO_ENABLED + select MFD + help + Enable the AD5592 GPIO driver. diff --git a/drivers/gpio/Kconfig.ambiq b/drivers/gpio/Kconfig.ambiq new file mode 100644 index 000000000000000..924028e6f275c01 --- /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.axp192 b/drivers/gpio/Kconfig.axp192 index a9e648309fb89ab..c81c02d895ca788 100644 --- a/drivers/gpio/Kconfig.axp192 +++ b/drivers/gpio/Kconfig.axp192 @@ -14,7 +14,7 @@ config GPIO_AXP192 config GPIO_AXP192_INIT_PRIORITY int "AXP192 GPIO driver initialization priority" depends on GPIO_AXP192 - default 80 + default 81 help Initialization priority for the AXP192 GPIO driver. It must be greater than the I2C controller init priority and the mfd driver diff --git a/drivers/gpio/Kconfig.bcm2711 b/drivers/gpio/Kconfig.bcm2711 new file mode 100644 index 000000000000000..ad7c3c11b13f5b4 --- /dev/null +++ b/drivers/gpio/Kconfig.bcm2711 @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_BCM2711 + bool "BCM2711 GPIO driver" + default y + depends on DT_HAS_BRCM_BCM2711_GPIO_ENABLED + help + Enable BCM2711 GPIO driver. diff --git a/drivers/gpio/Kconfig.mcux_rgpio b/drivers/gpio/Kconfig.mcux_rgpio new file mode 100644 index 000000000000000..6446137542aa8f2 --- /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.nct38xx b/drivers/gpio/Kconfig.nct38xx index 25e91e3cf09bf20..dfa5cbf9c384175 100644 --- a/drivers/gpio/Kconfig.nct38xx +++ b/drivers/gpio/Kconfig.nct38xx @@ -16,14 +16,14 @@ if GPIO_NCT38XX config GPIO_NCT38XX_INIT_PRIORITY int "NCT38XX GPIO init priority" - default 62 + default 82 help NCT38xx GPIO driver initialization priority. The priority must be lower than MFD_INIT_PRIORITY. config GPIO_NCT38XX_PORT_INIT_PRIORITY int "NCT38XX GPIO port init priority" - default 64 + default 84 help NCT38xx GPIO port device driver initialization priority. The priority must be lower than GPIO_NCT38XX_INIT_PRIORITY device. @@ -37,7 +37,7 @@ config GPIO_NCT38XX_ALERT config GPIO_NCT38XX_ALERT_INIT_PRIORITY int "NCT38XX GPIO alert handler init priority" - default 64 + default 84 depends on GPIO_NCT38XX_ALERT help NCT38XX alert handler initialization priority. This initialization diff --git a/drivers/gpio/Kconfig.npm1300 b/drivers/gpio/Kconfig.npm1300 index c3cbf53d6e20e36..65cb81a36868ced 100644 --- a/drivers/gpio/Kconfig.npm1300 +++ b/drivers/gpio/Kconfig.npm1300 @@ -13,7 +13,7 @@ config GPIO_NPM1300 config GPIO_NPM1300_INIT_PRIORITY int "nPM1300 GPIO driver initialization priority" depends on GPIO_NPM1300 - default 70 + default 85 help Initialization priority for the nPM1300 GPIO driver. It must be greater than the I2C controller init priority. diff --git a/drivers/gpio/Kconfig.npm6001 b/drivers/gpio/Kconfig.npm6001 index 81fc4cb4a604567..b138b101a7236e5 100644 --- a/drivers/gpio/Kconfig.npm6001 +++ b/drivers/gpio/Kconfig.npm6001 @@ -13,6 +13,6 @@ config GPIO_NPM6001 config GPIO_NPM6001_INIT_PRIORITY int "nPM6001 GPIO driver initialization priority" depends on GPIO_NPM6001 - default 65 + default 85 help Initialization priority for the nPM6001 GPIO driver. diff --git a/drivers/gpio/Kconfig.nrfx b/drivers/gpio/Kconfig.nrfx index 356c43cb5fa1fc3..760a45204fdff48 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 0c35008aa645652..000000000000000 --- 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 000000000000000..2617d8a76a101c9 --- /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.renesas_ra b/drivers/gpio/Kconfig.renesas_ra new file mode 100644 index 000000000000000..bd6f536ee80f1a8 --- /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/Kconfig.rzt2m b/drivers/gpio/Kconfig.rzt2m new file mode 100644 index 000000000000000..d9cb6b1e8675592 --- /dev/null +++ b/drivers/gpio/Kconfig.rzt2m @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_RZT2M + bool "Renesas RZT2M GPIO" + default y + depends on DT_HAS_RENESAS_RZT2M_GPIO_ENABLED + help + Enable Renesas RZT2M GPIO driver. diff --git a/drivers/gpio/Kconfig.tle9104 b/drivers/gpio/Kconfig.tle9104 new file mode 100644 index 000000000000000..fd12710a5f57a68 --- /dev/null +++ b/drivers/gpio/Kconfig.tle9104 @@ -0,0 +1,19 @@ +# TLE9104 GPIO configuration options + +# Copyright (c) 2023 SILA Embedded Solutions GmbH +# SPDX-License-Identifier: Apache-2.0 + +menuconfig GPIO_TLE9104 + bool "TLE9104 SPI-based powertrain switch" + default y + depends on DT_HAS_INFINEON_TLE9104_ENABLED + depends on SPI + help + Enable driver for TLE9104 SPI-based powertrain switch. + +config GPIO_TLE9104_INIT_PRIORITY + int "Init priority" + default 75 + depends on GPIO_TLE9104 + help + Device driver initialization priority. diff --git a/drivers/gpio/gpio_ad5592.c b/drivers/gpio/gpio_ad5592.c new file mode 100644 index 000000000000000..a8b30ddcee4d063 --- /dev/null +++ b/drivers/gpio/gpio_ad5592.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_ad5592_gpio + +#include +#include +#include +#include + +#include + +struct gpio_ad5592_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + const struct device *mfd_dev; +}; + +struct gpio_ad5592_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + uint8_t gpio_val; + uint8_t gpio_out; + uint8_t gpio_in; + uint8_t gpio_pull_down; +}; + +static int gpio_ad5592_port_get_raw(const struct device *dev, uint32_t *value) +{ + const struct gpio_ad5592_config *config = dev->config; + struct gpio_ad5592_data *drv_data = dev->data; + uint16_t data; + int ret; + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + ret = mfd_ad5592_read_reg(config->mfd_dev, + AD5592_REG_GPIO_INPUT_EN, drv_data->gpio_in, &data); + if (ret < 0) { + return ret; + } + + *value = (uint32_t)data; + + return 0; +} + +static int gpio_ad5592_port_set_bits_raw(const struct device *dev, + gpio_port_pins_t pins) +{ + struct gpio_ad5592_data *data = dev->data; + const struct gpio_ad5592_config *config = dev->config; + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + data->gpio_val |= (uint8_t)pins; + + return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_GPIO_SET, data->gpio_val); +} + +static int gpio_ad5592_port_clear_bits_raw(const struct device *dev, + gpio_port_pins_t pins) +{ + struct gpio_ad5592_data *data = dev->data; + const struct gpio_ad5592_config *config = dev->config; + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + data->gpio_val &= ~(uint8_t)pins; + + return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_GPIO_SET, data->gpio_val); +} + +static inline int gpio_ad5592_configure(const struct device *dev, + gpio_pin_t pin, gpio_flags_t flags) +{ + struct gpio_ad5592_data *data = dev->data; + const struct gpio_ad5592_config *config = dev->config; + uint8_t val; + int ret; + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + if (pin >= AD5592_PIN_MAX) { + return -EINVAL; + } + + val = BIT(pin); + if ((flags & GPIO_OUTPUT) != 0U) { + data->gpio_in &= ~val; + data->gpio_out |= val; + + if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) { + ret = gpio_ad5592_port_set_bits_raw( + dev, (gpio_port_pins_t)BIT(pin)); + if (ret < 0) { + return ret; + } + } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) { + ret = gpio_ad5592_port_clear_bits_raw( + dev, (gpio_port_pins_t)BIT(pin)); + if (ret < 0) { + return ret; + } + } + + ret = mfd_ad5592_write_reg(config->mfd_dev, + AD5592_REG_GPIO_OUTPUT_EN, data->gpio_out); + if (ret < 0) { + return ret; + } + + ret = mfd_ad5592_write_reg(config->mfd_dev, + AD5592_REG_GPIO_INPUT_EN, data->gpio_in); + } else if ((flags & GPIO_INPUT) != 0U) { + data->gpio_in |= val; + data->gpio_out &= ~val; + + if ((flags & GPIO_PULL_DOWN) != 0U) { + data->gpio_pull_down |= val; + + ret = mfd_ad5592_write_reg(config->mfd_dev, + AD5592_REG_GPIO_PULLDOWN, + data->gpio_pull_down); + if (ret < 0) { + return ret; + } + } else if ((flags & GPIO_PULL_UP) != 0U) { + return -ENOTSUP; + } + + ret = mfd_ad5592_write_reg(config->mfd_dev, + AD5592_REG_GPIO_OUTPUT_EN, data->gpio_out); + if (ret < 0) { + return ret; + } + + ret = mfd_ad5592_write_reg(config->mfd_dev, + AD5592_REG_GPIO_INPUT_EN, data->gpio_in); + } else { + return -ENOTSUP; + } + + return ret; +} + +static int gpio_ad5592_port_set_masked_raw(const struct device *dev, + gpio_port_pins_t mask, + gpio_port_value_t value) +{ + ARG_UNUSED(dev); + ARG_UNUSED(mask); + ARG_UNUSED(value); + + return -ENOTSUP; +} + +static int gpio_ad5592_port_toggle_bits(const struct device *dev, + gpio_port_pins_t pins) +{ + ARG_UNUSED(dev); + ARG_UNUSED(pins); + + return -ENOTSUP; +} + +static int gpio_ad5592_pin_interrupt_configure(const struct device *dev, + gpio_pin_t pin, + enum gpio_int_mode mode, + enum gpio_int_trig trig) +{ + ARG_UNUSED(dev); + ARG_UNUSED(pin); + ARG_UNUSED(mode); + ARG_UNUSED(trig); + + return -ENOTSUP; +} + +static const struct gpio_driver_api gpio_ad5592_api = { + .pin_configure = gpio_ad5592_configure, + .port_get_raw = gpio_ad5592_port_get_raw, + .port_set_masked_raw = gpio_ad5592_port_set_masked_raw, + .port_set_bits_raw = gpio_ad5592_port_set_bits_raw, + .port_clear_bits_raw = gpio_ad5592_port_clear_bits_raw, + .port_toggle_bits = gpio_ad5592_port_toggle_bits, + .pin_interrupt_configure = gpio_ad5592_pin_interrupt_configure, +}; + +static int gpio_ad5592_init(const struct device *dev) +{ + const struct gpio_ad5592_config *config = dev->config; + + if (!device_is_ready(config->mfd_dev)) { + return -ENODEV; + } + + return 0; +} + +#define GPIO_AD5592_DEFINE(inst) \ + static const struct gpio_ad5592_config gpio_ad5592_config##inst = { \ + .common = { \ + .port_pin_mask = \ + GPIO_PORT_PIN_MASK_FROM_DT_INST(inst), \ + }, \ + .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + }; \ + \ + static struct gpio_ad5592_data gpio_ad5592_data##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, gpio_ad5592_init, NULL, \ + &gpio_ad5592_data##inst, &gpio_ad5592_config##inst, \ + POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ + &gpio_ad5592_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_AD5592_DEFINE) diff --git a/drivers/gpio/gpio_ambiq.c b/drivers/gpio/gpio_ambiq.c new file mode 100644 index 000000000000000..b036094e683f1de --- /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 4b5d18fc0a7d597..f7c8bdfc4da902e 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 bc73f9db9f59c7a..4c4c14dc9098c44 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_bcm2711.c b/drivers/gpio/gpio_bcm2711.c new file mode 100644 index 000000000000000..a4e4a31e7c9af61 --- /dev/null +++ b/drivers/gpio/gpio_bcm2711.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2023 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT brcm_bcm2711_gpio + +#include +#include +#include +#include +#include + +#define GPIO_REG_GROUP(n, cnt) (n / cnt) +#define GPIO_REG_SHIFT(n, cnt, bits) ((n % cnt) * bits) + +#define GPFSEL(base, n) (base + 0x00 + 0x04 * n) +#define GPSET(base, n) (base + 0x1C + 0x04 * n) +#define GPCLR(base, n) (base + 0x28 + 0x04 * n) +#define GPLEV(base, n) (base + 0x34 + 0x04 * n) +#define GPEDS(base, n) (base + 0x40 + 0x04 * n) +#define GPREN(base, n) (base + 0x4C + 0x04 * n) +#define GPFEN(base, n) (base + 0x58 + 0x04 * n) +#define GPHEN(base, n) (base + 0x64 + 0x04 * n) +#define GPLEN(base, n) (base + 0x70 + 0x04 * n) +#define GPAREN(base, n) (base + 0x7C + 0x04 * n) +#define GPAFEN(base, n) (base + 0x88 + 0x04 * n) +#define GPPULL(base, n) (base + 0xE4 + 0x04 * n) + +#define FSEL_GROUPS (10) +#define FSEL_BITS (3) +#define FSEL_OUTPUT (0x1) + +#define IO_GROUPS (32) +#define IO_BITS (1) + +#define PULL_GROUPS (16) +#define PULL_BITS (2) +#define PULL_UP (0x1) +#define PULL_DOWN (0x2) + +#define DEV_CFG(dev) ((const struct gpio_bcm2711_config *const)(dev)->config) +#define DEV_DATA(dev) ((struct gpio_bcm2711_data *const)(dev)->data) + +#define RPI_PIN_NUM(dev, n) (DEV_CFG(dev)->offset + n) + +#define FROM_U64(val, idx) ((uint32_t)((val >> (idx * 32)) & UINT32_MAX)) + +struct gpio_bcm2711_config { + struct gpio_driver_config common; + + DEVICE_MMIO_NAMED_ROM(reg_base); + + void (*irq_config_func)(void); + + uint8_t offset; + uint8_t ngpios; +}; + +struct gpio_bcm2711_data { + struct gpio_driver_data common; + + DEVICE_MMIO_NAMED_RAM(reg_base); + mem_addr_t base; + + sys_slist_t cb; +}; + +static int gpio_bcm2711_pin_configure(const struct device *port, gpio_pin_t pin, gpio_flags_t flags) +{ + struct gpio_bcm2711_data *data = DEV_DATA(port); + uint32_t group; + uint32_t shift; + uint32_t regval; + + if (flags & GPIO_OPEN_DRAIN) { + return -ENOTSUP; + } + + /* Set direction */ + { + group = GPIO_REG_GROUP(RPI_PIN_NUM(port, pin), FSEL_GROUPS); + shift = GPIO_REG_SHIFT(RPI_PIN_NUM(port, pin), FSEL_GROUPS, FSEL_BITS); + + regval = sys_read32(GPFSEL(data->base, group)); + regval &= ~(BIT_MASK(FSEL_BITS) << shift); + if (flags & GPIO_OUTPUT) { + regval |= (FSEL_OUTPUT << shift); + } + sys_write32(regval, GPFSEL(data->base, group)); + } + + /* Set output level */ + if (flags & GPIO_OUTPUT) { + group = GPIO_REG_GROUP(RPI_PIN_NUM(port, pin), IO_GROUPS); + shift = GPIO_REG_SHIFT(RPI_PIN_NUM(port, pin), IO_GROUPS, IO_BITS); + + if (flags & GPIO_OUTPUT_INIT_HIGH) { + regval = sys_read32(GPSET(data->base, group)); + regval |= BIT(shift); + sys_write32(regval, GPSET(data->base, group)); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + regval = sys_read32(GPCLR(data->base, group)); + regval |= BIT(shift); + sys_write32(regval, GPCLR(data->base, group)); + } + } + + /* Set pull */ + { + group = GPIO_REG_GROUP(RPI_PIN_NUM(port, pin), PULL_GROUPS); + shift = GPIO_REG_SHIFT(RPI_PIN_NUM(port, pin), PULL_GROUPS, PULL_BITS); + + regval = sys_read32(GPPULL(data->base, group)); + regval &= ~(BIT_MASK(PULL_BITS) << shift); + if (flags & GPIO_PULL_UP) { + regval |= (PULL_UP << shift); + } else if (flags & GPIO_PULL_DOWN) { + regval |= (PULL_DOWN << shift); + } + sys_write32(regval, GPPULL(data->base, group)); + } + + return 0; +} + +static int gpio_bcm2711_port_get_raw(const struct device *port, gpio_port_value_t *value) +{ + const struct gpio_bcm2711_config *cfg = DEV_CFG(port); + struct gpio_bcm2711_data *data = DEV_DATA(port); + uint64_t regval; + + regval = ((uint64_t)sys_read32(GPLEV(data->base, 0))) | + ((uint64_t)sys_read32(GPLEV(data->base, 1)) << 32); + + *value = (regval >> cfg->offset) & BIT_MASK(cfg->ngpios); + + return 0; +} + +static int gpio_bcm2711_port_set_masked_raw(const struct device *port, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + const struct gpio_bcm2711_config *cfg = DEV_CFG(port); + struct gpio_bcm2711_data *data = DEV_DATA(port); + uint64_t regval, regmask; + uint64_t set, clr; + + value &= BIT_MASK(cfg->ngpios); + mask &= BIT_MASK(cfg->ngpios); + + regval = (uint64_t)value << cfg->offset; + regmask = (uint64_t)mask << cfg->offset; + + set = regval & regmask; + clr = regval ^ regmask; + + sys_write32(FROM_U64(set, 0), GPSET(data->base, 0)); + sys_write32(FROM_U64(clr, 0), GPCLR(data->base, 0)); + sys_write32(FROM_U64(set, 1), GPSET(data->base, 1)); + sys_write32(FROM_U64(clr, 1), GPCLR(data->base, 1)); + + return 0; +} + +static int gpio_bcm2711_port_set_bits_raw(const struct device *port, gpio_port_pins_t pins) +{ + const struct gpio_bcm2711_config *cfg = DEV_CFG(port); + struct gpio_bcm2711_data *data = DEV_DATA(port); + uint64_t regval; + + regval = ((uint64_t)pins & BIT_MASK(cfg->ngpios)) << cfg->offset; + + sys_write32(FROM_U64(regval, 0), GPSET(data->base, 0)); + sys_write32(FROM_U64(regval, 1), GPSET(data->base, 1)); + + return 0; +} + +static int gpio_bcm2711_port_clear_bits_raw(const struct device *port, gpio_port_pins_t pins) +{ + const struct gpio_bcm2711_config *cfg = DEV_CFG(port); + struct gpio_bcm2711_data *data = DEV_DATA(port); + uint64_t regval; + + regval = ((uint64_t)pins & BIT_MASK(cfg->ngpios)) << cfg->offset; + + sys_write32(FROM_U64(regval, 0), GPCLR(data->base, 0)); + sys_write32(FROM_U64(regval, 1), GPCLR(data->base, 1)); + + return 0; +} + +static int gpio_bcm2711_port_toggle_bits(const struct device *port, gpio_port_pins_t pins) +{ + const struct gpio_bcm2711_config *cfg = DEV_CFG(port); + struct gpio_bcm2711_data *data = DEV_DATA(port); + uint64_t regval, regmask; + uint64_t set, clr; + + regval = ((uint64_t)sys_read32(GPLEV(data->base, 0))) | + ((uint64_t)sys_read32(GPLEV(data->base, 1)) << 32); + + regmask = ((uint64_t)pins & BIT_MASK(cfg->ngpios)) << cfg->offset; + + set = regval ^ regmask; + clr = regval & regmask; + + sys_write32(FROM_U64(set, 0), GPSET(data->base, 0)); + sys_write32(FROM_U64(clr, 0), GPCLR(data->base, 0)); + sys_write32(FROM_U64(set, 1), GPSET(data->base, 1)); + sys_write32(FROM_U64(clr, 1), GPCLR(data->base, 1)); + + return 0; +} + +static int gpio_bcm2711_pin_interrupt_configure(const struct device *port, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + struct gpio_bcm2711_data *data = DEV_DATA(port); + uint32_t group; + uint32_t shift; + uint32_t regval; + + group = GPIO_REG_GROUP(RPI_PIN_NUM(port, pin), IO_GROUPS); + shift = GPIO_REG_SHIFT(RPI_PIN_NUM(port, pin), IO_GROUPS, IO_BITS); + + /* Clear all detections first */ + + regval = sys_read32(GPREN(data->base, group)); + regval &= ~BIT(shift); + sys_write32(regval, GPREN(data->base, group)); + + regval = sys_read32(GPFEN(data->base, group)); + regval &= ~BIT(shift); + sys_write32(regval, GPFEN(data->base, group)); + + regval = sys_read32(GPHEN(data->base, group)); + regval &= ~BIT(shift); + sys_write32(regval, GPHEN(data->base, group)); + + regval = sys_read32(GPLEN(data->base, group)); + regval &= ~BIT(shift); + sys_write32(regval, GPLEN(data->base, group)); + + regval = sys_read32(GPAREN(data->base, group)); + regval &= ~BIT(shift); + sys_write32(regval, GPAREN(data->base, group)); + + regval = sys_read32(GPAFEN(data->base, group)); + regval &= ~BIT(shift); + sys_write32(regval, GPAFEN(data->base, group)); + + if (mode == GPIO_INT_MODE_LEVEL) { + if (trig & GPIO_INT_LOW_0) { + regval = sys_read32(GPLEN(data->base, group)); + regval |= BIT(shift); + sys_write32(regval, GPLEN(data->base, group)); + } + if (trig & GPIO_INT_HIGH_1) { + regval = sys_read32(GPHEN(data->base, group)); + regval |= BIT(shift); + sys_write32(regval, GPHEN(data->base, group)); + } + } else if (mode == GPIO_INT_MODE_EDGE) { + if (trig & GPIO_INT_LOW_0) { + regval = sys_read32(GPAFEN(data->base, group)); + regval |= BIT(shift); + sys_write32(regval, GPAFEN(data->base, group)); + } + if (trig & GPIO_INT_HIGH_1) { + regval = sys_read32(GPAREN(data->base, group)); + regval |= BIT(shift); + sys_write32(regval, GPAREN(data->base, group)); + } + } + + return 0; +} + +static int gpio_bcm2711_manage_callback(const struct device *port, struct gpio_callback *cb, + bool set) +{ + struct gpio_bcm2711_data *data = DEV_DATA(port); + + return gpio_manage_callback(&data->cb, cb, set); +} + +static void gpio_bcm2711_isr(const struct device *port) +{ + const struct gpio_bcm2711_config *cfg = DEV_CFG(port); + struct gpio_bcm2711_data *data = DEV_DATA(port); + uint64_t regval; + uint32_t pins; + + regval = ((uint64_t)sys_read32(GPEDS(data->base, 0))) | + ((uint64_t)sys_read32(GPEDS(data->base, 1)) << 32); + + regval &= BIT_MASK(cfg->ngpios) << cfg->offset; + + pins = (uint32_t)(regval >> cfg->offset); + gpio_fire_callbacks(&data->cb, port, pins); + + /* Write to clear */ + sys_write32(FROM_U64(regval, 0), GPEDS(data->base, 0)); + sys_write32(FROM_U64(regval, 1), GPEDS(data->base, 1)); +} + +int gpio_bcm2711_init(const struct device *port) +{ + const struct gpio_bcm2711_config *cfg = DEV_CFG(port); + struct gpio_bcm2711_data *data = DEV_DATA(port); + + DEVICE_MMIO_NAMED_MAP(port, reg_base, K_MEM_CACHE_NONE); + data->base = DEVICE_MMIO_NAMED_GET(port, reg_base); + + cfg->irq_config_func(); + + return 0; +} + +static const struct gpio_driver_api gpio_bcm2711_api = { + .pin_configure = gpio_bcm2711_pin_configure, + .port_get_raw = gpio_bcm2711_port_get_raw, + .port_set_masked_raw = gpio_bcm2711_port_set_masked_raw, + .port_set_bits_raw = gpio_bcm2711_port_set_bits_raw, + .port_clear_bits_raw = gpio_bcm2711_port_clear_bits_raw, + .port_toggle_bits = gpio_bcm2711_port_toggle_bits, + .pin_interrupt_configure = gpio_bcm2711_pin_interrupt_configure, + .manage_callback = gpio_bcm2711_manage_callback, +}; + +#define GPIO_BCM2711_INST(n) \ + static struct gpio_bcm2711_data gpio_bcm2711_data_##n; \ + \ + static void gpio_bcm2711_irq_config_func_##n(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), gpio_bcm2711_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } \ + \ + static const struct gpio_bcm2711_config gpio_bcm2711_cfg_##n = { \ + .common = {.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(0)}, \ + DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_INST_PARENT(n)), \ + .irq_config_func = gpio_bcm2711_irq_config_func_##n, \ + .offset = DT_INST_REG_ADDR(n), \ + .ngpios = DT_INST_PROP(n, ngpios), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, gpio_bcm2711_init, NULL, &gpio_bcm2711_data_##n, \ + &gpio_bcm2711_cfg_##n, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \ + &gpio_bcm2711_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_BCM2711_INST) diff --git a/drivers/gpio/gpio_bd8lb600fs.c b/drivers/gpio/gpio_bd8lb600fs.c index 30ae851d90bee2d..ad49e4a7768e7ad 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_davinci.c b/drivers/gpio/gpio_davinci.c index 5726ed1bf32e83b..205e0112cde8f66 100644 --- a/drivers/gpio/gpio_davinci.c +++ b/drivers/gpio/gpio_davinci.c @@ -17,10 +17,14 @@ #include #include #include +#include +#include + +LOG_MODULE_REGISTER(gpio_davinci, CONFIG_GPIO_LOG_LEVEL); /* Helper Macros for GPIO */ #define DEV_CFG(dev) \ - ((const struct gpio_davinci_config * const)((dev)->config)) + ((const struct gpio_davinci_config *)((dev)->config)) #define DEV_DATA(dev) ((struct gpio_davinci_data *)(dev)->data) #define DEV_GPIO_CFG_BASE(dev) \ ((struct gpio_davinci_regs *)DEVICE_MMIO_NAMED_GET(dev, port_base)) @@ -55,6 +59,7 @@ struct gpio_davinci_config { DEVICE_MMIO_NAMED_ROM(port_base); uint32_t port_num; + const struct pinctrl_dev_config *pcfg; }; static int gpio_davinci_configure(const struct device *dev, gpio_pin_t pin, @@ -76,11 +81,9 @@ static int gpio_davinci_configure(const struct device *dev, gpio_pin_t pin, } else { regs->clr_data = BIT(pin); } - - regs->dir &= (~(BIT(pin))); - + regs->dir &= ~(BIT(pin)); } else { - regs->dir |= (BIT(pin)); + regs->dir |= BIT(pin); } return 0; @@ -149,6 +152,7 @@ static int gpio_davinci_init(const struct device *dev) { const struct gpio_davinci_config *config = DEV_CFG(dev); volatile struct gpio_davinci_regs *regs = DEV_GPIO_CFG_BASE(dev); + int ret; DEVICE_MMIO_NAMED_MAP(dev, port_base, K_MEM_CACHE_NONE); @@ -156,44 +160,43 @@ static int gpio_davinci_init(const struct device *dev) config->bank_config(dev); + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("failed to apply pinctrl"); + return ret; + } return 0; } -#define GPIO_DAVINCI_INIT_FUNC(n) \ - static void gpio_davinci_bank_##n##_config(const struct device *dev) \ - { \ +#define GPIO_DAVINCI_INIT_FUNC(n) \ + static void gpio_davinci_bank_##n##_config(const struct device *dev) \ + { \ volatile struct gpio_davinci_regs *regs = DEV_GPIO_CFG_BASE(dev); \ - ARG_UNUSED(regs); \ + ARG_UNUSED(regs); \ } -#define GPIO_DAVINCI_DEVICE_INIT(n) \ - DEVICE_DT_INST_DEFINE(n, &gpio_davinci_##n##_init, \ - NULL, &gpio_davinci_##n##_data, \ - &gpio_davinci_##n##_config, \ - POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY, \ - &api_funcs) - -#define GPIO_DAVINCI_INIT(n) \ - \ - GPIO_DAVINCI_INIT_FUNC(n) \ - static const struct gpio_davinci_config gpio_davinci_##n##_config = { \ - .bank_config = gpio_davinci_bank_##n##_config, \ - .common = { \ - .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ - }, \ - DEVICE_MMIO_NAMED_ROM_INIT(port_base, DT_DRV_INST(n)), \ - .port_num = n \ - }; \ - \ - static struct gpio_davinci_data gpio_davinci_##n##_data; \ - \ - DEVICE_DT_INST_DEFINE(n, \ - &gpio_davinci_init, \ - NULL, \ - &gpio_davinci_##n##_data, \ - &gpio_davinci_##n##_config, \ - PRE_KERNEL_2, \ - CONFIG_GPIO_INIT_PRIORITY, \ +#define GPIO_DAVINCI_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + GPIO_DAVINCI_INIT_FUNC(n); \ + static const struct gpio_davinci_config gpio_davinci_##n##_config = { \ + .bank_config = gpio_davinci_bank_##n##_config, \ + .common = { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + }, \ + DEVICE_MMIO_NAMED_ROM_INIT(port_base, DT_DRV_INST(n)), \ + .port_num = n, \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + }; \ + \ + static struct gpio_davinci_data gpio_davinci_##n##_data; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + &gpio_davinci_init, \ + NULL, \ + &gpio_davinci_##n##_data, \ + &gpio_davinci_##n##_config, \ + PRE_KERNEL_2, \ + CONFIG_GPIO_INIT_PRIORITY, \ &gpio_davinci_driver_api); DT_INST_FOREACH_STATUS_OKAY(GPIO_DAVINCI_INIT) diff --git a/drivers/gpio/gpio_efinix_sapphire.c b/drivers/gpio/gpio_efinix_sapphire.c index 9456406a63c32c7..50123731a5f2503 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_handlers.c b/drivers/gpio/gpio_handlers.c index ce64fc87bda99fa..99fbc6f45d91cfe 100644 --- a/drivers/gpio/gpio_handlers.c +++ b/drivers/gpio/gpio_handlers.c @@ -5,13 +5,13 @@ */ #include -#include +#include static inline int z_vrfy_gpio_pin_configure(const struct device *port, gpio_pin_t pin, gpio_flags_t flags) { - Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, pin_configure)); + K_OOPS(K_SYSCALL_DRIVER_GPIO(port, pin_configure)); return z_impl_gpio_pin_configure((const struct device *)port, pin, flags); @@ -23,8 +23,8 @@ static inline int z_vrfy_gpio_pin_get_config(const struct device *port, gpio_pin_t pin, gpio_flags_t *flags) { - Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, pin_get_config)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(flags, sizeof(gpio_flags_t))); + K_OOPS(K_SYSCALL_DRIVER_GPIO(port, pin_get_config)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(flags, sizeof(gpio_flags_t))); return z_impl_gpio_pin_get_config(port, pin, flags); } @@ -34,8 +34,8 @@ static inline int z_vrfy_gpio_pin_get_config(const struct device *port, static inline int z_vrfy_gpio_port_get_raw(const struct device *port, gpio_port_value_t *value) { - Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_get_raw)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(value, sizeof(gpio_port_value_t))); + K_OOPS(K_SYSCALL_DRIVER_GPIO(port, port_get_raw)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(value, sizeof(gpio_port_value_t))); return z_impl_gpio_port_get_raw((const struct device *)port, (gpio_port_value_t *)value); } @@ -45,7 +45,7 @@ static inline int z_vrfy_gpio_port_set_masked_raw(const struct device *port, gpio_port_pins_t mask, gpio_port_value_t value) { - Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_set_masked_raw)); + K_OOPS(K_SYSCALL_DRIVER_GPIO(port, port_set_masked_raw)); return z_impl_gpio_port_set_masked_raw((const struct device *)port, mask, value); @@ -55,7 +55,7 @@ static inline int z_vrfy_gpio_port_set_masked_raw(const struct device *port, static inline int z_vrfy_gpio_port_set_bits_raw(const struct device *port, gpio_port_pins_t pins) { - Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_set_bits_raw)); + K_OOPS(K_SYSCALL_DRIVER_GPIO(port, port_set_bits_raw)); return z_impl_gpio_port_set_bits_raw((const struct device *)port, pins); } @@ -64,7 +64,7 @@ static inline int z_vrfy_gpio_port_set_bits_raw(const struct device *port, static inline int z_vrfy_gpio_port_clear_bits_raw(const struct device *port, gpio_port_pins_t pins) { - Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_clear_bits_raw)); + K_OOPS(K_SYSCALL_DRIVER_GPIO(port, port_clear_bits_raw)); return z_impl_gpio_port_clear_bits_raw((const struct device *)port, pins); } @@ -73,7 +73,7 @@ static inline int z_vrfy_gpio_port_clear_bits_raw(const struct device *port, static inline int z_vrfy_gpio_port_toggle_bits(const struct device *port, gpio_port_pins_t pins) { - Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_toggle_bits)); + K_OOPS(K_SYSCALL_DRIVER_GPIO(port, port_toggle_bits)); return z_impl_gpio_port_toggle_bits((const struct device *)port, pins); } #include @@ -82,7 +82,7 @@ static inline int z_vrfy_gpio_pin_interrupt_configure(const struct device *port, gpio_pin_t pin, gpio_flags_t flags) { - Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, pin_interrupt_configure)); + K_OOPS(K_SYSCALL_DRIVER_GPIO(port, pin_interrupt_configure)); return z_impl_gpio_pin_interrupt_configure((const struct device *)port, pin, flags); @@ -91,7 +91,7 @@ static inline int z_vrfy_gpio_pin_interrupt_configure(const struct device *port, static inline int z_vrfy_gpio_get_pending_int(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_GPIO(dev, get_pending_int)); + K_OOPS(K_SYSCALL_DRIVER_GPIO(dev, get_pending_int)); return z_impl_gpio_get_pending_int((const struct device *)dev); } @@ -102,14 +102,14 @@ static inline int z_vrfy_gpio_port_get_direction(const struct device *dev, gpio_ gpio_port_pins_t *inputs, gpio_port_pins_t *outputs) { - Z_OOPS(Z_SYSCALL_DRIVER_GPIO(dev, port_get_direction)); + K_OOPS(K_SYSCALL_DRIVER_GPIO(dev, port_get_direction)); if (inputs != NULL) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(inputs, sizeof(gpio_port_pins_t))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(inputs, sizeof(gpio_port_pins_t))); } if (outputs != NULL) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(outputs, sizeof(gpio_port_pins_t))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(outputs, sizeof(gpio_port_pins_t))); } return z_impl_gpio_port_get_direction(dev, map, inputs, outputs); diff --git a/drivers/gpio/gpio_ite_it8xxx2.c b/drivers/gpio/gpio_ite_it8xxx2.c index 754a3b773f1d444..1171c5b33918fc7 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 23fd217817969a1..16f505587f9c2d4 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 b5b3a7033d5288f..7db42b7791385f2 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_mchp_xec.c b/drivers/gpio/gpio_mchp_xec.c index f01aefd6d2d1027..86d9f2a5d7a55e4 100644 --- a/drivers/gpio/gpio_mchp_xec.c +++ b/drivers/gpio/gpio_mchp_xec.c @@ -66,7 +66,6 @@ static int gpio_xec_configure(const struct device *dev, __IO uint32_t *current_pcr1; uint32_t pcr1 = 0U; uint32_t mask = 0U; - __IO uint32_t *gpio_out_reg = GPIO_OUT_BASE(config); /* Validate pin number range in terms of current port */ if ((valid_ctrl_masks[config->port_num] & BIT(pin)) == 0U) { @@ -88,7 +87,22 @@ static int gpio_xec_configure(const struct device *dev, mask |= MCHP_GPIO_CTRL_DIR_MASK; mask |= MCHP_GPIO_CTRL_INPAD_DIS_MASK; mask |= MCHP_GPIO_CTRL_PWRG_MASK; - pcr1 |= MCHP_GPIO_CTRL_DIR_INPUT; + mask |= MCHP_GPIO_CTRL_AOD_MASK; + + current_pcr1 = config->pcr1_base + pin; + + if (flags == GPIO_DISCONNECTED) { + pcr1 |= MCHP_GPIO_CTRL_PWRG_OFF; + *current_pcr1 = (*current_pcr1 & ~mask) | pcr1; + return 0; + } + + pcr1 = MCHP_GPIO_CTRL_PWRG_VTR_IO; + + /* Always enable input pad */ + if (*current_pcr1 & BIT(MCHP_GPIO_CTRL_INPAD_DIS_POS)) { + *current_pcr1 &= ~BIT(MCHP_GPIO_CTRL_INPAD_DIS_POS); + } /* Figure out the pullup/pulldown configuration and keep it in the * pcr1 variable @@ -114,38 +128,33 @@ static int gpio_xec_configure(const struct device *dev, pcr1 |= MCHP_GPIO_CTRL_BUFT_PUSHPULL; } - /* Use GPIO output register to control pin output, instead of - * using the control register (=> alternate output disable). - */ - mask |= MCHP_GPIO_CTRL_AOD_MASK; - pcr1 |= MCHP_GPIO_CTRL_AOD_DIS; - - /* Make sure disconnected on first control register write */ - if (flags == GPIO_DISCONNECTED) { - pcr1 |= MCHP_GPIO_CTRL_PWRG_OFF; - } - - /* Now write contents of pcr1 variable to the PCR1 register that - * corresponds to the GPIO being configured. - * AOD is 1 and direction is input. HW will allow use to set the - * GPIO parallel output bit for this pin and with the pin direction - * as input no glitch will occur. - */ - current_pcr1 = config->pcr1_base + pin; - *current_pcr1 = (*current_pcr1 & ~mask) | pcr1; - if ((flags & GPIO_OUTPUT) != 0U) { + mask |= MCHP_GPIO_CTRL_OUTV_HI; if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) { - *gpio_out_reg |= BIT(pin); + pcr1 |= BIT(MCHP_GPIO_CTRL_OUTVAL_POS); } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) { - *gpio_out_reg &= ~BIT(pin); + pcr1 &= ~BIT(MCHP_GPIO_CTRL_OUTVAL_POS); + } else { /* Copy current input state to output state */ + if ((*current_pcr1 & MCHP_GPIO_CTRL_PWRG_MASK) == + MCHP_GPIO_CTRL_PWRG_OFF) { + *current_pcr1 = (*current_pcr1 & + ~MCHP_GPIO_CTRL_PWRG_MASK) | + MCHP_GPIO_CTRL_PWRG_VTR_IO; + } + if (*current_pcr1 & BIT(MCHP_GPIO_CTRL_INPAD_VAL_POS)) { + pcr1 |= BIT(MCHP_GPIO_CTRL_OUTVAL_POS); + } else { + pcr1 &= ~BIT(MCHP_GPIO_CTRL_OUTVAL_POS); + } } - mask = MCHP_GPIO_CTRL_DIR_MASK; - pcr1 = MCHP_GPIO_CTRL_DIR_OUTPUT; - *current_pcr1 = (*current_pcr1 & ~mask) | pcr1; + pcr1 |= MCHP_GPIO_CTRL_DIR_OUTPUT; } + *current_pcr1 = (*current_pcr1 & ~mask) | pcr1; + /* Control output bit becomes ready only and parallel output r/w */ + *current_pcr1 = *current_pcr1 | BIT(MCHP_GPIO_CTRL_AOD_POS); + return 0; } diff --git a/drivers/gpio/gpio_mcp23xxx.c b/drivers/gpio/gpio_mcp23xxx.c index c9bf2f6aa690b83..c9cb32866b705b9 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 ae0ef1bf7963aa7..673ad496a1414a5 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 { @@ -119,6 +118,12 @@ static int gpio_mcux_lpc_configure(const struct device *dev, gpio_pin_t pin, } else if ((flags & GPIO_PULL_DOWN) != 0) { *pinconfig |= IOCON_PIO_MODE_PULLDOWN; } +#endif + } else { +#ifdef IOPCTL /* RT600 and RT500 series */ + *pinconfig &= ~IOPCTL_PIO_PUPD_EN; +#else /* LPC SOCs */ + *pinconfig &= ~(IOCON_PIO_MODE_PULLUP|IOCON_PIO_MODE_PULLDOWN); #endif } @@ -375,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; @@ -392,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 @@ -423,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 000000000000000..16ad02c6ae826da --- /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 0aa282dda37dc31..d89c964cc90a8fb 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 7b5db11826e310d..81898e83382b408 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 80a0d8b7d068c04..000000000000000 --- 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 000000000000000..c30e1a5d36d02b0 --- /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 820db5fc76cfc8c..f60112427bc80a4 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_renesas_ra.c b/drivers/gpio/gpio_renesas_ra.c new file mode 100644 index 000000000000000..9f4fe59c83b1f16 --- /dev/null +++ b/drivers/gpio/gpio_renesas_ra.c @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_ra_gpio + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + PCNTR1_OFFSET = 0x0, + PCNTR2_OFFSET = 0x4, + PCNTR3_OFFSET = 0x8, + PCNTR4_OFFSET = 0xc +}; + +enum { + PCNTR1_PDR0_OFFSET = 0, + PCNTR1_PODR0_OFFSET = 16, +}; + +enum { + PCNTR2_PIDR0_OFFSET = 0, + PCNTR2_EIDR0_OFFSET = 16, +}; + +enum { + PCNTR3_POSR0_OFFSET = 0, + PCNTR3_PORR0_OFFSET = 16, +}; + +enum { + PCNTR4_EOSR0_OFFSET = 0, + PCNTR4_EORR0_OFFSET = 16, +}; + +struct gpio_ra_irq_info { + const uint8_t *const pins; + size_t num; + int port_irq; + int irq; + uint32_t priority; + uint32_t flags; + ra_isr_handler isr; +}; + +struct gpio_ra_pin_irq_info { + const struct gpio_ra_irq_info *info; + uint8_t pin; +}; + +struct gpio_ra_config { + struct gpio_driver_config common; + mem_addr_t regs; + struct gpio_ra_irq_info *irq_info; + uint32_t irq_info_size; + uint16_t port; +}; + +struct gpio_ra_data { + struct gpio_driver_data common; + struct gpio_ra_pin_irq_info port_irq_info[16]; + sys_slist_t callbacks; +}; + +static inline uint32_t gpio_ra_irq_info_event(const struct gpio_ra_irq_info *info) +{ + return ((info->flags & RA_ICU_FLAG_EVENT_MASK) >> RA_ICU_FLAG_EVENT_OFFSET); +} + +static void gpio_ra_isr(const struct device *dev, uint32_t port_irq) +{ + struct gpio_ra_data *data = dev->data; + const struct gpio_ra_pin_irq_info *pin_irq = &data->port_irq_info[port_irq]; + const int irq = ra_icu_query_exists_irq(gpio_ra_irq_info_event(pin_irq->info)); + + if (irq >= 0) { + gpio_fire_callbacks(&data->callbacks, dev, BIT(pin_irq->pin)); + ra_icu_clear_int_flag(irq); + } +} + +static const struct gpio_ra_irq_info *query_irq_info(const struct device *dev, uint32_t pin) +{ + const struct gpio_ra_config *config = dev->config; + + for (int i = 0; i < config->irq_info_size; i++) { + const struct gpio_ra_irq_info *info = &config->irq_info[i]; + + for (int j = 0; j < info->num; j++) { + if (info->pins[j] == pin) { + return info; + } + } + } + + return NULL; +} + +static inline uint32_t reg_read(const struct device *dev, size_t offset) +{ + const struct gpio_ra_config *config = dev->config; + + return sys_read32(config->regs + offset); +} + +static inline void reg_write(const struct device *dev, size_t offset, uint32_t value) +{ + const struct gpio_ra_config *config = dev->config; + + sys_write32(value, config->regs + offset); +} + +static inline uint32_t port_read(const struct device *dev) +{ + return reg_read(dev, PCNTR2_OFFSET) & UINT16_MAX; +} + +static int port_write(const struct device *dev, uint16_t value, uint16_t mask) +{ + const uint16_t set = value & mask; + const uint16_t clr = (~value) & mask; + + reg_write(dev, PCNTR3_OFFSET, (clr << PCNTR3_PORR0_OFFSET) | set << PCNTR3_POSR0_OFFSET); + + return 0; +} + +static int gpio_ra_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + const enum gpio_int_mode mode = + flags & (GPIO_INT_EDGE | GPIO_INT_DISABLE | GPIO_INT_ENABLE); + const enum gpio_int_trig trig = flags & (GPIO_INT_LOW_0 | GPIO_INT_HIGH_1); + const struct gpio_ra_config *config = dev->config; + struct gpio_ra_data *data = dev->data; + struct pinctrl_ra_pin pincfg = {0}; + + if ((flags & GPIO_OUTPUT) && (flags & GPIO_INPUT)) { + /* Pin cannot be configured as input and output */ + return -ENOTSUP; + } else if (!(flags & (GPIO_INPUT | GPIO_OUTPUT))) { + /* Pin has to be configured as input or output */ + return -ENOTSUP; + } + + if (flags & GPIO_OUTPUT) { + pincfg.config |= BIT(PmnPFS_PDR_POS); + } + + if (flags & GPIO_PULL_UP) { + pincfg.config |= BIT(PmnPFS_PCR_POS); + } + + if ((flags & GPIO_SINGLE_ENDED) && (flags & GPIO_LINE_OPEN_DRAIN)) { + pincfg.config |= BIT(PmnPFS_NCODR_POS); + } + + if (flags & GPIO_INT_ENABLE) { + pincfg.config |= BIT(PmnPFS_ISEL_POS); + } + + pincfg.config &= ~BIT(PmnPFS_PMR_POS); + + pincfg.pin = pin; + pincfg.port = config->port; + + if (flags & GPIO_INT_ENABLE) { + const struct gpio_ra_irq_info *irq_info; + uint32_t intcfg; + int irqn; + + if (mode == GPIO_INT_MODE_LEVEL) { + if (trig != GPIO_INT_TRIG_LOW) { + return -ENOTSUP; + } + + intcfg = ICU_LOW_LEVEL; + } else if (mode == GPIO_INT_MODE_EDGE) { + switch (trig) { + case GPIO_INT_TRIG_LOW: + intcfg = ICU_FALLING; + break; + case GPIO_INT_TRIG_HIGH: + intcfg = ICU_RISING; + break; + case GPIO_INT_TRIG_BOTH: + intcfg = ICU_BOTH_EDGE; + break; + default: + return -ENOTSUP; + } + } else { + return -ENOTSUP; + } + + irq_info = query_irq_info(dev, pin); + if (irq_info == NULL) { + return -EINVAL; + } + + irqn = ra_icu_irq_connect_dynamic( + irq_info->irq, irq_info->priority, irq_info->isr, dev, + (intcfg << RA_ICU_FLAG_INTCFG_OFFSET) | irq_info->flags); + if (irqn < 0) { + return irqn; + } + + data->port_irq_info[irq_info->port_irq].pin = pin; + data->port_irq_info[irq_info->port_irq].info = irq_info; + + irq_enable(irqn); + } + + return pinctrl_configure_pins(&pincfg, 1, PINCTRL_REG_NONE); +} + +#ifdef CONFIG_GPIO_GET_CONFIG +static int gpio_ra_pin_get_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t *flags) +{ + const struct gpio_ra_config *config = dev->config; + const struct gpio_ra_irq_info *irq_info; + struct pinctrl_ra_pin pincfg; + ra_isr_handler cb; + const void *cbarg; + uint32_t intcfg; + int irqn; + int err; + + memset(flags, 0, sizeof(gpio_flags_t)); + + err = pinctrl_ra_query_config(config->port, pin, &pincfg); + if (err < 0) { + return err; + } + + if (pincfg.config & BIT(PmnPFS_PDR_POS)) { + *flags |= GPIO_OUTPUT; + } else { + *flags |= GPIO_INPUT; + } + + if (pincfg.config & BIT(PmnPFS_ISEL_POS)) { + *flags |= GPIO_INT_ENABLE; + } + + if (pincfg.config & BIT(PmnPFS_PCR_POS)) { + *flags |= GPIO_PULL_UP; + } + + irq_info = query_irq_info(dev, pin); + if (irq_info == NULL) { + return 0; + } + + irqn = ra_icu_query_exists_irq(gpio_ra_irq_info_event(irq_info)); + if (irqn < 0) { + return 0; + } + + ra_icu_query_irq_config(irqn, &intcfg, &cb, &cbarg); + + if (cbarg != dev) { + return 0; + } + + if (intcfg == ICU_FALLING) { + *flags |= GPIO_INT_TRIG_LOW; + *flags |= GPIO_INT_MODE_EDGE; + } else if (intcfg == ICU_RISING) { + *flags |= GPIO_INT_TRIG_HIGH; + *flags |= GPIO_INT_MODE_EDGE; + } else if (intcfg == ICU_BOTH_EDGE) { + *flags |= GPIO_INT_TRIG_BOTH; + *flags |= GPIO_INT_MODE_EDGE; + } else if (intcfg == ICU_LOW_LEVEL) { + *flags |= GPIO_INT_TRIG_LOW; + *flags |= GPIO_INT_MODE_LEVEL; + } + + return 0; +} +#endif + +static int gpio_ra_port_get_raw(const struct device *dev, gpio_port_value_t *value) +{ + *value = port_read(dev); + + return 0; +} + +static int gpio_ra_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + uint16_t port_val; + + port_val = port_read(dev); + port_val = (port_val & ~mask) | (value & mask); + return port_write(dev, port_val, UINT16_MAX); +} + +static int gpio_ra_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + uint16_t port_val; + + port_val = port_read(dev); + port_val |= pins; + return port_write(dev, port_val, UINT16_MAX); +} + +static int gpio_ra_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + uint16_t port_val; + + port_val = port_read(dev); + port_val &= ~pins; + return port_write(dev, port_val, UINT16_MAX); +} + +static int gpio_ra_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) +{ + uint16_t port_val; + + port_val = port_read(dev); + port_val ^= pins; + return port_write(dev, port_val, UINT16_MAX); +} + +static int gpio_ra_manage_callback(const struct device *dev, struct gpio_callback *callback, + bool set) +{ + struct gpio_ra_data *data = dev->data; + + return gpio_manage_callback(&data->callbacks, callback, set); +} + +static int gpio_ra_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + gpio_flags_t pincfg; + int err; + + err = gpio_ra_pin_get_config(dev, pin, &pincfg); + if (err < 0) { + return err; + } + + return gpio_ra_pin_configure(dev, pin, pincfg | mode | trig); +} + +static const struct gpio_driver_api gpio_ra_driver_api = { + .pin_configure = gpio_ra_pin_configure, +#ifdef CONFIG_GPIO_GET_CONFIG + .pin_get_config = gpio_ra_pin_get_config, +#endif + .port_get_raw = gpio_ra_port_get_raw, + .port_set_masked_raw = gpio_ra_port_set_masked_raw, + .port_set_bits_raw = gpio_ra_port_set_bits_raw, + .port_clear_bits_raw = gpio_ra_port_clear_bits_raw, + .port_toggle_bits = gpio_ra_port_toggle_bits, + .pin_interrupt_configure = gpio_ra_pin_interrupt_configure, + .manage_callback = gpio_ra_manage_callback, +}; + +#define RA_NUM_PORT_IRQ0 0 +#define RA_NUM_PORT_IRQ1 1 +#define RA_NUM_PORT_IRQ2 2 +#define RA_NUM_PORT_IRQ3 3 +#define RA_NUM_PORT_IRQ4 4 +#define RA_NUM_PORT_IRQ5 5 +#define RA_NUM_PORT_IRQ6 6 +#define RA_NUM_PORT_IRQ7 7 +#define RA_NUM_PORT_IRQ8 8 +#define RA_NUM_PORT_IRQ9 9 +#define RA_NUM_PORT_IRQ10 10 +#define RA_NUM_PORT_IRQ11 11 +#define RA_NUM_PORT_IRQ12 12 +#define RA_NUM_PORT_IRQ13 13 +#define RA_NUM_PORT_IRQ14 14 +#define RA_NUM_PORT_IRQ15 15 + +#define GPIO_RA_DECL_PINS(n, p, i) \ + const uint8_t _CONCAT(n, ___pins##i[]) = {DT_FOREACH_PROP_ELEM_SEP( \ + n, _CONCAT(DT_STRING_TOKEN_BY_IDX(n, p, i), _pins), DT_PROP_BY_IDX, (,))}; + +#define GPIO_RA_IRQ_INFO(n, p, i) \ + { \ + .port_irq = _CONCAT(RA_NUM_, DT_STRING_UPPER_TOKEN_BY_IDX(n, p, i)), \ + .irq = DT_IRQ_BY_IDX(n, i, irq), \ + .flags = DT_IRQ_BY_IDX(n, i, flags), \ + .priority = DT_IRQ_BY_IDX(n, i, priority), \ + .pins = _CONCAT(n, ___pins##i), \ + .num = ARRAY_SIZE(_CONCAT(n, ___pins##i)), \ + .isr = _CONCAT(n, _CONCAT(gpio_ra_isr_, DT_STRING_TOKEN_BY_IDX(n, p, i))), \ + }, + +#define GPIO_RA_ISR_DECL(n, p, i) \ + static void _CONCAT(n, _CONCAT(gpio_ra_isr_, DT_STRING_TOKEN_BY_IDX(n, p, i)))( \ + const void *arg) \ + { \ + gpio_ra_isr((const struct device *)arg, \ + _CONCAT(RA_NUM_, DT_STRING_UPPER_TOKEN_BY_IDX(n, p, i))); \ + } + +#define GPIO_RA_INIT(idx) \ + static struct gpio_ra_data gpio_ra_data_##idx = {}; \ + DT_INST_FOREACH_PROP_ELEM(idx, interrupt_names, GPIO_RA_DECL_PINS); \ + DT_INST_FOREACH_PROP_ELEM(idx, interrupt_names, GPIO_RA_ISR_DECL); \ + struct gpio_ra_irq_info gpio_ra_irq_info_##idx[] = { \ + DT_INST_FOREACH_PROP_ELEM(idx, interrupt_names, GPIO_RA_IRQ_INFO)}; \ + static struct gpio_ra_config gpio_ra_config_##idx = { \ + .common = { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(idx), \ + }, \ + .regs = DT_INST_REG_ADDR(idx), \ + .port = (DT_INST_REG_ADDR(idx) - DT_REG_ADDR(DT_NODELABEL(ioport0))) / \ + DT_INST_REG_SIZE(idx), \ + .irq_info = gpio_ra_irq_info_##idx, \ + .irq_info_size = ARRAY_SIZE(gpio_ra_irq_info_##idx), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(idx, NULL, NULL, &gpio_ra_data_##idx, &gpio_ra_config_##idx, \ + PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, &gpio_ra_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_RA_INIT) diff --git a/drivers/gpio/gpio_rzt2m.c b/drivers/gpio/gpio_rzt2m.c new file mode 100644 index 000000000000000..c2bfd1a4acd8b2c --- /dev/null +++ b/drivers/gpio/gpio_rzt2m.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_rzt2m_gpio + +#include +#include +#include +#include +#include +#include +#include + +#define PMm_OFFSET 0x200 +#define PINm_OFFSET 0x800 +#define DRCTLm_OFFSET 0xa00 + +#define DRIVE_SHIFT 0 +#define SCHMITT_TRIGGER_SHIFT 4 +#define SLEW_RATE_SHIFT 5 + +#define PULL_SHIFT 2 +#define PULL_NONE (0 << PULL_SHIFT) +#define PULL_UP (1 << PULL_SHIFT) +#define PULL_DOWN (2 << PULL_SHIFT) + +struct rzt2m_gpio_config { + struct gpio_driver_config common; + uint8_t *port_nsr; + uint8_t *ptadr; + uint8_t port; +}; + +struct rzt2m_gpio_data { + struct gpio_driver_data common; +}; + +static void rzt2m_gpio_unlock(void) +{ + rzt2m_unlock_prcrn(PRCRN_PRC1); + rzt2m_unlock_prcrs(PRCRS_GPIO); +} + +static void rzt2m_gpio_lock(void) +{ + rzt2m_lock_prcrn(PRCRN_PRC1); + rzt2m_lock_prcrs(PRCRS_GPIO); +} + +/* Port m output data store */ +static volatile uint8_t *rzt2m_gpio_get_p_reg(const struct device *dev) +{ + const struct rzt2m_gpio_config *config = dev->config; + + return (volatile uint8_t *)(config->port_nsr + config->port); +} + +/* Port m input data store */ +static volatile uint8_t *rzt2m_gpio_get_pin_reg(const struct device *dev) +{ + const struct rzt2m_gpio_config *config = dev->config; + + return (volatile uint8_t *)(config->port_nsr + PINm_OFFSET + config->port); +} + +/* Port m mode register */ +static volatile uint16_t *rzt2m_gpio_get_pm_reg(const struct device *dev) +{ + const struct rzt2m_gpio_config *config = dev->config; + + return (volatile uint16_t *)(config->port_nsr + PMm_OFFSET + 0x2 * config->port); +} + +/* IO Buffer m function switching register */ +static volatile uint64_t *rzt2m_gpio_get_drctl_reg(const struct device *dev) +{ + const struct rzt2m_gpio_config *config = dev->config; + + return (volatile uint64_t *)(config->port_nsr + DRCTLm_OFFSET + 0x8 * config->port); +} + +/* Port m region select register */ +static volatile uint8_t *rzt2m_gpio_get_rselp_reg(const struct device *dev) +{ + const struct rzt2m_gpio_config *config = dev->config; + + return (volatile uint8_t *)(config->ptadr + config->port); +} + +static int rzt2m_gpio_init(const struct device *dev) +{ + rzt2m_gpio_unlock(); + + volatile uint8_t *rselp_reg = rzt2m_gpio_get_rselp_reg(dev); + *rselp_reg = 0xFF; + + rzt2m_gpio_lock(); + + return 0; +} + +static int rzt2m_gpio_get_raw(const struct device *dev, gpio_port_value_t *value) +{ + rzt2m_gpio_unlock(); + + volatile uint8_t *pin_reg = rzt2m_gpio_get_pin_reg(dev); + *value = *pin_reg; + + rzt2m_gpio_lock(); + + return 0; +} + +static int rzt2m_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + rzt2m_gpio_unlock(); + + volatile uint8_t *p_reg = rzt2m_gpio_get_p_reg(dev); + *p_reg = (*p_reg & ~mask) | (value & mask); + + rzt2m_gpio_lock(); + + return 0; +} + +static int rzt2m_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + rzt2m_gpio_unlock(); + + volatile uint8_t *p_reg = rzt2m_gpio_get_p_reg(dev); + *p_reg |= pins; + + rzt2m_gpio_lock(); + + return 0; +} + +static int rzt2m_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + rzt2m_gpio_unlock(); + + volatile uint8_t *p_reg = rzt2m_gpio_get_p_reg(dev); + *p_reg &= ~pins; + + rzt2m_gpio_lock(); + + return 0; +} + +static int rzt2m_gpio_toggle(const struct device *dev, gpio_port_pins_t pins) +{ + rzt2m_gpio_unlock(); + + volatile uint8_t *p_reg = rzt2m_gpio_get_p_reg(dev); + *p_reg ^= pins; + + rzt2m_gpio_lock(); + + return 0; +} + +static int rzt2m_gpio_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + volatile uint16_t *pm_reg = rzt2m_gpio_get_pm_reg(dev); + volatile uint64_t *drctl_reg = rzt2m_gpio_get_drctl_reg(dev); + + rzt2m_gpio_unlock(); + + WRITE_BIT(*pm_reg, pin * 2, flags & GPIO_INPUT); + WRITE_BIT(*pm_reg, pin * 2 + 1, flags & GPIO_OUTPUT); + + if (flags & GPIO_OUTPUT) { + if (flags & GPIO_OUTPUT_INIT_LOW) { + rzt2m_port_clear_bits_raw(dev, 1 << pin); + } else if (flags & GPIO_OUTPUT_INIT_HIGH) { + rzt2m_port_set_bits_raw(dev, 1 << pin); + } + } + + if (flags & GPIO_PULL_UP && flags & GPIO_PULL_DOWN) { + rzt2m_gpio_lock(); + return -EINVAL; + } + + uint8_t drctl_pin_config = 0; + + if (flags & GPIO_PULL_UP) { + drctl_pin_config |= PULL_UP; + } else if (flags & GPIO_PULL_DOWN) { + drctl_pin_config |= PULL_DOWN; + } else { + drctl_pin_config |= PULL_NONE; + } + + drctl_pin_config |= + (flags & RZT2M_GPIO_DRIVE_MASK) >> (RZT2M_GPIO_DRIVE_OFFSET - DRIVE_SHIFT); + drctl_pin_config |= (flags & RZT2M_GPIO_SCHMITT_TRIGGER_MASK) >> + (RZT2M_GPIO_SCHMITT_TRIGGER_OFFSET - SCHMITT_TRIGGER_SHIFT); + drctl_pin_config |= (flags & RZT2M_GPIO_SLEW_RATE_MASK) >> + (RZT2M_GPIO_SLEW_RATE_OFFSET - SLEW_RATE_SHIFT); + + uint64_t drctl_pin_value = *drctl_reg & ~(0xFFULL << (pin * 8)); + *drctl_reg = drctl_pin_value | ((uint64_t)drctl_pin_config << (pin * 8)); + + rzt2m_gpio_lock(); + + return 0; +} + +static const struct gpio_driver_api rzt2m_gpio_driver_api = { + .pin_configure = rzt2m_gpio_configure, + .port_get_raw = rzt2m_gpio_get_raw, + .port_set_masked_raw = rzt2m_port_set_masked_raw, + .port_set_bits_raw = rzt2m_port_set_bits_raw, + .port_clear_bits_raw = rzt2m_port_clear_bits_raw, + .port_toggle_bits = rzt2m_gpio_toggle}; + +#define RZT2M_GPIO_DEFINE(inst) \ + static struct rzt2m_gpio_data rzt2m_gpio_data##inst; \ + static struct rzt2m_gpio_config rzt2m_gpio_config##inst = { \ + .port_nsr = (uint8_t *)DT_REG_ADDR_BY_NAME(DT_INST_PARENT(inst), port_nsr), \ + .ptadr = (uint8_t *)DT_REG_ADDR_BY_NAME(DT_INST_PARENT(inst), ptadr), \ + .port = DT_INST_REG_ADDR(inst), \ + .common = {.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(inst)}}; \ + DEVICE_DT_INST_DEFINE(inst, rzt2m_gpio_init, NULL, &rzt2m_gpio_data##inst, \ + &rzt2m_gpio_config##inst, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \ + &rzt2m_gpio_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(RZT2M_GPIO_DEFINE) diff --git a/drivers/gpio/gpio_shell.c b/drivers/gpio/gpio_shell.c index b444288953b0df5..48d7e95f7a75254 100644 --- a/drivers/gpio/gpio_shell.c +++ b/drivers/gpio/gpio_shell.c @@ -1,187 +1,607 @@ /* * Copyright (c) 2018 Intel Corporation * Copyright (c) 2021 Dennis Ruffer + * Copyright (c) 2023 Nick Ward * * SPDX-License-Identifier: Apache-2.0 - * - * Use "device list" command for GPIO port names */ -#include +#include #include -#include -#include + #include -#include -#include -#include -#include -#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL +#define ARGV_DEV 1 +#define ARGV_PIN 2 +#define ARGV_CONF 3 +#define ARGV_VALUE 3 +#define ARGV_VENDOR_SPECIFIC 4 -LOG_MODULE_REGISTER(gpio_shell); +#define NGPIOS_UNKNOWN -1 +#define PIN_NOT_FOUND UINT8_MAX -struct args_index { - uint8_t port; - uint8_t index; - uint8_t mode; - uint8_t value; -}; +/* Pin syntax maximum length */ +#define PIN_SYNTAX_MAX 32 +#define PIN_NUM_MAX 4 -static const struct args_index args_indx = { - .port = 1, - .index = 2, - .mode = 3, - .value = 3, +struct gpio_ctrl { + const struct device *dev; + int8_t ngpios; + gpio_port_pins_t reserved_mask; + const char **line_names; + uint8_t line_names_len; + const union shell_cmd_entry *subcmd; }; -static int cmd_gpio_conf(const struct shell *sh, size_t argc, char **argv) -{ - uint8_t index = 0U; - int type = GPIO_OUTPUT; +struct sh_gpio { const struct device *dev; + gpio_pin_t pin; +}; +/* + * Find idx-th pin reference from the set of non reserved + * pin numbers and provided line names. + */ +static void port_pin_get(gpio_port_pins_t reserved_mask, const char **line_names, + uint8_t line_names_len, size_t idx, struct shell_static_entry *entry) +{ + static char pin_syntax[PIN_SYNTAX_MAX]; + static char pin_num[PIN_NUM_MAX]; + const char *name; + gpio_pin_t pin; + bool reserved; + + entry->handler = NULL; + + /* Find allowed numeric pin reference */ + for (pin = 0; pin < GPIO_MAX_PINS_PER_PORT; pin++) { + reserved = ((BIT64(pin) & reserved_mask) != 0); + if (!reserved) { + if (idx == 0) { + break; + } + idx--; + } + } - if (isdigit((unsigned char)argv[args_indx.index][0]) != 0 && - isalpha((unsigned char)argv[args_indx.mode][0]) != 0) { - index = (uint8_t)atoi(argv[args_indx.index]); - if (!strcmp(argv[args_indx.mode], "in")) { - type = GPIO_INPUT; - } else if (!strcmp(argv[args_indx.mode], "inu")) { - type = GPIO_INPUT | GPIO_PULL_UP; - } else if (!strcmp(argv[args_indx.mode], "ind")) { - type = GPIO_INPUT | GPIO_PULL_DOWN; - } else if (!strcmp(argv[args_indx.mode], "out")) { - type = GPIO_OUTPUT; + if (pin < GPIO_MAX_PINS_PER_PORT) { + sprintf(pin_num, "%u", pin); + if ((pin < line_names_len) && (strlen(line_names[pin]) > 0)) { + /* pin can be specified by line name */ + name = line_names[pin]; + for (int i = 0; i < (sizeof(pin_syntax) - 1); i++) { + /* + * For line-name tab completion to work replace any + * space characters with '_'. + */ + pin_syntax[i] = (name[i] != ' ') ? name[i] : '_'; + if (name[i] == '\0') { + break; + } + } + pin_syntax[sizeof(pin_syntax) - 1] = '\0'; + entry->syntax = pin_syntax; + entry->help = pin_num; } else { - return 0; + /* fallback to pin specified by pin number */ + entry->syntax = pin_num; + entry->help = NULL; } } else { - shell_error(sh, "Wrong parameters for conf"); - return -ENOTSUP; + /* No more pins */ + entry->syntax = NULL; + entry->help = NULL; } +} - dev = device_get_binding(argv[args_indx.port]); +#define GPIO_DT_RESERVED_RANGES_NGPIOS_SHELL(node_id) \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, ngpios), \ + (GPIO_DT_RESERVED_RANGES_NGPIOS(node_id, DT_PROP(node_id, ngpios))), \ + (GPIO_MAX_PINS_PER_PORT)) - if (dev != NULL) { - index = (uint8_t)atoi(argv[args_indx.index]); - shell_print(sh, "Configuring %s pin %d", - argv[args_indx.port], index); - gpio_pin_configure(dev, index, type); +#define GPIO_CTRL_PIN_GET_FN(node_id) \ + static const char *node_id##line_names[] = DT_PROP_OR(node_id, gpio_line_names, {NULL}); \ + \ + static void node_id##cmd_gpio_pin_get(size_t idx, struct shell_static_entry *entry); \ + \ + SHELL_DYNAMIC_CMD_CREATE(node_id##sub_gpio_pin, node_id##cmd_gpio_pin_get); \ + \ + static void node_id##cmd_gpio_pin_get(size_t idx, struct shell_static_entry *entry) \ + { \ + gpio_port_pins_t reserved_mask = GPIO_DT_RESERVED_RANGES_NGPIOS_SHELL(node_id); \ + uint8_t line_names_len = DT_PROP_LEN_OR(node_id, gpio_line_names, 0); \ + \ + port_pin_get(reserved_mask, node_id##line_names, line_names_len, idx, entry); \ + entry->subcmd = NULL; \ } - return 0; +#define IS_GPIO_CTRL_PIN_GET(node_id) \ + COND_CODE_1(DT_PROP(node_id, gpio_controller), (GPIO_CTRL_PIN_GET_FN(node_id)), ()) + +DT_FOREACH_STATUS_OKAY_NODE(IS_GPIO_CTRL_PIN_GET) + +#define GPIO_CTRL_LIST_ENTRY(node_id) \ + { \ + .dev = DEVICE_DT_GET(node_id), \ + .ngpios = DT_PROP_OR(node_id, ngpios, NGPIOS_UNKNOWN), \ + .reserved_mask = GPIO_DT_RESERVED_RANGES_NGPIOS_SHELL(node_id), \ + .line_names = node_id##line_names, \ + .line_names_len = DT_PROP_LEN_OR(node_id, gpio_line_names, 0), \ + .subcmd = &node_id##sub_gpio_pin, \ + }, + +#define IS_GPIO_CTRL_LIST(node_id) \ + COND_CODE_1(DT_PROP(node_id, gpio_controller), (GPIO_CTRL_LIST_ENTRY(node_id)), ()) + +static const struct gpio_ctrl gpio_list[] = {DT_FOREACH_STATUS_OKAY_NODE(IS_GPIO_CTRL_LIST)}; + +static const struct gpio_ctrl *get_gpio_ctrl(char *name) +{ + const struct device *dev = device_get_binding(name); + size_t i; + + for (i = 0; i < ARRAY_SIZE(gpio_list); i++) { + if (gpio_list[i].dev == dev) { + return &gpio_list[i]; + } + } + return NULL; } -static int cmd_gpio_get(const struct shell *sh, - size_t argc, char **argv) +int line_cmp(const char *input, const char *line_name) { - const struct device *dev; - uint8_t index = 0U; - int rc; + int i = 0; - if (isdigit((unsigned char)argv[args_indx.index][0]) != 0) { - index = (uint8_t)atoi(argv[args_indx.index]); - } else { - shell_error(sh, "Wrong parameters for get"); + while (true) { + if ((input[i] == '_') && (line_name[i] == ' ')) { + /* Allow input underscore to match line_name space */ + } else if (input[i] != line_name[i]) { + return (input[i] > line_name[i]) ? 1 : -1; + } else if (line_name[i] == '\0') { + return 0; + } + i++; + } +} + +static int get_gpio_pin(const struct shell *sh, const struct gpio_ctrl *ctrl, char *line_name) +{ + gpio_pin_t pin = PIN_NOT_FOUND; + gpio_pin_t i; + int result; + + for (i = 0; i < ctrl->ngpios; i++) { + result = line_cmp(line_name, ctrl->line_names[i]); + if (result == 0) { + if ((BIT64(i) & ctrl->reserved_mask) != 0) { + shell_error(sh, "Reserved pin"); + return -EACCES; + } else if (pin == PIN_NOT_FOUND) { + pin = i; + } else { + shell_error(sh, "Line name ambiguous"); + return -EFAULT; + } + } + } + + if (pin == PIN_NOT_FOUND) { + shell_error(sh, "Line name not found: '%s'", line_name); + return -ENOENT; + } + + return pin; +} + +static int get_sh_gpio(const struct shell *sh, char **argv, struct sh_gpio *gpio) +{ + const struct gpio_ctrl *ctrl; + int ret = 0; + int pin; + + ctrl = get_gpio_ctrl(argv[ARGV_DEV]); + if (ctrl == NULL) { + shell_error(sh, "unknown gpio controller: %s", argv[ARGV_DEV]); return -EINVAL; } + gpio->dev = ctrl->dev; + pin = shell_strtoul(argv[ARGV_PIN], 0, &ret); + if (ret != 0) { + pin = get_gpio_pin(sh, ctrl, argv[ARGV_PIN]); + if (pin < 0) { + return pin; + } + } else if ((BIT64(pin) & ctrl->reserved_mask) != 0) { + shell_error(sh, "Reserved pin"); + return -EACCES; + } + gpio->pin = pin; + + return 0; +} - dev = device_get_binding(argv[args_indx.port]); +static int cmd_gpio_conf(const struct shell *sh, size_t argc, char **argv, void *data) +{ + gpio_flags_t flags = 0; + gpio_flags_t vendor_specific; + struct sh_gpio gpio; + int ret = 0; + + ret = get_sh_gpio(sh, argv, &gpio); + if (ret != 0) { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } - if (dev != NULL) { - index = (uint8_t)atoi(argv[2]); - shell_print(sh, "Reading %s pin %d", - argv[args_indx.port], index); - rc = gpio_pin_get(dev, index); - if (rc >= 0) { - shell_print(sh, "Value %d", rc); + for (int i = 0; i < strlen(argv[ARGV_CONF]); i++) { + switch (argv[ARGV_CONF][i]) { + case 'i': + flags |= GPIO_INPUT; + break; + case 'o': + flags |= GPIO_OUTPUT; + break; + case 'u': + flags |= GPIO_PULL_UP; + break; + case 'd': + flags |= GPIO_PULL_DOWN; + break; + case 'h': + flags |= GPIO_ACTIVE_HIGH; + break; + case 'l': + flags |= GPIO_ACTIVE_LOW; + break; + case '0': + flags |= GPIO_OUTPUT_INIT_LOGICAL | GPIO_OUTPUT_INIT_LOW; + break; + case '1': + flags |= GPIO_OUTPUT_INIT_LOGICAL | GPIO_OUTPUT_INIT_HIGH; + break; + default: + shell_error(sh, "Unknown: '%c'", argv[ARGV_CONF][i]); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + } + + if (((flags & GPIO_INPUT) != 0) == ((flags & GPIO_OUTPUT) != 0)) { + shell_error(sh, "must be either input or output"); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + if (((flags & GPIO_PULL_UP) != 0) && ((flags & GPIO_PULL_DOWN) != 0)) { + shell_error(sh, "cannot be pull up and pull down"); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + if (((flags & GPIO_ACTIVE_LOW) != 0) && ((flags & GPIO_ACTIVE_HIGH) != 0)) { + shell_error(sh, "cannot be active low and active high"); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + if ((flags & GPIO_OUTPUT) != 0) { + /* Default to active high if not specified */ + if ((flags & (GPIO_ACTIVE_LOW | GPIO_ACTIVE_HIGH)) == 0) { + flags |= GPIO_ACTIVE_HIGH; + } + /* Default to initialisation to logic 0 if not specified */ + if ((flags & GPIO_OUTPUT_INIT_LOGICAL) == 0) { + flags |= GPIO_OUTPUT_INIT_LOGICAL | GPIO_OUTPUT_INIT_LOW; + } + } + + if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT_INIT_LOGICAL) != 0)) { + shell_error(sh, "an input cannot be initialised to a logic level"); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + if (((flags & GPIO_OUTPUT_INIT_LOW) != 0) && ((flags & GPIO_OUTPUT_INIT_HIGH) != 0)) { + shell_error(sh, "cannot initialise to logic 0 and logic 1"); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + if (argc == 5) { + vendor_specific = shell_strtoul(argv[ARGV_VENDOR_SPECIFIC], 0, &ret); + if ((ret == 0) && ((vendor_specific & ~(0xFF00U)) == 0)) { + flags |= vendor_specific; } else { - shell_error(sh, "Error %d reading value", rc); - return -EIO; + /* + * See include/zephyr/dt-bindings/gpio/ for the + * available flags for your vendor. + */ + shell_error(sh, "vendor specific flags must be within " + "the mask 0xFF00"); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; } } + ret = gpio_pin_configure(gpio.dev, gpio.pin, flags); + if (ret != 0) { + shell_error(sh, "error: %d", ret); + return ret; + } + return 0; } -static int cmd_gpio_set(const struct shell *sh, - size_t argc, char **argv) +static int cmd_gpio_get(const struct shell *sh, size_t argc, char **argv) { - const struct device *dev; - uint8_t index = 0U; - uint8_t value = 0U; + struct sh_gpio gpio; + int value; + int ret; - if (isdigit((unsigned char)argv[args_indx.index][0]) != 0 && - isdigit((unsigned char)argv[args_indx.value][0]) != 0) { - index = (uint8_t)atoi(argv[args_indx.index]); - value = (uint8_t)atoi(argv[args_indx.value]); - } else { - shell_print(sh, "Wrong parameters for set"); - return -EINVAL; + ret = get_sh_gpio(sh, argv, &gpio); + if (ret != 0) { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; } - dev = device_get_binding(argv[args_indx.port]); - if (dev != NULL) { - index = (uint8_t)atoi(argv[2]); - shell_print(sh, "Writing to %s pin %d", - argv[args_indx.port], index); - gpio_pin_set(dev, index, value); + value = gpio_pin_get(gpio.dev, gpio.pin); + if (value >= 0) { + shell_print(sh, "%u", value); + } else { + shell_error(sh, "error: %d", value); + return value; } return 0; } +static int cmd_gpio_set(const struct shell *sh, size_t argc, char **argv) +{ + struct sh_gpio gpio; + unsigned long value; + int ret = 0; + + ret = get_sh_gpio(sh, argv, &gpio); + if (ret != 0) { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + value = shell_strtoul(argv[ARGV_VALUE], 0, &ret); + if (ret != 0) { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + ret = gpio_pin_set(gpio.dev, gpio.pin, value != 0); + if (ret != 0) { + shell_error(sh, "error: %d", ret); + return ret; + } + + return 0; +} /* 500 msec = 1/2 sec */ #define SLEEP_TIME_MS 500 -static int cmd_gpio_blink(const struct shell *sh, - size_t argc, char **argv) +static int cmd_gpio_blink(const struct shell *sh, size_t argc, char **argv) { - const struct device *dev; - uint8_t index = 0U; - uint8_t value = 0U; - size_t count = 0; + bool msg_one_shot = true; + struct sh_gpio gpio; + size_t count; char data; + int ret; - if (isdigit((unsigned char)argv[args_indx.index][0]) != 0) { - index = (uint8_t)atoi(argv[args_indx.index]); - } else { - shell_error(sh, "Wrong parameters for blink"); - return -EINVAL; + ret = get_sh_gpio(sh, argv, &gpio); + if (ret != 0) { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; } - dev = device_get_binding(argv[args_indx.port]); - if (dev != NULL) { - index = (uint8_t)atoi(argv[2]); - shell_fprintf(sh, SHELL_NORMAL, "Blinking port %s index %d.", argv[1], index); - shell_fprintf(sh, SHELL_NORMAL, " Hit any key to exit"); + /* dummy read to clear any pending input */ + (void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count); - /* dummy read to clear any pending input */ + while (true) { (void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count); + if (count != 0) { + break; + } + ret = gpio_pin_toggle(gpio.dev, gpio.pin); + if (ret != 0) { + shell_error(sh, "%d", ret); + break; + } else if (msg_one_shot) { + msg_one_shot = false; + shell_print(sh, "Hit any key to exit"); + } + k_msleep(SLEEP_TIME_MS); + } - while (true) { - (void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count); - if (count != 0) { - break; + return 0; +} + +static void device_name_get(size_t idx, struct shell_static_entry *entry) +{ + if (idx >= ARRAY_SIZE(gpio_list)) { + entry->syntax = NULL; + return; + } + + entry->syntax = gpio_list[idx].dev->name; + entry->handler = NULL; + entry->help = "Device"; + entry->subcmd = gpio_list[idx].subcmd; +} + +SHELL_DYNAMIC_CMD_CREATE(sub_gpio_dev, device_name_get); + +struct pin_info { + const struct device *dev; + bool reserved; + gpio_pin_t pin; + const char *line_name; +}; + +struct pin_order_user_data { + const struct shell *sh; + struct pin_info prev; + struct pin_info next; +}; + +typedef void (*pin_foreach_func_t)(const struct pin_info *info, void *user_data); + +static void print_gpio_ctrl_info(const struct shell *sh, const struct gpio_ctrl *ctrl) +{ + gpio_pin_t pin; + bool reserved; + + shell_print(sh, " ngpios: %u", ctrl->ngpios); + shell_print(sh, " Reserved pin mask: 0x%08X", ctrl->reserved_mask); + + shell_print(sh, ""); + + shell_print(sh, " Reserved Pin Line Name"); + for (pin = 0; pin < GPIO_MAX_PINS_PER_PORT; pin++) { + if ((pin >= ctrl->ngpios) && (pin >= ctrl->line_names_len)) { + /* Out of info */ + break; + } + reserved = (BIT64(pin) & ctrl->reserved_mask) != 0; + shell_print(sh, " %c %2u %s", reserved ? '*' : ' ', + pin, ctrl->line_names[pin]); + } +} + +static void foreach_pin(pin_foreach_func_t func, void *user_data) +{ + gpio_port_pins_t reserved_mask; + struct pin_info info; + gpio_pin_t pin; + size_t i; + + for (i = 0; i < ARRAY_SIZE(gpio_list); i++) { + for (pin = 0; pin < gpio_list[i].ngpios; pin++) { + info.dev = gpio_list[i].dev; + reserved_mask = gpio_list[i].reserved_mask; + info.reserved = (BIT64(pin) & reserved_mask) != 0; + info.pin = pin; + if (pin < gpio_list[i].line_names_len) { + info.line_name = gpio_list[i].line_names[pin]; + } else { + info.line_name = ""; } - gpio_pin_set(dev, index, value); - value = !value; - k_msleep(SLEEP_TIME_MS); + func(&info, user_data); } + } +} + +static int pin_cmp(const struct pin_info *a, const struct pin_info *b) +{ + int result = strcmp(a->line_name, b->line_name); + + if (result != 0) { + return result; + } + result = strcmp(a->dev->name, b->dev->name); + if (result != 0) { + return result; + } + result = (int)a->pin - (int)b->pin; + + return result; +} + +static void pin_get_next(const struct pin_info *info, void *user_data) +{ + struct pin_order_user_data *data = user_data; + int result; - shell_fprintf(sh, SHELL_NORMAL, "\n"); + if (data->prev.line_name != NULL) { + result = pin_cmp(info, &data->prev); + } else { + result = 1; + } + if (result > 0) { + if (data->next.line_name == NULL) { + data->next = *info; + return; + } + result = pin_cmp(info, &data->next); + if (result < 0) { + data->next = *info; + } } +} + +static void pin_ordered(const struct pin_info *info, void *user_data) +{ + struct pin_order_user_data *data = user_data; + + ARG_UNUSED(info); + + foreach_pin(pin_get_next, data); + + shell_print(data->sh, " %-12s %-8c %-16s %2u", + data->next.line_name, + data->next.reserved ? '*' : ' ', + data->next.dev->name, + data->next.pin); + + data->prev = data->next; + data->next.line_name = NULL; +} + +static void print_ordered_info(const struct shell *sh) +{ + struct pin_order_user_data data = {0}; + + data.sh = sh; + + shell_print(sh, " %-12s %-8s %-16s %-3s", + "Line", "Reserved", "Device", "Pin"); + + foreach_pin(pin_ordered, &data); +} + +static int cmd_gpio_info(const struct shell *sh, size_t argc, char **argv) +{ + const struct gpio_ctrl *ctrl = get_gpio_ctrl(argv[ARGV_DEV]); + + if (ctrl == NULL) { + /* No device specified */ + print_ordered_info(sh); + return 0; + } + + print_gpio_ctrl_info(sh, ctrl); return 0; } SHELL_STATIC_SUBCMD_SET_CREATE(sub_gpio, - SHELL_CMD_ARG(conf, NULL, "Configure GPIO", cmd_gpio_conf, 4, 0), - SHELL_CMD_ARG(get, NULL, "Get GPIO value", cmd_gpio_get, 3, 0), - SHELL_CMD_ARG(set, NULL, "Set GPIO", cmd_gpio_set, 4, 0), - SHELL_CMD_ARG(blink, NULL, "Blink GPIO", cmd_gpio_blink, 3, 0), - SHELL_SUBCMD_SET_END /* Array terminated. */ - ); + SHELL_CMD_ARG(conf, &sub_gpio_dev, + "Configure GPIO pin\n" + "Usage: gpio conf [u|d][h|l][0|1]> [vendor specific]\n" + " - input|output\n" + "[u|d] - pull up|pull down, otherwise open\n" + "[h|l] - active high|active low, otherwise defaults to active high\n" + "[0|1] - initialise to logic 0|logic 1, otherwise defaults to logic 0\n" + "[vendor specific] - configuration flags within the mask 0xFF00\n" + " see include/zephyr/dt-bindings/gpio/", + cmd_gpio_conf, 4, 1), + SHELL_CMD_ARG(get, &sub_gpio_dev, + "Get GPIO pin value\n" + "Usage: gpio get ", cmd_gpio_get, 3, 0), + SHELL_CMD_ARG(set, &sub_gpio_dev, + "Set GPIO pin value\n" + "Usage: gpio set ", cmd_gpio_set, 4, 0), + SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_BLINK_CMD, blink, &sub_gpio_dev, + "Blink GPIO pin\n" + "Usage: gpio blink ", cmd_gpio_blink, 3, 0), + SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_INFO_CMD, info, &sub_gpio_dev, + "GPIO Information\n" + "Usage: gpio info [device]", cmd_gpio_info, 1, 1), + SHELL_SUBCMD_SET_END /* Array terminated. */ +); SHELL_CMD_REGISTER(gpio, &sub_gpio, "GPIO commands", NULL); diff --git a/drivers/gpio/gpio_sifive.c b/drivers/gpio/gpio_sifive.c index 440ad3f78ab79fb..7e56b9dba3e47b0 100644 --- a/drivers/gpio/gpio_sifive.c +++ b/drivers/gpio/gpio_sifive.c @@ -17,7 +17,8 @@ #include #include #include - +#include +#include #include typedef void (*sifive_cfg_func_t)(void); @@ -144,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; @@ -376,7 +373,7 @@ DEVICE_DT_INST_DEFINE(0, &gpio_sifive_driver); #define IRQ_INIT(n) \ -IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, n, irq), \ +IRQ_CONNECT(DT_INST_IRQN_BY_IDX(0, n), \ DT_INST_IRQ_BY_IDX(0, n, priority), \ gpio_sifive_irq_handler, \ DEVICE_DT_INST_GET(0), \ diff --git a/drivers/gpio/gpio_stm32.c b/drivers/gpio/gpio_stm32.c index 877dbb4882cf3c2..e2cdb1d5325cf09 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 new file mode 100644 index 000000000000000..47a899e161532c0 --- /dev/null +++ b/drivers/gpio/gpio_tle9104.c @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT infineon_tle9104 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(gpio_tle9104, CONFIG_GPIO_LOG_LEVEL); + +/* + * The values for the defines below as well as the register definitions were + * taken from the datasheet, which can be found at: + * https://www.infineon.com/dgdl/Infineon-TLE9104SH-DataSheet-v01_31-EN.pdf?fileId=5546d462766cbe86017676144d76581b + */ +#define TLE9104_RESET_DURATION_TIME_US 10 +#define TLE9104_RESET_DURATION_WAIT_TIME_SAFETY_MARGIN_US 200 +#define TLE9104_RESET_DURATION_WAIT_TIME_US 10 +#define TLE9104_GPIO_COUNT 4 +#define TLE9104_INITIALIZATION_TIMEOUT_MS 1 +#define TLE9104_ICVERSIONID 0xB1 + +#define TLE9104_FRAME_RW_POS 15 +#define TLE9104_FRAME_PARITY_POS 14 +#define TLE9104_FRAME_FAULTCOMMUNICATION_POS 13 +#define TLE9104_FRAME_FAULTGLOBAL_POS 12 +#define TLE9104_FRAME_ADDRESS_POS 8 +#define TLE9104_FRAME_DATA_POS 0 + +#define TLE9104_CFG_CWDTIME_LENGTH 2 +#define TLE9104_CFG_CWDTIME_POS 6 + +#define TLE9104_CTRL_OUT1ONS_BIT BIT(1) +#define TLE9104_CTRL_OUT1ONC_BIT BIT(0) +#define TLE9104_CFG_OUT1DD_BIT BIT(0) +#define TLE9104_GLOBALSTATUS_OUTEN_BIT BIT(7) +#define TLE9104_GLOBALSTATUS_POR_LATCH_BIT BIT(0) +#define TLE9104_SPIFRAME_FAULTCOMMUNICATION_BIT BIT(13) + +enum tle9104_register { + TLE9104REGISTER_CTRL = 0x00, + TLE9104REGISTER_CFG = 0x01, + TLE9104REGISTER_GLOBALSTATUS = 0x07, + TLE9104REGISTER_ICVID = 0x08, +}; + +struct tle9104_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + + struct spi_dt_spec bus; + const struct gpio_dt_spec gpio_reset; + const struct gpio_dt_spec gpio_enable; + const struct gpio_dt_spec gpio_control[TLE9104_GPIO_COUNT]; +}; + +struct tle9104_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + /* each bit is one output channel, bit 0 = OUT1, ... */ + uint8_t state; + /* same as state, just kept for checking what has to be updated */ + uint8_t previous_state; + /* 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) +{ + uint8_t length = TLE9104_CFG_CWDTIME_LENGTH; + uint8_t pos = TLE9104_CFG_CWDTIME_POS; + + *destination &= ~GENMASK(pos + length - 1, pos); + *destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value); +} + +static int tle9104_calculate_parity(uint16_t value) +{ + int parity = 1 + POPCOUNT(value); + + if ((value & BIT(TLE9104_FRAME_PARITY_POS)) != 0) { + parity--; + } + + return parity % 2; +} + +static void tle9104_apply_parity(uint16_t *value) +{ + int parity = tle9104_calculate_parity(*value); + + WRITE_BIT(*value, TLE9104_FRAME_PARITY_POS, parity); +} + +static bool tle9104_check_parity(uint16_t value) +{ + int parity = tle9104_calculate_parity(value); + + return ((value & BIT(TLE9104_FRAME_PARITY_POS)) >> TLE9104_FRAME_PARITY_POS) == parity; +} + +static int tle9104_transceive_frame(const struct device *dev, bool write, + enum tle9104_register write_reg, uint8_t write_data, + 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; + uint8_t buffer_tx[2]; + uint8_t buffer_rx[ARRAY_SIZE(buffer_tx)]; + const struct spi_buf tx_buf[] = {{ + .buf = buffer_tx, + .len = ARRAY_SIZE(buffer_tx), + }}; + const struct spi_buf rx_buf[] = {{ + .buf = buffer_rx, + .len = ARRAY_SIZE(buffer_rx), + }}; + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = ARRAY_SIZE(tx_buf), + }; + const struct spi_buf_set rx = { + .buffers = rx_buf, + .count = ARRAY_SIZE(rx_buf), + }; + + write_frame = write_data << TLE9104_FRAME_DATA_POS; + write_frame |= write_reg << TLE9104_FRAME_ADDRESS_POS; + WRITE_BIT(write_frame, TLE9104_FRAME_RW_POS, write); + tle9104_apply_parity(&write_frame); + sys_put_be16(write_frame, buffer_tx); + LOG_DBG("writing in register 0x%02X of TLE9104 value 0x%02X, complete frame 0x%04X", + write_reg, write_data, write_frame); + + result = spi_transceive_dt(&config->bus, &tx, &rx); + if (result != 0) { + LOG_ERR("spi_write failed with error %i", result); + return result; + } + + read_frame = sys_get_be16(buffer_rx); + LOG_DBG("received complete frame 0x%04X", read_frame); + + if (!tle9104_check_parity(read_frame)) { + LOG_ERR("parity check for received frame of TLE9104 failed"); + return -EIO; + } + + 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), + read_frame); + *read_data = FIELD_GET(GENMASK(TLE9104_FRAME_ADDRESS_POS - 1, TLE9104_FRAME_DATA_POS), + read_frame); + + return 0; +} + +static int tle9104_write_register(const struct device *dev, enum tle9104_register reg, + uint8_t value) +{ + enum tle9104_register read_reg; + uint8_t read_data; + + return tle9104_transceive_frame(dev, true, reg, value, &read_reg, &read_data); +} + +static int tle9104_write_state(const struct device *dev) +{ + const struct tle9104_config *config = dev->config; + struct tle9104_data *data = dev->data; + bool spi_update_required = false; + uint8_t register_ctrl = 0x00; + int result; + + LOG_DBG("writing state 0x%02X to TLE9104", data->state); + + for (size_t i = 0; i < TLE9104_GPIO_COUNT; ++i) { + uint8_t mask = GENMASK(i, i); + bool current_value = (data->state & mask) != 0; + bool previous_value = (data->previous_state & mask) != 0; + + /* + * Setting the OUTx_ON bits results in a high impedance output, + * clearing them pulls the output to ground. Therefore the + * meaning here is intentionally inverted, as this will then turn + * out for a low active open drain output to be pulled to ground + * if set to off. + */ + if (current_value == 0) { + register_ctrl |= TLE9104_CTRL_OUT1ONS_BIT << (2 * i); + } else { + register_ctrl |= TLE9104_CTRL_OUT1ONC_BIT << (2 * i); + } + + if (current_value == previous_value) { + continue; + } + + if (config->gpio_control[i].port == NULL) { + spi_update_required = true; + continue; + } + + result = gpio_pin_set_dt(&config->gpio_control[i], current_value); + if (result != 0) { + LOG_ERR("unable to set control GPIO"); + return result; + } + } + + if (spi_update_required) { + result = tle9104_write_register(dev, TLE9104REGISTER_CTRL, register_ctrl); + if (result != 0) { + LOG_ERR("unable to set control register"); + return result; + } + } + + data->previous_state = data->state; + + return 0; +} + +static int tle9104_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + struct tle9104_data *data = dev->data; + int result; + + /* cannot execute a bus operation in an ISR context */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + if (pin >= TLE9104_GPIO_COUNT) { + LOG_ERR("invalid pin number %i", pin); + return -EINVAL; + } + + if ((flags & GPIO_INPUT) != 0) { + LOG_ERR("cannot configure pin as input"); + return -ENOTSUP; + } + + if ((flags & GPIO_OUTPUT) == 0) { + LOG_ERR("pin must be configured as an output"); + return -ENOTSUP; + } + + if ((flags & GPIO_SINGLE_ENDED) == 0) { + LOG_ERR("pin must be configured as single ended"); + return -ENOTSUP; + } + + if ((flags & GPIO_LINE_OPEN_DRAIN) == 0) { + LOG_ERR("pin must be configured as open drain"); + return -ENOTSUP; + } + + if ((flags & GPIO_PULL_UP) != 0) { + LOG_ERR("pin cannot have a pull up configured"); + return -ENOTSUP; + } + + if ((flags & GPIO_PULL_DOWN) != 0) { + LOG_ERR("pin cannot have a pull down configured"); + return -ENOTSUP; + } + + k_mutex_lock(&data->lock, K_FOREVER); + + if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) { + WRITE_BIT(data->state, pin, 0); + } else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) { + WRITE_BIT(data->state, pin, 1); + } + + WRITE_BIT(data->configured, pin, 1); + result = tle9104_write_state(dev); + k_mutex_unlock(&data->lock); + + return result; +} + +static int tle9104_port_get_raw(const struct device *dev, uint32_t *value) +{ + ARG_UNUSED(dev); + ARG_UNUSED(value); + + LOG_ERR("input pins are not available"); + return -ENOTSUP; +} + +static int tle9104_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value) +{ + struct tle9104_data *data = dev->data; + int result; + + /* cannot execute a bus operation in an ISR context */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + k_mutex_lock(&data->lock, K_FOREVER); + data->state = (data->state & ~mask) | (mask & value); + result = tle9104_write_state(dev); + k_mutex_unlock(&data->lock); + + return result; +} + +static int tle9104_port_set_bits_raw(const struct device *dev, uint32_t mask) +{ + return tle9104_port_set_masked_raw(dev, mask, mask); +} + +static int tle9104_port_clear_bits_raw(const struct device *dev, uint32_t mask) +{ + return tle9104_port_set_masked_raw(dev, mask, 0); +} + +static int tle9104_port_toggle_bits(const struct device *dev, uint32_t mask) +{ + struct tle9104_data *data = dev->data; + int result; + + /* cannot execute a bus operation in an ISR context */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + k_mutex_lock(&data->lock, K_FOREVER); + data->state ^= mask; + result = tle9104_write_state(dev); + k_mutex_unlock(&data->lock); + + return result; +} + +static int tle9104_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + ARG_UNUSED(dev); + ARG_UNUSED(pin); + ARG_UNUSED(mode); + ARG_UNUSED(trig); + return -ENOTSUP; +} + +static const struct gpio_driver_api api_table = { + .pin_configure = tle9104_pin_configure, + .port_get_raw = tle9104_port_get_raw, + .port_set_masked_raw = tle9104_port_set_masked_raw, + .port_set_bits_raw = tle9104_port_set_bits_raw, + .port_clear_bits_raw = tle9104_port_clear_bits_raw, + .port_toggle_bits = tle9104_port_toggle_bits, + .pin_interrupt_configure = tle9104_pin_interrupt_configure, +}; + +static int tle9104_init(const struct device *dev) +{ + const struct tle9104_config *config = dev->config; + struct tle9104_data *data = dev->data; + uint8_t register_cfg; + uint8_t register_globalstatus; + uint8_t register_icvid; + enum tle9104_register read_reg; + int result; + + 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"); + return result; + } + + if (!spi_is_ready_dt(&config->bus)) { + LOG_ERR("SPI bus %s is not ready", config->bus.bus->name); + return -ENODEV; + } + + register_cfg = 0x00; + + for (int i = 0; i < TLE9104_GPIO_COUNT; ++i) { + const struct gpio_dt_spec *current = config->gpio_control + i; + + if (current->port == NULL) { + LOG_DBG("got no control port for output %i, will control it via SPI", i); + continue; + } + + register_cfg |= TLE9104_CFG_OUT1DD_BIT << i; + + if (!gpio_is_ready_dt(current)) { + LOG_ERR("%s: control GPIO is not ready", dev->name); + return -ENODEV; + } + + result = gpio_pin_configure_dt(current, GPIO_OUTPUT_INACTIVE); + if (result != 0) { + LOG_ERR("failed to initialize control GPIO %i", i); + return result; + } + } + + if (config->gpio_enable.port != NULL) { + if (!gpio_is_ready_dt(&config->gpio_enable)) { + LOG_ERR("%s: enable GPIO is not ready", dev->name); + return -ENODEV; + } + + result = gpio_pin_configure_dt(&config->gpio_enable, GPIO_OUTPUT_ACTIVE); + if (result != 0) { + LOG_ERR("failed to enable TLE9104"); + 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; + } + + 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 + * global status register address. + */ + result = tle9104_transceive_frame(dev, false, TLE9104REGISTER_GLOBALSTATUS, 0x00, &read_reg, + ®ister_icvid); + if (result != 0) { + return result; + } + + if (read_reg != TLE9104REGISTER_ICVID) { + LOG_ERR("expected to read register ICVID, got instead 0x%02X", read_reg); + return -EIO; + } + + if (register_icvid != TLE9104_ICVERSIONID) { + LOG_ERR("got unexpected IC version id 0x%02X", register_icvid); + return -EIO; + } + + result = tle9104_transceive_frame(dev, false, TLE9104REGISTER_GLOBALSTATUS, 0x00, &read_reg, + ®ister_globalstatus); + if (result != 0) { + return result; + } + + if (read_reg != TLE9104REGISTER_GLOBALSTATUS) { + LOG_ERR("expected to read register GLOBALSTATUS, got instead 0x%02X", read_reg); + return -EIO; + } + + if ((register_globalstatus & TLE9104_GLOBALSTATUS_POR_LATCH_BIT) == 0) { + LOG_ERR("no power on reset detected"); + return -EIO; + } + + result = tle9104_write_register(dev, TLE9104REGISTER_CFG, register_cfg); + if (result != 0) { + LOG_ERR("unable to write configuration"); + return result; + } + + register_globalstatus = 0x00; + /* disable communication watchdog */ + tle9104_set_cfg_cwdtime(®ister_cfg, 0); + /* enable outputs */ + register_globalstatus |= TLE9104_GLOBALSTATUS_OUTEN_BIT; + + result = tle9104_write_register(dev, TLE9104REGISTER_GLOBALSTATUS, register_globalstatus); + if (result != 0) { + LOG_ERR("unable to write global status"); + return result; + } + + data->cwd_ignore = false; + + return 0; +} + +BUILD_ASSERT(CONFIG_GPIO_TLE9104_INIT_PRIORITY > CONFIG_SPI_INIT_PRIORITY, + "TLE9104 must be initialized after SPI"); + +#define TLE9104_INIT_GPIO_FIELDS(inst, gpio) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, gpio), \ + (GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), gpio, 0)), ({0})) + +#define TLE9104_INIT(inst) \ + static const struct tle9104_config tle9104_##inst##_config = { \ + .common = { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(inst), \ + }, \ + .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 = TLE9104_INIT_GPIO_FIELDS(inst, resn_gpios), \ + .gpio_control = { \ + TLE9104_INIT_GPIO_FIELDS(inst, in1_gpios), \ + TLE9104_INIT_GPIO_FIELDS(inst, in2_gpios), \ + TLE9104_INIT_GPIO_FIELDS(inst, in3_gpios), \ + TLE9104_INIT_GPIO_FIELDS(inst, in4_gpios), \ + }, \ + }; \ + \ + static struct tle9104_data tle9104_##inst##_drvdata; \ + \ + /* This has to be initialized after the SPI peripheral. */ \ + DEVICE_DT_INST_DEFINE(inst, tle9104_init, NULL, &tle9104_##inst##_drvdata, \ + &tle9104_##inst##_config, POST_KERNEL, \ + CONFIG_GPIO_TLE9104_INIT_PRIORITY, &api_table); + +DT_INST_FOREACH_STATUS_OKAY(TLE9104_INIT) diff --git a/drivers/hwinfo/CMakeLists.txt b/drivers/hwinfo/CMakeLists.txt index 437fbf969cf667e..ab3b587dc7525b2 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 6971315b6b89a60..84afbefd84feb1a 100644 --- a/drivers/hwinfo/Kconfig +++ b/drivers/hwinfo/Kconfig @@ -16,7 +16,6 @@ source "subsys/logging/Kconfig.template.log_config" config HWINFO_SHELL bool "HWINFO Shell" - default y depends on SHELL help Enable hwinfo Shell for testing. @@ -150,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 @@ -182,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 df4d67321120d8e..131c3fac0c5202e 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_handlers.c b/drivers/hwinfo/hwinfo_handlers.c index dd411f265d04516..02058f9b955c535 100644 --- a/drivers/hwinfo/hwinfo_handlers.c +++ b/drivers/hwinfo/hwinfo_handlers.c @@ -4,12 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include ssize_t z_vrfy_hwinfo_get_device_id(uint8_t *buffer, size_t length) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(buffer, length)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(buffer, length)); return z_impl_hwinfo_get_device_id((uint8_t *)buffer, (size_t)length); } @@ -21,7 +21,7 @@ int z_vrfy_hwinfo_get_reset_cause(uint32_t *cause) uint32_t cause_copy; ret = z_impl_hwinfo_get_reset_cause(&cause_copy); - Z_OOPS(z_user_to_copy(cause, &cause_copy, sizeof(uint32_t))); + K_OOPS(k_usermode_to_copy(cause, &cause_copy, sizeof(uint32_t))); return ret; } @@ -40,7 +40,7 @@ int z_vrfy_hwinfo_get_supported_reset_cause(uint32_t *supported) uint32_t supported_copy; ret = z_impl_hwinfo_get_supported_reset_cause(&supported_copy); - Z_OOPS(z_user_to_copy(supported, &supported_copy, sizeof(uint32_t))); + K_OOPS(k_usermode_to_copy(supported, &supported_copy, sizeof(uint32_t))); return ret; } diff --git a/drivers/hwinfo/hwinfo_nrf.c b/drivers/hwinfo/hwinfo_nrf.c index 2a79f1d0c0d1724..4375cf05b2f2830 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 000000000000000..f19c7770d60b87b --- /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/hwspinlock/hwspinlock_handlers.c b/drivers/hwspinlock/hwspinlock_handlers.c index a8e6c2a132ef69e..7064293be4bfe27 100644 --- a/drivers/hwspinlock/hwspinlock_handlers.c +++ b/drivers/hwspinlock/hwspinlock_handlers.c @@ -5,11 +5,11 @@ */ #include -#include +#include static inline int z_vrfy_hwspinlock_trylock(const struct device *dev, uint32_t id) { - Z_OOPS(Z_SYSCALL_DRIVER_HWSPINLOCK(dev, trylock)); + K_OOPS(K_SYSCALL_DRIVER_HWSPINLOCK(dev, trylock)); return z_impl_hwspinlock_trylock(dev, id); } @@ -17,7 +17,7 @@ static inline int z_vrfy_hwspinlock_trylock(const struct device *dev, uint32_t i static inline void z_vrfy_hwspinlock_lock(const struct device *dev, uint32_t id) { - Z_OOPS(Z_SYSCALL_DRIVER_HWSPINLOCK(dev, lock)); + K_OOPS(K_SYSCALL_DRIVER_HWSPINLOCK(dev, lock)); z_impl_hwspinlock_lock(dev, id); } @@ -25,7 +25,7 @@ static inline void z_vrfy_hwspinlock_lock(const struct device *dev, uint32_t id) static inline void z_vrfy_hwspinlock_unlock(const struct device *dev, uint32_t id) { - Z_OOPS(Z_SYSCALL_DRIVER_HWSPINLOCK(dev, unlock)); + K_OOPS(K_SYSCALL_DRIVER_HWSPINLOCK(dev, unlock)); z_impl_hwspinlock_unlock(dev, id); } @@ -33,7 +33,7 @@ static inline void z_vrfy_hwspinlock_unlock(const struct device *dev, uint32_t i static inline uint32_t z_vrfy_hwspinlock_get_max_id(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_HWSPINLOCK(dev, get_max_id)); + K_OOPS(K_SYSCALL_DRIVER_HWSPINLOCK(dev, get_max_id)); return z_impl_hwspinlock_get_max_id(dev); } diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index b9ed0a5fc29a41c..ff9289ad3f4c373 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) @@ -30,7 +27,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,8 @@ zephyr_library_sources_ifdef(CONFIG_I2C_XILINX_AXI i2c_xilinx_axi.c) 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 +67,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 ea1350344e54221..45e2dcd67fbf6b2 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -15,7 +15,6 @@ if I2C config I2C_SHELL bool "I2C Shell" - default y depends on SHELL help Enable I2C Shell. @@ -94,6 +93,7 @@ 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" config I2C_INIT_PRIORITY int "Init priority" @@ -196,4 +196,11 @@ config I2C_RV32M1_LPI2C help Enable the RV32M1 LPI2C driver. +config GPIO_I2C_SWITCH + bool "GPIO controlled I2C bus switch" + default y + depends on DT_HAS_GPIO_I2C_SWITCH_ENABLED + help + Enable GPIO controlled I2C bus switch driver. + endif # I2C diff --git a/drivers/i2c/Kconfig.dw b/drivers/i2c/Kconfig.dw index c84215f457198d9..796cfb643d1388c 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.nrfx b/drivers/i2c/Kconfig.nrfx index bfde27721a82b25..78967177a3ac2a0 100644 --- a/drivers/i2c/Kconfig.nrfx +++ b/drivers/i2c/Kconfig.nrfx @@ -27,6 +27,19 @@ config I2C_NRFX_TWIM select NRFX_TWIM1 if HAS_HW_NRF_TWIM1 select NRFX_TWIM2 if HAS_HW_NRF_TWIM2 select NRFX_TWIM3 if HAS_HW_NRF_TWIM3 + select NRFX_TWIM20 if HAS_HW_NRF_TWIM20 + select NRFX_TWIM21 if HAS_HW_NRF_TWIM21 + select NRFX_TWIM22 if HAS_HW_NRF_TWIM22 + select NRFX_TWIM30 if HAS_HW_NRF_TWIM30 + select NRFX_TWIM120 if HAS_HW_NRF_TWIM120 + select NRFX_TWIM130 if HAS_HW_NRF_TWIM130 + select NRFX_TWIM131 if HAS_HW_NRF_TWIM131 + select NRFX_TWIM132 if HAS_HW_NRF_TWIM132 + select NRFX_TWIM133 if HAS_HW_NRF_TWIM133 + select NRFX_TWIM134 if HAS_HW_NRF_TWIM134 + select NRFX_TWIM135 if HAS_HW_NRF_TWIM135 + select NRFX_TWIM136 if HAS_HW_NRF_TWIM136 + select NRFX_TWIM137 if HAS_HW_NRF_TWIM137 config I2C_NRFX_TRANSFER_TIMEOUT int "Transfer timeout [ms]" diff --git a/drivers/i2c/Kconfig.numaker b/drivers/i2c/Kconfig.numaker new file mode 100644 index 000000000000000..622592cd020d147 --- /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/Kconfig.sc18im704 b/drivers/i2c/Kconfig.sc18im704 index 15cdbd43d4d5c90..f38c0e67d23472e 100644 --- a/drivers/i2c/Kconfig.sc18im704 +++ b/drivers/i2c/Kconfig.sc18im704 @@ -5,6 +5,7 @@ config I2C_SC18IM704 bool "NXP SC18IM704 I2C controller driver" default y depends on DT_HAS_NXP_SC18IM704_I2C_ENABLED + select UART_USE_RUNTIME_CONFIGURE help Enables NXP SC18IM704 I2C controller driver diff --git a/drivers/i2c/gpio_i2c_switch.c b/drivers/i2c/gpio_i2c_switch.c new file mode 100644 index 000000000000000..d5a125a531b1e33 --- /dev/null +++ b/drivers/i2c/gpio_i2c_switch.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2023 Ayush Singh + * Copyright (c) 2021 Jason Kridner, BeagleBoard.org Foundation + * Copyright (c) 2020 Innoseis BV + * + * Based on i2c_tca9656a.c + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT gpio_i2c_switch + +#define GPIO_I2C_TOGGLE_DELAY_US 1 +#define GPIO_I2C_LOCK_TIMEOUT_US (GPIO_I2C_TOGGLE_DELAY_US * 2 + 100) + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(gpio_i2c_switch, CONFIG_I2C_LOG_LEVEL); + +struct gpio_i2c_switch_config { + const struct device *bus; + const struct gpio_dt_spec gpio; +}; + +struct gpio_i2c_switch_data { + struct k_mutex lock; +}; + +static int gpio_i2c_switch_configure(const struct device *dev, uint32_t dev_config) +{ + const struct gpio_i2c_switch_config *config = dev->config; + + return i2c_configure(config->bus, dev_config); +} + +static int gpio_i2c_switch_transfer(const struct device *dev, struct i2c_msg *msgs, + uint8_t num_msgs, uint16_t addr) +{ + int res; + struct gpio_i2c_switch_data *data = dev->data; + const struct gpio_i2c_switch_config *config = dev->config; + + res = k_mutex_lock(&data->lock, K_USEC(GPIO_I2C_LOCK_TIMEOUT_US)); + if (res != 0) { + return res; + } + + /* enable switch */ + gpio_pin_set_dt(&config->gpio, 1); + k_busy_wait(GPIO_I2C_TOGGLE_DELAY_US); + + res = i2c_transfer(config->bus, msgs, num_msgs, addr); + + /* disable switch */ + gpio_pin_set_dt(&config->gpio, 0); + k_busy_wait(GPIO_I2C_TOGGLE_DELAY_US); + k_mutex_unlock(&data->lock); + + return res; +} + +static const struct i2c_driver_api gpio_i2c_switch_api_funcs = { + .configure = gpio_i2c_switch_configure, + .transfer = gpio_i2c_switch_transfer, +}; + +static int gpio_i2c_switch_init(const struct device *dev) +{ + const struct gpio_i2c_switch_config *config = dev->config; + struct gpio_i2c_switch_data *data = dev->data; + + k_mutex_init(&data->lock); + + return gpio_pin_configure_dt(&config->gpio, GPIO_OUTPUT_INACTIVE); +} + +#define DEFINE_GPIO_I2C_SWITCH(inst) \ + \ + static struct gpio_i2c_switch_data gpio_i2c_switch_dev_data_##inst; \ + \ + static const struct gpio_i2c_switch_config gpio_i2c_switch_dev_cfg_##inst = { \ + .bus = DEVICE_DT_GET(DT_PHANDLE(DT_DRV_INST(inst), controller)), \ + .gpio = GPIO_DT_SPEC_GET(DT_DRV_INST(inst), gpios), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, gpio_i2c_switch_init, device_pm_control_nop, \ + &gpio_i2c_switch_dev_data_##inst, &gpio_i2c_switch_dev_cfg_##inst, \ + POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, &gpio_i2c_switch_api_funcs); + +DT_INST_FOREACH_STATUS_OKAY(DEFINE_GPIO_I2C_SWITCH) diff --git a/drivers/i2c/i2c_ambiq.c b/drivers/i2c/i2c_ambiq.c index 432bfbe4f002022..e8b62fb2c45a7d1 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 1aa0ff6f397010a..9312427ee8ef247 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 ca4485606b7cb4c..b198aa15c1bedf1 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 344275047081e33..c25246bbafe8a3f 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 4324f6792c62f14..62e0b0d762177c7 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 ab4347f2352347d..4959bed65b1360e 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 17d1eac0d8ae45d..4cb5606507a9960 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_handlers.c b/drivers/i2c/i2c_handlers.c index fca385ee27b5709..20ec2a6f5788c52 100644 --- a/drivers/i2c/i2c_handlers.c +++ b/drivers/i2c/i2c_handlers.c @@ -6,12 +6,12 @@ #include #include -#include +#include static inline int z_vrfy_i2c_configure(const struct device *dev, uint32_t dev_config) { - Z_OOPS(Z_SYSCALL_DRIVER_I2C(dev, configure)); + K_OOPS(K_SYSCALL_DRIVER_I2C(dev, configure)); return z_impl_i2c_configure((const struct device *)dev, dev_config); } #include @@ -19,8 +19,8 @@ static inline int z_vrfy_i2c_configure(const struct device *dev, static inline int z_vrfy_i2c_get_config(const struct device *dev, uint32_t *dev_config) { - Z_OOPS(Z_SYSCALL_DRIVER_I2C(dev, get_config)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(dev_config, sizeof(uint32_t))); + K_OOPS(K_SYSCALL_DRIVER_I2C(dev, get_config)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(dev_config, sizeof(uint32_t))); return z_impl_i2c_get_config(dev, dev_config); } @@ -41,7 +41,7 @@ static uint32_t copy_msgs_and_transfer(const struct device *dev, * that the target buffer be writable */ for (i = 0U; i < num_msgs; i++) { - Z_OOPS(Z_SYSCALL_MEMORY(copy[i].buf, copy[i].len, + K_OOPS(K_SYSCALL_MEMORY(copy[i].buf, copy[i].len, copy[i].flags & I2C_MSG_READ)); } @@ -52,17 +52,17 @@ static inline int z_vrfy_i2c_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs, uint16_t addr) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_I2C)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_I2C)); /* copy_msgs_and_transfer() will allocate a copy on the stack using * VLA, so ensure this won't blow the stack. Most functions defined * in i2c.h use only a handful of messages, so up to 32 messages * should be more than sufficient. */ - Z_OOPS(Z_SYSCALL_VERIFY(num_msgs >= 1 && num_msgs < 32)); + K_OOPS(K_SYSCALL_VERIFY(num_msgs >= 1 && num_msgs < 32)); /* We need to be able to read the overall array of messages */ - Z_OOPS(Z_SYSCALL_MEMORY_ARRAY_READ(msgs, num_msgs, + K_OOPS(K_SYSCALL_MEMORY_ARRAY_READ(msgs, num_msgs, sizeof(struct i2c_msg))); return copy_msgs_and_transfer((const struct device *)dev, @@ -73,21 +73,21 @@ static inline int z_vrfy_i2c_transfer(const struct device *dev, static inline int z_vrfy_i2c_target_driver_register(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_I2C)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_I2C)); return z_impl_i2c_target_driver_register(dev); } #include static inline int z_vrfy_i2c_target_driver_unregister(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_I2C)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_I2C)); return z_impl_i2c_target_driver_unregister(dev); } #include static inline int z_vrfy_i2c_recover_bus(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_I2C)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_I2C)); return z_impl_i2c_recover_bus(dev); } #include diff --git a/drivers/i2c/i2c_ifx_xmc4.c b/drivers/i2c/i2c_ifx_xmc4.c index 43714cce618fb4c..82994eae0773528 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 a499c81bf0a3a27..ae799596270a897 100644 --- a/drivers/i2c/i2c_ite_enhance.c +++ b/drivers/i2c/i2c_ite_enhance.c @@ -63,6 +63,7 @@ struct i2c_enhance_config { uint8_t *base; uint8_t i2c_irq_base; uint8_t port; + uint8_t channel_switch_sel; /* SCL GPIO cells */ struct gpio_dt_spec scl_gpios; /* SDA GPIO cells */ @@ -70,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; @@ -292,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(); /* @@ -316,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."); + } + + /* + * 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 */ - IT8XXX2_I2C_PSR(base) = psr & 0xFF; - IT8XXX2_I2C_HSPR(base) = psr & 0xFF; + /* 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; } } @@ -735,9 +755,11 @@ static int enhanced_i2c_cq_isr(const struct device *dev) uint8_t msgs_idx = data->num_msgs - 1; /* Get data if this is a read transaction. */ - for (int i = 0; i < data->cq_msgs[msgs_idx].len; i++) { - data->cq_msgs[msgs_idx].buf[i] = - host_buffer->i2c_cq_mode_rx_dlm[i]; + if (data->cq_msgs[msgs_idx].flags & I2C_MSG_READ) { + for (int i = 0; i < data->cq_msgs[msgs_idx].len; i++) { + data->cq_msgs[msgs_idx].buf[i] = + host_buffer->i2c_cq_mode_rx_dlm[i]; + } } } else { /* Device 1 error have occurred. eg. nack, timeout... */ @@ -1008,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 { @@ -1142,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; @@ -1172,6 +1195,31 @@ static int i2c_enhance_init(const struct device *dev) enhanced_i2c_set_cmd_addr_regs(dev); #endif + /* ChannelA-F switch selection of I2C pin */ + if (config->port == SMB_CHANNEL_A) { + IT8XXX2_SMB_SMB01CHS = (IT8XXX2_SMB_SMB01CHS &= ~GENMASK(2, 0)) | + config->channel_switch_sel; + } else if (config->port == SMB_CHANNEL_B) { + IT8XXX2_SMB_SMB01CHS = (config->channel_switch_sel << 4) | + (IT8XXX2_SMB_SMB01CHS &= ~GENMASK(6, 4)); + } else if (config->port == SMB_CHANNEL_C) { + IT8XXX2_SMB_SMB23CHS = (IT8XXX2_SMB_SMB23CHS &= ~GENMASK(2, 0)) | + config->channel_switch_sel; + } else if (config->port == I2C_CHANNEL_D) { + IT8XXX2_SMB_SMB23CHS = (config->channel_switch_sel << 4) | + (IT8XXX2_SMB_SMB23CHS &= ~GENMASK(6, 4)); + } else if (config->port == I2C_CHANNEL_E) { + IT8XXX2_SMB_SMB45CHS = (IT8XXX2_SMB_SMB45CHS &= ~GENMASK(2, 0)) | + config->channel_switch_sel; + } else if (config->port == I2C_CHANNEL_F) { + IT8XXX2_SMB_SMB45CHS = (config->channel_switch_sel << 4) | + (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 || @@ -1425,9 +1473,11 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_I2C_TARGET_BUFFER_MODE), .bitrate = DT_INST_PROP(inst, clock_frequency), \ .i2c_irq_base = DT_INST_IRQN(inst), \ .port = DT_INST_PROP(inst, port_num), \ + .channel_switch_sel = DT_INST_PROP(inst, channel_switch_sel), \ .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 2a55576ef5b7560..b931a9320302970 100644 --- a/drivers/i2c/i2c_ite_it8xxx2.c +++ b/drivers/i2c/i2c_ite_it8xxx2.c @@ -44,6 +44,7 @@ struct i2c_it8xxx2_config { uint8_t *reg_mstfctrl; uint8_t i2c_irq_base; uint8_t port; + uint8_t channel_switch_sel; /* SCL GPIO cells */ struct gpio_dt_spec scl_gpios; /* SDA GPIO cells */ @@ -1134,6 +1135,18 @@ static int i2c_it8xxx2_init(const struct device *dev) } #endif + /* ChannelA-C switch selection of I2C pin */ + if (config->port == SMB_CHANNEL_A) { + IT8XXX2_SMB_SMB01CHS = (IT8XXX2_SMB_SMB01CHS &= ~GENMASK(2, 0)) | + config->channel_switch_sel; + } else if (config->port == SMB_CHANNEL_B) { + IT8XXX2_SMB_SMB01CHS = (config->channel_switch_sel << 4) | + (IT8XXX2_SMB_SMB01CHS &= ~GENMASK(6, 4)); + } else if (config->port == SMB_CHANNEL_C) { + IT8XXX2_SMB_SMB23CHS = (IT8XXX2_SMB_SMB23CHS &= ~GENMASK(2, 0)) | + config->channel_switch_sel; + } + /* Set clock frequency for I2C ports */ if (config->bitrate == I2C_BITRATE_STANDARD || config->bitrate == I2C_BITRATE_FAST || @@ -1242,7 +1255,7 @@ static const struct i2c_driver_api i2c_it8xxx2_driver_api = { * that channel C may encounter wrong register being written due to FIFO2 * byte counter wrong write after channel B's write operation. */ -BUILD_ASSERT((DT_INST_PROP(SMB_CHANNEL_C, fifo_enable) == false), +BUILD_ASSERT((DT_PROP(DT_NODELABEL(i2c2), fifo_enable) == false), "Channel C cannot use FIFO mode."); #endif @@ -1265,6 +1278,7 @@ BUILD_ASSERT((DT_INST_PROP(SMB_CHANNEL_C, fifo_enable) == false), .bitrate = DT_INST_PROP(inst, clock_frequency), \ .i2c_irq_base = DT_INST_IRQN(inst), \ .port = DT_INST_PROP(inst, port_num), \ + .channel_switch_sel = DT_INST_PROP(inst, channel_switch_sel), \ .scl_gpios = GPIO_DT_SPEC_INST_GET(inst, scl_gpios), \ .sda_gpios = GPIO_DT_SPEC_INST_GET(inst, sda_gpios), \ .clock_gate_offset = DT_INST_PROP(inst, clock_gate_offset), \ diff --git a/drivers/i2c/i2c_litex.c b/drivers/i2c/i2c_litex.c index 8f429ba5e5962e3..58636209bf6a97c 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 0ee35f69134ccab..f834aa658f78ab8 100644 --- a/drivers/i2c/i2c_ll_stm32.c +++ b/drivers/i2c/i2c_ll_stm32.c @@ -44,25 +44,38 @@ LOG_MODULE_REGISTER(i2c_ll_stm32); #define STM32_I2C_DOMAIN_CLOCK_SUPPORT 0 #endif +int i2c_stm32_get_config(const struct device *dev, uint32_t *config) +{ + struct i2c_stm32_data *data = dev->data; + + if (!data->is_configured) { + LOG_ERR("I2C controller not configured"); + return -EIO; + } + + *config = data->dev_config; + + return 0; +} + 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 clock = 0U; + 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], - &clock) < 0) { + 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], - &clock) < 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; } @@ -73,19 +86,27 @@ int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config) k_sem_take(&data->bus_mutex, K_FOREVER); #ifdef CONFIG_PM_DEVICE_RUNTIME - (void)pm_device_runtime_get(dev); -#else - pm_device_busy_set(dev); + ret = clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken[0]); + if (ret < 0) { + LOG_ERR("failure Enabling I2C clock"); + return ret; + } #endif LL_I2C_Disable(i2c); - LL_I2C_SetMode(i2c, LL_I2C_MODE_I2C); - ret = stm32_i2c_configure_timing(dev, clock); + 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 - (void)pm_device_runtime_put(dev); -#else - pm_device_busy_clear(dev); + ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]); + if (ret < 0) { + LOG_ERR("failure disabling I2C clock"); + return ret; + } #endif k_sem_give(&data->bus_mutex); @@ -272,6 +293,7 @@ static int i2c_stm32_recover_bus(const struct device *dev) static const struct i2c_driver_api api_funcs = { .configure = i2c_stm32_runtime_configure, .transfer = i2c_stm32_transfer, + .get_config = i2c_stm32_get_config, #if CONFIG_I2C_STM32_BUS_RECOVERY .recover_bus = i2c_stm32_recover_bus, #endif /* CONFIG_I2C_STM32_BUS_RECOVERY */ @@ -346,6 +368,9 @@ static int i2c_stm32_init(const struct device *dev) cfg->irq_config_func(dev); #endif + data->is_configured = false; + data->mode = I2CSTM32MODE_I2C; + /* * initialize mutex used when multiple transfers * are taking place to guarantee that each one is @@ -391,11 +416,11 @@ static int i2c_stm32_init(const struct device *dev) } #ifdef CONFIG_PM_DEVICE_RUNTIME - i2c_stm32_suspend(dev); - pm_device_init_suspended(dev); (void)pm_device_runtime_enable(dev); #endif + data->is_configured = true; + return 0; } @@ -421,6 +446,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 @@ -468,30 +557,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); \ \ @@ -505,9 +576,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 1db22236043b466..0a9dc1be350a6a9 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 */ @@ -77,6 +79,13 @@ struct i2c_stm32_data { struct i2c_target_config *slave2_cfg; #endif 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 }; @@ -85,6 +94,7 @@ int32_t stm32_i2c_transaction(const struct device *dev, uint16_t periph); int32_t stm32_i2c_configure_timing(const struct device *dev, uint32_t clk); int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config); +int i2c_stm32_get_config(const struct device *dev, uint32_t *config); void stm32_i2c_event_isr(void *arg); void stm32_i2c_error_isr(void *arg); diff --git a/drivers/i2c/i2c_ll_stm32_v1.c b/drivers/i2c/i2c_ll_stm32_v1.c index d0a0131858fec42..ff63ee399131d31 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 c75d68e4f19a900..a685ebebeb78677 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 887579cf9a10249..49b0da2a719c8f6 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_lpi2c.c b/drivers/i2c/i2c_mcux_lpi2c.c index cc6d7954b588041..166603593122e20 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 2540a0a87ac83e9..1300b2d95b68dd9 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 9cd4a02970b17c7..1349a535b93578e 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 08338244043f65e..6155f1a1499c109 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_nrfx_twi.c b/drivers/i2c/i2c_nrfx_twi.c index bbb070e7e0c7caa..8af5fe4ddeecafe 100644 --- a/drivers/i2c/i2c_nrfx_twi.c +++ b/drivers/i2c/i2c_nrfx_twi.c @@ -126,7 +126,6 @@ static int i2c_nrfx_twi_transfer(const struct device *dev, * to make sure everything has been done to restore the * bus from this error. */ - LOG_ERR("Error on I2C line occurred for message %d", i); nrfx_twi_disable(&config->twi); (void)i2c_nrfx_twi_recover_bus(dev); ret = -EIO; @@ -135,7 +134,6 @@ static int i2c_nrfx_twi_transfer(const struct device *dev, res = data->res; if (res != NRFX_SUCCESS) { - LOG_ERR("Error 0x%08X occurred for message %d", res, i); ret = -EIO; break; } diff --git a/drivers/i2c/i2c_nrfx_twim.c b/drivers/i2c/i2c_nrfx_twim.c index 13df5051ac726e8..90e1fcfb1097054 100644 --- a/drivers/i2c/i2c_nrfx_twim.c +++ b/drivers/i2c/i2c_nrfx_twim.c @@ -166,7 +166,6 @@ static int i2c_nrfx_twim_transfer(const struct device *dev, * to make sure everything has been done to restore the * bus from this error. */ - LOG_ERR("Error on I2C line occurred for message %d", i); (void)i2c_nrfx_twim_recover_bus(dev); ret = -EIO; break; @@ -175,7 +174,6 @@ static int i2c_nrfx_twim_transfer(const struct device *dev, res = dev_data->res; if (res != NRFX_SUCCESS) { - LOG_ERR("Error 0x%08X occurred for message %d", res, i); ret = -EIO; break; } @@ -455,3 +453,55 @@ I2C_NRFX_TWIM_DEVICE(2); #ifdef CONFIG_HAS_HW_NRF_TWIM3 I2C_NRFX_TWIM_DEVICE(3); #endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM20 +I2C_NRFX_TWIM_DEVICE(20); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM21 +I2C_NRFX_TWIM_DEVICE(21); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM22 +I2C_NRFX_TWIM_DEVICE(22); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM30 +I2C_NRFX_TWIM_DEVICE(30); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM120 +I2C_NRFX_TWIM_DEVICE(120); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM130 +I2C_NRFX_TWIM_DEVICE(130); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM131 +I2C_NRFX_TWIM_DEVICE(131); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM132 +I2C_NRFX_TWIM_DEVICE(132); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM133 +I2C_NRFX_TWIM_DEVICE(133); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM134 +I2C_NRFX_TWIM_DEVICE(134); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM135 +I2C_NRFX_TWIM_DEVICE(135); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM136 +I2C_NRFX_TWIM_DEVICE(136); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM137 +I2C_NRFX_TWIM_DEVICE(137); +#endif diff --git a/drivers/i2c/i2c_numaker.c b/drivers/i2c/i2c_numaker.c new file mode 100644 index 000000000000000..0c85601566077c6 --- /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 7e74329612dd3c0..6c02837065ddce5 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 ca0f6e6ef2ec5a3..ef64f1ac3d38d6c 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 8ef32d7bb89ddbb..e3ddd62b26247f8 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 ab14a7be9dd8d46..4802e0ba071c1d1 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 671139bd266765e..ca2e4ae8b6850b6 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 da19336af7339e2..9a61d2bad175e29 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.nrfx b/drivers/i2s/Kconfig.nrfx index 1cb023a2b2ea540..b36f3eb9c641eea 100644 --- a/drivers/i2s/Kconfig.nrfx +++ b/drivers/i2s/Kconfig.nrfx @@ -6,6 +6,7 @@ menuconfig I2S_NRFX default y depends on DT_HAS_NORDIC_NRF_I2S_ENABLED select NRFX_I2S0 if HAS_HW_NRF_I2S0 + select NRFX_I2S20 if HAS_HW_NRF_I2S20 select PINCTRL help Enable support for nrfx I2S driver for nRF MCU series. diff --git a/drivers/i2s/Kconfig.stm32 b/drivers/i2s/Kconfig.stm32 index 8ef499ce7c96860..3a4078d9f7a9ed6 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_handlers.c b/drivers/i2s/i2s_handlers.c index e556d708616c876..0ef1f6e6cd55416 100644 --- a/drivers/i2s/i2s_handlers.c +++ b/drivers/i2s/i2s_handlers.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include @@ -16,17 +16,17 @@ static inline int z_vrfy_i2s_configure(const struct device *dev, struct i2s_config config; int ret = -EINVAL; - if (Z_SYSCALL_DRIVER_I2S(dev, configure)) { + if (K_SYSCALL_DRIVER_I2S(dev, configure)) { goto out; } - Z_OOPS(z_user_from_copy(&config, (const void *)cfg_ptr, + K_OOPS(k_usermode_from_copy(&config, (const void *)cfg_ptr, sizeof(struct i2s_config))); /* Check that the k_mem_slab provided is a valid pointer and that * the caller has permission on it */ - if (Z_SYSCALL_OBJ(config.mem_slab, K_OBJ_MEM_SLAB)) { + if (K_SYSCALL_OBJ(config.mem_slab, K_OBJ_MEM_SLAB)) { goto out; } @@ -50,7 +50,7 @@ static inline int z_vrfy_i2s_buf_read(const struct device *dev, size_t data_size; int ret; - Z_OOPS(Z_SYSCALL_DRIVER_I2S(dev, read)); + K_OOPS(K_SYSCALL_DRIVER_I2S(dev, read)); ret = i2s_read((const struct device *)dev, &mem_block, &data_size); @@ -63,12 +63,12 @@ static inline int z_vrfy_i2s_buf_read(const struct device *dev, */ rx_cfg = i2s_config_get((const struct device *)dev, I2S_DIR_RX); - copy_success = z_user_to_copy((void *)buf, mem_block, + copy_success = k_usermode_to_copy((void *)buf, mem_block, data_size); k_mem_slab_free(rx_cfg->mem_slab, mem_block); - Z_OOPS(copy_success); - Z_OOPS(z_user_to_copy((void *)size, &data_size, + K_OOPS(copy_success); + K_OOPS(k_usermode_to_copy((void *)size, &data_size, sizeof(data_size))); } @@ -83,7 +83,7 @@ static inline int z_vrfy_i2s_buf_write(const struct device *dev, const struct i2s_config *tx_cfg; void *mem_block; - Z_OOPS(Z_SYSCALL_DRIVER_I2S(dev, write)); + K_OOPS(K_SYSCALL_DRIVER_I2S(dev, write)); tx_cfg = i2s_config_get((const struct device *)dev, I2S_DIR_TX); if (!tx_cfg) { return -EIO; @@ -98,10 +98,10 @@ static inline int z_vrfy_i2s_buf_write(const struct device *dev, return -ENOMEM; } - ret = z_user_from_copy(mem_block, (void *)buf, size); + ret = k_usermode_from_copy(mem_block, (void *)buf, size); if (ret) { k_mem_slab_free(tx_cfg->mem_slab, mem_block); - Z_OOPS(ret); + K_OOPS(ret); } ret = i2s_write((const struct device *)dev, mem_block, size); @@ -117,7 +117,7 @@ static inline int z_vrfy_i2s_trigger(const struct device *dev, enum i2s_dir dir, enum i2s_trigger_cmd cmd) { - Z_OOPS(Z_SYSCALL_DRIVER_I2S(dev, trigger)); + K_OOPS(K_SYSCALL_DRIVER_I2S(dev, trigger)); return z_impl_i2s_trigger((const struct device *)dev, dir, cmd); } diff --git a/drivers/i2s/i2s_ll_stm32.c b/drivers/i2s/i2s_ll_stm32.c index 7ff2d2c3b6ec21b..bf06d5f4df705a2 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 d1dda99a5f2f4a4..6e966edd4a136f6 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)); @@ -901,7 +922,7 @@ static int i2s_mcux_init(const struct device *dev) data->tx.state = I2S_STATE_NOT_READY; data->rx.state = I2S_STATE_NOT_READY; - LOG_INF("Device %s inited", dev->name); + LOG_DBG("Device %s inited", dev->name); return 0; } @@ -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_mcux_sai.c b/drivers/i2s/i2s_mcux_sai.c index 5294127f7590c1f..08bcdbb6343fe33 100644 --- a/drivers/i2s/i2s_mcux_sai.c +++ b/drivers/i2s/i2s_mcux_sai.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 NXP Semiconductor INC. + * Copyright 2021,2023 NXP Semiconductor INC. * All rights reserved. * * SPDX-License-Identifier: Apache-2.0 @@ -1254,9 +1254,7 @@ static const struct i2s_driver_api i2s_mcux_driver_api = { \ static const struct i2s_mcux_config i2s_##i2s_id##_config = { \ .base = (I2S_Type *)DT_INST_REG_ADDR(i2s_id), \ - .clk_src = \ - DT_CLOCKS_CELL_BY_IDX(DT_DRV_INST(i2s_id), \ - 0, bits), \ + .clk_src = DT_INST_PROP(i2s_id, clock_mux), \ .clk_pre_div = DT_INST_PROP(i2s_id, pre_div), \ .clk_src_div = DT_INST_PROP(i2s_id, podf), \ .pll_src = \ diff --git a/drivers/i2s/i2s_nrfx.c b/drivers/i2s/i2s_nrfx.c index 57910c464ab7f83..b4a6f55443f19d2 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; \ @@ -955,5 +987,10 @@ static const struct i2s_driver_api i2s_nrf_drv_api = { POST_KERNEL, CONFIG_I2S_INIT_PRIORITY, \ &i2s_nrf_drv_api); -/* Existing SoCs only have one I2S instance. */ +#ifdef CONFIG_HAS_HW_NRF_I2S0 I2S_NRFX_DEVICE(0); +#endif + +#ifdef CONFIG_HAS_HW_NRF_I2S20 +I2S_NRFX_DEVICE(20); +#endif diff --git a/drivers/i3c/CMakeLists.txt b/drivers/i3c/CMakeLists.txt index 2645dbeabb59d7c..71a7dc6eb27b00a 100644 --- a/drivers/i3c/CMakeLists.txt +++ b/drivers/i3c/CMakeLists.txt @@ -30,3 +30,8 @@ zephyr_library_sources_ifdef( CONFIG_I3C_CADENCE i3c_cdns.c ) + +zephyr_library_sources_ifdef( + CONFIG_I3C_TEST + i3c_test.c +) diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig index f4a343632abf4bb..2b524c2bf9d8ed9 100644 --- a/drivers/i3c/Kconfig +++ b/drivers/i3c/Kconfig @@ -100,5 +100,6 @@ comment "Device Drivers" rsource "Kconfig.nxp" rsource "Kconfig.cdns" +rsource "Kconfig.test" endif # I3C diff --git a/drivers/i3c/Kconfig.test b/drivers/i3c/Kconfig.test new file mode 100644 index 000000000000000..3b28d596980e5b5 --- /dev/null +++ b/drivers/i3c/Kconfig.test @@ -0,0 +1,11 @@ +# Copyright (c) 2021, Commonwealth Scientific and Industrial Research +# Organisation (CSIRO) ABN 41 687 119 230. +# Copyright (c) 2023 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 + +# Hidden option for turning on the dummy driver for vnd,i3c devices +# used in testing. +config I3C_TEST + def_bool DT_HAS_VND_I3C_ENABLED + depends on DT_HAS_VND_I3C_ENABLED diff --git a/drivers/i3c/i3c_cdns.c b/drivers/i3c/i3c_cdns.c index cad6bab65664371..ef361523e4e225d 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; @@ -703,7 +725,7 @@ static void cdns_i3c_program_controller_retaining_reg(const struct device *dev) if (!i3c_addr_slots_is_free(&data->common.attached_dev.addr_slots, controller_da)) { controller_da = - i3c_addr_slots_next_free_find(&data->common.attached_dev.addr_slots); + i3c_addr_slots_next_free_find(&data->common.attached_dev.addr_slots, 0); LOG_DBG("%s: 0x%02x DA selected for controller", dev->name, controller_da); } sys_write32(prepare_rr0_dev_address(controller_da), config->base + DEV_ID_RR0(0)); @@ -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_common.c b/drivers/i3c/i3c_common.c index 29746f3cf68eae5..6c170edb9e33b93 100644 --- a/drivers/i3c/i3c_common.c +++ b/drivers/i3c/i3c_common.c @@ -157,13 +157,13 @@ bool i3c_addr_slots_is_free(struct i3c_addr_slots *slots, return (status == I3C_ADDR_SLOT_STATUS_FREE); } -uint8_t i3c_addr_slots_next_free_find(struct i3c_addr_slots *slots) +uint8_t i3c_addr_slots_next_free_find(struct i3c_addr_slots *slots, uint8_t start_addr) { uint8_t addr; enum i3c_addr_slot_status status; /* Addresses 0 to 7 are reserved. So start at 8. */ - for (addr = 8; addr < I3C_MAX_ADDR; addr++) { + for (addr = MAX(start_addr, 8); addr < I3C_MAX_ADDR; addr++) { status = i3c_addr_slots_status(slots, addr); if (status == I3C_ADDR_SLOT_STATUS_FREE) { return addr; @@ -252,7 +252,7 @@ int i3c_determine_default_addr(struct i3c_device_desc *target, uint8_t *addr) } else { /* address is not free, get the next one */ *addr = i3c_addr_slots_next_free_find( - &data->attached_dev.addr_slots); + &data->attached_dev.addr_slots, 0); } } else { /* Use the init dynamic address as it's DA, but the RR will need to @@ -281,7 +281,7 @@ int i3c_determine_default_addr(struct i3c_device_desc *target, uint8_t *addr) } else { /* pick a DA to use */ *addr = i3c_addr_slots_next_free_find( - &data->attached_dev.addr_slots); + &data->attached_dev.addr_slots, 0); } } } else { @@ -488,7 +488,7 @@ int i3c_dev_list_daa_addr_helper(struct i3c_addr_slots *addr_slots, /* * Find the next available address. */ - dyn_addr = i3c_addr_slots_next_free_find(addr_slots); + dyn_addr = i3c_addr_slots_next_free_find(addr_slots, 0); if (dyn_addr == 0U) { /* No free addresses available */ diff --git a/drivers/i3c/i3c_handlers.c b/drivers/i3c/i3c_handlers.c index e5a5289868db144..a5d218992a33277 100644 --- a/drivers/i3c/i3c_handlers.c +++ b/drivers/i3c/i3c_handlers.c @@ -6,29 +6,29 @@ #include #include -#include +#include static inline int z_vrfy_i3c_do_ccc(const struct device *dev, struct i3c_ccc_payload *payload) { - Z_OOPS(Z_SYSCALL_DRIVER_I3C(dev, do_ccc)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(payload, sizeof(*payload))); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(payload, sizeof(*payload))); + K_OOPS(K_SYSCALL_DRIVER_I3C(dev, do_ccc)); + K_OOPS(K_SYSCALL_MEMORY_READ(payload, sizeof(*payload))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(payload, sizeof(*payload))); if (payload->ccc.data != NULL) { - Z_OOPS(Z_SYSCALL_MEMORY_ARRAY_READ(payload->ccc.data, + K_OOPS(K_SYSCALL_MEMORY_ARRAY_READ(payload->ccc.data, payload->ccc.data_len, sizeof(*payload->ccc.data))); - Z_OOPS(Z_SYSCALL_MEMORY_ARRAY_WRITE(payload->ccc.data, + K_OOPS(K_SYSCALL_MEMORY_ARRAY_WRITE(payload->ccc.data, payload->ccc.data_len, sizeof(*payload->ccc.data))); } if (payload->targets.payloads != NULL) { - Z_OOPS(Z_SYSCALL_MEMORY_ARRAY_READ(payload->targets.payloads, + K_OOPS(K_SYSCALL_MEMORY_ARRAY_READ(payload->targets.payloads, payload->targets.num_targets, sizeof(*payload->targets.payloads))); - Z_OOPS(Z_SYSCALL_MEMORY_ARRAY_WRITE(payload->targets.payloads, + K_OOPS(K_SYSCALL_MEMORY_ARRAY_WRITE(payload->targets.payloads, payload->targets.num_targets, sizeof(*payload->targets.payloads))); } @@ -51,7 +51,7 @@ static uint32_t copy_i3c_msgs_and_transfer(struct i3c_device_desc *target, * that the target buffer be writable */ for (i = 0U; i < num_msgs; i++) { - Z_OOPS(Z_SYSCALL_MEMORY(copy[i].buf, copy[i].len, + K_OOPS(K_SYSCALL_MEMORY(copy[i].buf, copy[i].len, copy[i].flags & I3C_MSG_READ)); } @@ -61,18 +61,18 @@ static uint32_t copy_i3c_msgs_and_transfer(struct i3c_device_desc *target, static inline int z_vrfy_i3c_transfer(struct i3c_device_desc *target, struct i3c_msg *msgs, uint8_t num_msgs) { - Z_OOPS(Z_SYSCALL_MEMORY_READ(target, sizeof(*target))); - Z_OOPS(Z_SYSCALL_OBJ(target->bus, K_OBJ_DRIVER_I3C)); + K_OOPS(K_SYSCALL_MEMORY_READ(target, sizeof(*target))); + K_OOPS(K_SYSCALL_OBJ(target->bus, K_OBJ_DRIVER_I3C)); /* copy_msgs_and_transfer() will allocate a copy on the stack using * VLA, so ensure this won't blow the stack. Most functions defined * in i2c.h use only a handful of messages, so up to 32 messages * should be more than sufficient. */ - Z_OOPS(Z_SYSCALL_VERIFY(num_msgs >= 1 && num_msgs < 32)); + K_OOPS(K_SYSCALL_VERIFY(num_msgs >= 1 && num_msgs < 32)); /* We need to be able to read the overall array of messages */ - Z_OOPS(Z_SYSCALL_MEMORY_ARRAY_READ(msgs, num_msgs, + K_OOPS(K_SYSCALL_MEMORY_ARRAY_READ(msgs, num_msgs, sizeof(struct i3c_msg))); return copy_i3c_msgs_and_transfer((struct i3c_device_desc *)target, diff --git a/drivers/i3c/i3c_mcux.c b/drivers/i3c/i3c_mcux.c index c1ef9d9392e35d6..4d630ee1519c787 100644 --- a/drivers/i3c/i3c_mcux.c +++ b/drivers/i3c/i3c_mcux.c @@ -81,15 +81,15 @@ struct mcux_i3c_config { /** Interrupt configuration function. */ void (*irq_config_func)(const struct device *dev); + + /** Disable open drain high push pull */ + bool disable_open_drain_high_pp; }; struct mcux_i3c_data { /** Common I3C Driver Data */ struct i3c_driver_data common; - /** Configuration parameter to be used with HAL. */ - i3c_master_config_t ctrl_config_hal; - /** Semaphore to serialize access for applications. */ struct k_sem lock; @@ -542,9 +542,6 @@ static inline void mcux_i3c_request_daa(I3C_Type *base) /** * @brief Tell controller to start auto IBI. * - * This also waits for the controller to indicate auto IBI - * has started before returning. - * * @param base Pointer to controller registers. */ static inline void mcux_i3c_request_auto_ibi(I3C_Type *base) @@ -552,8 +549,6 @@ static inline void mcux_i3c_request_auto_ibi(I3C_Type *base) reg32_update(&base->MCTRL, I3C_MCTRL_REQUEST_MASK | I3C_MCTRL_IBIRESP_MASK | I3C_MCTRL_RDTERM_MASK, I3C_MCTRL_REQUEST_AUTO_IBI | I3C_MCTRL_IBIRESP_ACK_AUTO); - - mcux_i3c_status_wait_clear(base, I3C_MSTATUS_MCTRLDONE_MASK); } /** @@ -882,9 +877,7 @@ static int mcux_i3c_recover_bus(const struct device *dev) */ static int mcux_i3c_do_one_xfer_read(I3C_Type *base, uint8_t *buf, uint8_t buf_sz) { - int rx_count; bool completed = false; - bool overflow = false; int ret = 0; int offset = 0; @@ -911,28 +904,19 @@ static int mcux_i3c_do_one_xfer_read(I3C_Type *base, uint8_t *buf, uint8_t buf_s } /* - * Transfer data from FIFO into buffer. + * Transfer data from FIFO into buffer. Read + * in a tight loop to reduce chance of losing + * FIFO data when the i3c speed is high. */ - rx_count = mcux_i3c_fifo_rx_count_get(base); - while (rx_count > 0) { - uint8_t data = (uint8_t)base->MRDATAB; - - if (offset < buf_sz) { - buf[offset] = data; - offset += 1; - } else { - overflow = true; + while (offset < buf_sz) { + if (mcux_i3c_fifo_rx_count_get(base) == 0) { + break; } - - rx_count -= 1; + buf[offset++] = (uint8_t)base->MRDATAB; } } - if (overflow) { - ret = -EINVAL; - } else { - ret = offset; - } + ret = offset; one_xfer_read_out: return ret; @@ -1074,6 +1058,7 @@ static int mcux_i3c_transfer(const struct device *dev, I3C_Type *base = config->base; uint32_t intmask; int ret; + bool send_broadcast = true; if (target->dynamic_addr == 0U) { ret = -EINVAL; @@ -1124,12 +1109,35 @@ static int mcux_i3c_transfer(const struct device *dev, } } + /* + * Send broadcast header on first transfer or after a STOP, + * unless flag is set not to. + */ + if (!(msgs[i].flags & I3C_MSG_NBCH) && (send_broadcast)) { + ret = mcux_i3c_request_emit_start(base, I3C_BROADCAST_ADDR, + false, false, 0); + if (ret < 0) { + LOG_ERR("emit start of broadcast addr failed, error (%d)", + ret); + goto out_xfer_i3c_stop_unlock; + } + send_broadcast = false; + } + ret = mcux_i3c_do_one_xfer(base, dev_data, target->dynamic_addr, false, msgs[i].buf, msgs[i].len, is_read, emit_start, emit_stop, no_ending); if (ret < 0) { 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; + } } ret = 0; @@ -1366,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 */ @@ -1397,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; } } @@ -1806,7 +1820,7 @@ static int mcux_i3c_configure(const struct device *dev, const struct mcux_i3c_config *dev_cfg = dev->config; struct mcux_i3c_data *dev_data = dev->data; I3C_Type *base = dev_cfg->base; - i3c_master_config_t *ctrl_config_hal = &dev_data->ctrl_config_hal; + i3c_master_config_t master_config; struct i3c_config_controller *ctrl_cfg = config; uint32_t clock_freq; int ret = 0; @@ -1835,11 +1849,24 @@ static int mcux_i3c_configure(const struct device *dev, goto out_configure; } - ctrl_config_hal->baudRate_Hz.i2cBaud = ctrl_cfg->scl.i2c; - ctrl_config_hal->baudRate_Hz.i3cPushPullBaud = ctrl_cfg->scl.i3c; + /* + * Save requested config so next config_get() call returns the + * correct values. + */ + (void)memcpy(&dev_data->common.ctrl_config, ctrl_cfg, sizeof(*ctrl_cfg)); + + I3C_MasterGetDefaultConfig(&master_config); + + master_config.baudRate_Hz.i2cBaud = ctrl_cfg->scl.i2c; + master_config.baudRate_Hz.i3cPushPullBaud = ctrl_cfg->scl.i3c; + master_config.enableOpenDrainHigh = dev_cfg->disable_open_drain_high_pp ? false : true; + + if (dev_data->clocks.i3c_od_scl_hz) { + master_config.baudRate_Hz.i3cOpenDrainBaud = dev_data->clocks.i3c_od_scl_hz; + } /* Initialize hardware */ - I3C_MasterInit(base, ctrl_config_hal, clock_freq); + I3C_MasterInit(base, &master_config, clock_freq); out_configure: return ret; @@ -1912,30 +1939,11 @@ static int mcux_i3c_init(const struct device *dev) k_sem_init(&data->lock, 1, 1); k_sem_init(&data->ibi_lock, 1, 1); - /* - * Default controller configuration to act as the primary - * and active controller. - */ - I3C_MasterGetDefaultConfig(&data->ctrl_config_hal); - - /* Set default SCL clock rate (in Hz) */ - if (ctrl_config->scl.i2c == 0U) { - ctrl_config->scl.i2c = data->ctrl_config_hal.baudRate_Hz.i2cBaud; - } - - if (ctrl_config->scl.i3c == 0U) { - ctrl_config->scl.i3c = data->ctrl_config_hal.baudRate_Hz.i3cPushPullBaud; - } - - if (data->clocks.i3c_od_scl_hz != 0U) { - data->ctrl_config_hal.baudRate_Hz.i3cOpenDrainBaud = data->clocks.i3c_od_scl_hz; - } - /* Currently can only act as primary controller. */ - data->common.ctrl_config.is_secondary = false; + ctrl_config->is_secondary = false; /* HDR mode not supported at the moment. */ - data->common.ctrl_config.supported_hdr = 0U; + ctrl_config->supported_hdr = 0U; ret = mcux_i3c_configure(dev, I3C_CONFIG_CONTROLLER, ctrl_config); if (ret != 0) { @@ -2080,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,6 +2103,8 @@ static const struct i3c_driver_api mcux_i3c_driver_api = { .common.dev_list.i2c = mcux_i3c_i2c_device_array_##id, \ .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(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/i3c/i3c_test.c b/drivers/i3c/i3c_test.c new file mode 100644 index 000000000000000..165449747d859bc --- /dev/null +++ b/drivers/i3c/i3c_test.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * This is not a real I3C driver. It is used to instantiate struct + * devices for the "vnd,i3c" devicetree compatible used in test code. + */ + +#define DT_DRV_COMPAT vnd_i3c + +#include +#include +#include + +static int vnd_i3c_configure(const struct device *dev, + enum i3c_config_type type, void *config) +{ + return -ENOTSUP; +} + +static int vnd_i3c_config_get(const struct device *dev, + enum i3c_config_type type, void *config) +{ + return -ENOTSUP; +} + +static int vnd_i3c_recover_bus(const struct device *dev) +{ + return -ENOTSUP; +} + +static const struct i3c_driver_api vnd_i3c_api = { + .configure = vnd_i3c_configure, + .config_get = vnd_i3c_config_get, + .recover_bus = vnd_i3c_recover_bus, +}; + +#define VND_I3C_INIT(n) \ + DEVICE_DT_INST_DEFINE(n, NULL, NULL, NULL, NULL, \ + POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &vnd_i3c_api); + +DT_INST_FOREACH_STATUS_OKAY(VND_I3C_INIT) diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig index feccd4a60012aa4..d692024b096dc44 100644 --- a/drivers/ieee802154/Kconfig +++ b/drivers/ieee802154/Kconfig @@ -98,11 +98,6 @@ config IEEE802154_CSL_DEBUG help Enable support for CSL debugging by avoiding sleep state in favor of receive state. -config IEEE802154_SELECTIVE_TXPOWER - bool "Support selective TX power setting" - help - Enable support for selectively setting TX power for every transmission request. - module = IEEE802154_DRIVER module-str = IEEE 802.15.4 driver module-help = Sets log level for IEEE 802.15.4 Device Drivers. diff --git a/drivers/ieee802154/ieee802154_b91.c b/drivers/ieee802154/ieee802154_b91.c index 3c47c56fc9a1fb7..e44c99888dddb10 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" @@ -173,19 +175,26 @@ static void b91_update_rssi_and_lqi(struct net_pkt *pkt) } /* Prepare TX buffer */ -static void b91_set_tx_payload(uint8_t *payload, uint8_t payload_len) +static int b91_set_tx_payload(uint8_t *payload, uint8_t payload_len) { unsigned char rf_data_len; unsigned int rf_tx_dma_len; + /* See Telink SDK Dev Handbook, AN-21010600, section 21.5.2.2. */ + if (payload_len > (B91_TRX_LENGTH - B91_PAYLOAD_OFFSET - IEEE802154_FCS_LENGTH)) { + return -EINVAL; + } + rf_data_len = payload_len + 1; rf_tx_dma_len = rf_tx_packet_dma_len(rf_data_len); data.tx_buffer[0] = rf_tx_dma_len & 0xff; data.tx_buffer[1] = (rf_tx_dma_len >> 8) & 0xff; data.tx_buffer[2] = (rf_tx_dma_len >> 16) & 0xff; data.tx_buffer[3] = (rf_tx_dma_len >> 24) & 0xff; - data.tx_buffer[4] = payload_len + 2; + data.tx_buffer[4] = payload_len + IEEE802154_FCS_LENGTH; memcpy(data.tx_buffer + B91_PAYLOAD_OFFSET, payload, payload_len); + + return 0; } /* Enable ack handler */ @@ -243,7 +252,10 @@ static void b91_send_ack(uint8_t seq_num) { uint8_t ack_buf[] = { B91_ACK_TYPE, 0, seq_num }; - b91_set_tx_payload(ack_buf, sizeof(ack_buf)); + if (b91_set_tx_payload(ack_buf, sizeof(ack_buf))) { + return; + } + rf_set_txmode(); delay_us(CONFIG_IEEE802154_B91_SET_TXRX_DELAY_US); rf_tx_pkt(data.tx_buffer); @@ -534,7 +546,10 @@ static int b91_tx(const struct device *dev, } /* prepare tx buffer */ - b91_set_tx_payload(frag->data, frag->len); + status = b91_set_tx_payload(frag->data, frag->len); + if (status) { + return status; + } /* reset semaphores */ k_sem_reset(&b91->tx_wait); @@ -604,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 0c7901dfda3473c..7bc3aa3ed12c93f 100644 --- a/drivers/ieee802154/ieee802154_cc1200.c +++ b/drivers/ieee802154/ieee802154_cc1200.c @@ -446,9 +446,12 @@ static inline bool verify_crc(const struct device *dev, struct net_pkt *pkt) return true; } -static void cc1200_rx(void *arg) +static void cc1200_rx(void *p1, void *p2, void *p3) { - const struct device *dev = arg; + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; struct cc1200_context *cc1200 = dev->data; struct net_pkt *pkt; uint8_t pkt_len; @@ -779,7 +782,7 @@ static int cc1200_init(const struct device *dev) k_thread_create(&cc1200->rx_thread, cc1200->rx_stack, CONFIG_IEEE802154_CC1200_RX_STACK_SIZE, - (k_thread_entry_t)cc1200_rx, + cc1200_rx, (void *)dev, NULL, NULL, K_PRIO_COOP(2), 0, K_NO_WAIT); k_thread_name_set(&cc1200->rx_thread, "cc1200_rx"); @@ -810,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 5d5a53ed08e74cc..263b98d2823d79f 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 b5cc9b361767f41..dbaa02ff9eb2845 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -82,7 +82,7 @@ static uint32_t ieee802154_cc13xx_overrides_sub_ghz[] = { }; /* Radio values for CC13X2P */ -#elif defined(CONFIG_SOC_CC1352P) +#elif defined(CONFIG_SOC_CC1352P) || defined(CONFIG_SOC_CC1352P7) /* CC1352P overrides from SmartRF Studio (200kbps, 50kHz deviation, 2-GFSK, 311.8kHz Rx BW) */ static uint32_t ieee802154_cc13xx_overrides_sub_ghz[] = { /* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4:3]=0x1) */ @@ -141,7 +141,7 @@ static uint32_t rf_prop_overrides_tx_20[] = { #if defined(CONFIG_SOC_CC1352R) static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t ieee802154_cc13xx_subg_radio_div_setup = { .commandNo = CMD_PROP_RADIO_DIV_SETUP, -#elif defined(CONFIG_SOC_CC1352P) +#elif defined(CONFIG_SOC_CC1352P) || defined(CONFIG_SOC_CC1352P7) static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_PA_t ieee802154_cc13xx_subg_radio_div_setup = { .commandNo = CMD_PROP_RADIO_DIV_SETUP_PA, #endif /* CONFIG_SOC_CC1352x */ @@ -207,7 +207,7 @@ static const RF_TxPowerTable_Entry ieee802154_cc13xx_subg_power_table[] = { #endif RF_TxPowerTable_TERMINATION_ENTRY }; -#elif defined(CONFIG_SOC_CC1352P) +#elif defined(CONFIG_SOC_CC1352P) || defined(CONFIG_SOC_CC1352P7) /* Sub GHz power table */ static const RF_TxPowerTable_Entry ieee802154_cc13xx_subg_power_table[] = { { -20, RF_TxPowerTable_DEFAULT_PA_ENTRY(0, 3, 0, 2) }, @@ -673,6 +673,10 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, RF_EventMask events; int ret = 0; + if (buf->len > (CC13XX_CC26XX_TX_BUF_SIZE - IEEE802154_PHY_SUN_FSK_PHR_LEN)) { + return -EINVAL; + } + if (mode != IEEE802154_TX_MODE_DIRECT) { /* For backwards compatibility we only log an error but do not bail. */ NET_ERR("TX mode %d not supported - sending directly instead.", mode); @@ -698,9 +702,10 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, /* Complete the SUN FSK PHY header, see IEEE 802.15.4, section 19.2.4. */ drv_data->tx_data[0] = buf->len + IEEE802154_FCS_LENGTH; - /* Set TX data */ - __ASSERT_NO_MSG(buf->len + IEEE802154_PHY_SUN_FSK_PHR_LEN <= CC13XX_CC26XX_TX_BUF_SIZE); - /* TODO: Zero-copy TX, see discussion in #49775. */ + /* Set TX data + * + * TODO: Zero-copy TX, see discussion in #49775. + */ memcpy(&drv_data->tx_data[IEEE802154_PHY_SUN_FSK_PHR_LEN], buf->data, buf->len); drv_data->cmd_prop_tx_adv.pktLen = buf->len + IEEE802154_PHY_SUN_FSK_PHR_LEN; @@ -904,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 05404314d1f96ad..1f86d20d02f0b1c 100644 --- a/drivers/ieee802154/ieee802154_cc2520.c +++ b/drivers/ieee802154/ieee802154_cc2520.c @@ -591,9 +591,12 @@ static inline bool verify_rxfifo_validity(const struct device *dev, return true; } -static void cc2520_rx(void *arg) +static void cc2520_rx(void *p1, void *p2, void *p3) { - const struct device *dev = arg; + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; struct cc2520_context *cc2520 = dev->data; struct net_pkt *pkt; uint8_t pkt_len; @@ -1020,7 +1023,7 @@ static int cc2520_init(const struct device *dev) k_thread_create(&cc2520->cc2520_rx_thread, cc2520->cc2520_rx_stack, CONFIG_IEEE802154_CC2520_RX_STACK_SIZE, - (k_thread_entry_t)cc2520_rx, + cc2520_rx, (void *)dev, NULL, NULL, K_PRIO_COOP(2), 0, K_NO_WAIT); k_thread_name_set(&cc2520->cc2520_rx_thread, "cc2520_rx"); @@ -1054,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 d20df48896641db..13d5e047544fd7f 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 aee802ad6ff1a3d..40064c6df7b5959 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 5ba4e844a95fba7..2e6ed14286116d4 100644 --- a/drivers/ieee802154/ieee802154_mcr20a.c +++ b/drivers/ieee802154/ieee802154_mcr20a.c @@ -730,9 +730,12 @@ static inline bool irqsts3_event(const struct device *dev, return retval; } -static void mcr20a_thread_main(void *arg) +static void mcr20a_thread_main(void *p1, void *p2, void *p3) { - const struct device *dev = arg; + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; struct mcr20a_context *mcr20a = dev->data; uint8_t dregs[MCR20A_PHY_CTRL4 + 1]; bool set_new_seq; @@ -1419,7 +1422,7 @@ static int mcr20a_init(const struct device *dev) k_thread_create(&mcr20a->mcr20a_rx_thread, mcr20a->mcr20a_rx_stack, CONFIG_IEEE802154_MCR20A_RX_STACK_SIZE, - (k_thread_entry_t)mcr20a_thread_main, + mcr20a_thread_main, (void *)dev, NULL, NULL, K_PRIO_COOP(2), 0, K_NO_WAIT); k_thread_name_set(&mcr20a->mcr20a_rx_thread, "mcr20a_rx"); @@ -1449,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 8e1032718e4c162..0643d6051b653b0 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -57,14 +57,14 @@ struct nrf5_802154_config { }; static struct nrf5_802154_data nrf5_data; - -#define ACK_REQUEST_BYTE 1 -#define ACK_REQUEST_BIT (1 << 5) -#define FRAME_PENDING_BYTE 1 -#define FRAME_PENDING_BIT (1 << 4) +#if defined(CONFIG_IEEE802154_RAW_MODE) +static const struct device *nrf5_dev; +#endif #define DRX_SLOT_RX 0 /* Delayed reception window ID */ +#define NSEC_PER_TEN_SYMBOLS (10 * IEEE802154_PHY_OQPSK_780_TO_2450MHZ_SYMBOL_PERIOD_NS) + #if defined(CONFIG_IEEE802154_NRF5_UICR_EUI64_ENABLE) #if defined(CONFIG_SOC_NRF5340_CPUAPP) #if defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) @@ -98,6 +98,15 @@ static struct nrf5_802154_data nrf5_data; #define IEEE802154_NRF5_VENDOR_OUI (uint32_t)0xF4CE36 #endif +static inline const struct device *nrf5_get_device(void) +{ +#if defined(CONFIG_IEEE802154_RAW_MODE) + return nrf5_dev; +#else + return net_if_get_device(nrf5_data.iface); +#endif +} + static void nrf5_get_eui64(uint8_t *mac) { uint64_t factoryAddress; @@ -181,6 +190,10 @@ static void nrf5_rx_thread(void *arg1, void *arg2, void *arg3) net_pkt_set_timestamp_ns(pkt, rx_frame->time * NSEC_PER_USEC); #endif +#if defined(CONFIG_NET_L2_OPENTHREAD) + net_pkt_set_ieee802154_ack_seb(pkt, rx_frame->ack_seb); +#endif + LOG_DBG("Caught a packet (%u) (LQI: %u)", pkt_len, rx_frame->lqi); @@ -223,6 +236,7 @@ static void nrf5_get_capabilities_at_boot(void) ((caps & NRF_802154_CAPABILITY_DELAYED_TX) ? IEEE802154_HW_TXTIME : 0UL) | ((caps & NRF_802154_CAPABILITY_DELAYED_RX) ? IEEE802154_HW_RXTIME : 0UL) | IEEE802154_HW_SLEEP_TO_TX | + IEEE802154_RX_ON_WHEN_IDLE | ((caps & NRF_802154_CAPABILITY_SECURITY) ? IEEE802154_HW_TX_SEC : 0UL) #if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) | IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA @@ -241,6 +255,8 @@ static int nrf5_cca(const struct device *dev) { struct nrf5_802154_data *nrf5_radio = NRF5_802154_DATA(dev); + nrf_802154_channel_set(nrf5_data.channel); + if (!nrf_802154_cca()) { LOG_DBG("CCA failed"); return -EBUSY; @@ -266,7 +282,7 @@ static int nrf5_set_channel(const struct device *dev, uint16_t channel) return channel < 11 ? -ENOTSUP : -EINVAL; } - nrf_802154_channel_set(channel); + nrf5_data.channel = channel; return 0; } @@ -279,6 +295,8 @@ static int nrf5_energy_scan_start(const struct device *dev, ARG_UNUSED(dev); + nrf_802154_channel_set(nrf5_data.channel); + if (nrf5_data.energy_scan_done == NULL) { nrf5_data.energy_scan_done = done_cb; @@ -362,7 +380,7 @@ static int nrf5_set_txpower(const struct device *dev, int16_t dbm) LOG_DBG("%d", dbm); - nrf_802154_tx_power_set(dbm); + nrf5_data.txpwr = dbm; return 0; } @@ -441,10 +459,12 @@ static bool nrf5_tx_immediate(struct net_pkt *pkt, uint8_t *payload, bool cca) }, .cca = cca, .tx_power = { - .use_metadata_value = IS_ENABLED(CONFIG_IEEE802154_SELECTIVE_TXPOWER), -#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) - .power = net_pkt_ieee802154_txpwr(pkt), -#endif + .use_metadata_value = true, + .power = nrf5_data.txpwr, + }, + .tx_channel = { + .use_metadata_value = true, + .channel = nrf5_data.channel, }, }; @@ -460,10 +480,12 @@ static bool nrf5_tx_csma_ca(struct net_pkt *pkt, uint8_t *payload) .dynamic_data_is_set = net_pkt_ieee802154_mac_hdr_rdy(pkt), }, .tx_power = { - .use_metadata_value = IS_ENABLED(CONFIG_IEEE802154_SELECTIVE_TXPOWER), -#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) - .power = net_pkt_ieee802154_txpwr(pkt), -#endif + .use_metadata_value = true, + .power = nrf5_data.txpwr, + }, + .tx_channel = { + .use_metadata_value = true, + .channel = nrf5_data.channel, }, }; @@ -504,12 +526,10 @@ static bool nrf5_tx_at(struct nrf5_802154_data *nrf5_radio, struct net_pkt *pkt, .dynamic_data_is_set = net_pkt_ieee802154_mac_hdr_rdy(pkt), }, .cca = cca, - .channel = nrf_802154_channel_get(), + .channel = nrf5_data.channel, .tx_power = { - .use_metadata_value = IS_ENABLED(CONFIG_IEEE802154_SELECTIVE_TXPOWER), -#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) - .power = net_pkt_ieee802154_txpwr(pkt), -#endif + .use_metadata_value = true, + .power = nrf5_data.txpwr, }, #if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) .extra_cca_attempts = max_extra_cca_attempts, @@ -647,6 +667,9 @@ static int nrf5_start(const struct device *dev) { ARG_UNUSED(dev); + nrf_802154_tx_power_set(nrf5_data.txpwr); + nrf_802154_channel_set(nrf5_data.channel); + if (!nrf_802154_receive()) { LOG_ERR("Failed to enter receive state"); return -EIO; @@ -663,10 +686,11 @@ static int nrf5_stop(const struct device *dev) #if defined(CONFIG_IEEE802154_CSL_ENDPOINT) if (nrf_802154_sleep_if_idle() != NRF_802154_SLEEP_ERROR_NONE) { if (nrf5_data.event_handler) { - nrf5_data.event_handler(dev, IEEE802154_EVENT_SLEEP, NULL); + nrf5_data.event_handler(dev, IEEE802154_EVENT_RX_OFF, NULL); } else { LOG_WRN("Transition to radio sleep cannot be handled."); } + Z_SPIN_DELAY(1); return 0; } #else @@ -688,6 +712,9 @@ static int nrf5_continuous_carrier(const struct device *dev) { ARG_UNUSED(dev); + nrf_802154_tx_power_set(nrf5_data.txpwr); + nrf_802154_channel_set(nrf5_data.channel); + if (!nrf_802154_continuous_carrier()) { LOG_ERR("Failed to enter continuous carrier state"); return -EIO; @@ -724,6 +751,9 @@ static int nrf5_init(const struct device *dev) { const struct nrf5_802154_config *nrf5_radio_cfg = NRF5_802154_CFG(dev); struct nrf5_802154_data *nrf5_radio = NRF5_802154_DATA(dev); +#if defined(CONFIG_IEEE802154_RAW_MODE) + nrf5_dev = dev; +#endif k_fifo_init(&nrf5_radio->rx_fifo); k_sem_init(&nrf5_radio->tx_wait, 0, 1); @@ -733,6 +763,7 @@ static int nrf5_init(const struct device *dev) nrf5_get_capabilities_at_boot(); + nrf5_radio->rx_on_when_idle = true; nrf5_radio_cfg->irq_config_func(dev); k_thread_create(&nrf5_radio->rx_thread, nrf5_radio->rx_stack, @@ -764,25 +795,17 @@ static void nrf5_iface_init(struct net_if *iface) #if defined(CONFIG_NRF_802154_ENCRYPTION) static void nrf5_config_mac_keys(struct ieee802154_key *mac_keys) { - static nrf_802154_key_id_t stored_key_ids[NRF_802154_SECURITY_KEY_STORAGE_SIZE]; - static uint8_t stored_ids[NRF_802154_SECURITY_KEY_STORAGE_SIZE]; - uint8_t i; - - for (i = 0; i < NRF_802154_SECURITY_KEY_STORAGE_SIZE && stored_key_ids[i].p_key_id; i++) { - nrf_802154_security_key_remove(&stored_key_ids[i]); - stored_key_ids[i].p_key_id = NULL; - } + nrf_802154_security_key_remove_all(); - i = 0; - for (struct ieee802154_key *keys = mac_keys; keys->key_value - && i < NRF_802154_SECURITY_KEY_STORAGE_SIZE; keys++, i++) { + for (uint8_t i = 0; mac_keys->key_value + && i < NRF_802154_SECURITY_KEY_STORAGE_SIZE; mac_keys++, i++) { nrf_802154_key_t key = { - .value.p_cleartext_key = keys->key_value, - .id.mode = keys->key_id_mode, - .id.p_key_id = &(keys->key_index), + .value.p_cleartext_key = mac_keys->key_value, + .id.mode = mac_keys->key_id_mode, + .id.p_key_id = mac_keys->key_id, .type = NRF_802154_KEY_CLEARTEXT, .frame_counter = 0, - .use_global_frame_counter = !(keys->frame_counter_per_key), + .use_global_frame_counter = !(mac_keys->frame_counter_per_key), }; __ASSERT_EVAL((void)nrf_802154_security_key_store(&key), @@ -790,10 +813,6 @@ static void nrf5_config_mac_keys(struct ieee802154_key *mac_keys) err == NRF_802154_SECURITY_ERROR_NONE || err == NRF_802154_SECURITY_ERROR_ALREADY_PRESENT, "Storing key failed, err: %d", err); - - stored_ids[i] = *key.id.p_key_id; - stored_key_ids[i].mode = key.id.mode; - stored_key_ids[i].p_key_id = &stored_ids[i]; }; } #endif /* CONFIG_NRF_802154_ENCRYPTION */ @@ -877,36 +896,74 @@ static int nrf5_configure(const struct device *dev, #endif /* CONFIG_NRF_802154_ENCRYPTION */ case IEEE802154_CONFIG_ENH_ACK_HEADER_IE: { - uint8_t short_addr_le[SHORT_ADDRESS_SIZE]; uint8_t ext_addr_le[EXTENDED_ADDRESS_SIZE]; + uint8_t short_addr_le[SHORT_ADDRESS_SIZE]; + uint8_t element_id; + bool valid_vendor_specific_ie = false; + + if (config->ack_ie.purge_ie) { + nrf_802154_ack_data_remove_all(false, NRF_802154_ACK_DATA_IE); + nrf_802154_ack_data_remove_all(true, NRF_802154_ACK_DATA_IE); + break; + } + + if (config->ack_ie.short_addr == IEEE802154_BROADCAST_ADDRESS || + config->ack_ie.ext_addr == NULL) { + return -ENOTSUP; + } sys_put_le16(config->ack_ie.short_addr, short_addr_le); - /** - * The extended address field passed to this function starts - * with the most significant octet and ends with the least - * significant octet (i.e. big endian byte order). - * The IEEE 802.15.4 transmission order mandates this order to be - * reversed (i.e. little endian byte order) in a transmitted frame. - * - * The nrf_802154_ack_data_set expects extended address in transmission - * order. - */ sys_memcpy_swap(ext_addr_le, config->ack_ie.ext_addr, EXTENDED_ADDRESS_SIZE); - if (config->ack_ie.data_len > 0) { - nrf_802154_ack_data_set(short_addr_le, false, config->ack_ie.data, - config->ack_ie.data_len, NRF_802154_ACK_DATA_IE); - nrf_802154_ack_data_set(ext_addr_le, true, config->ack_ie.data, - config->ack_ie.data_len, NRF_802154_ACK_DATA_IE); - } else { + if (config->ack_ie.header_ie == NULL || config->ack_ie.header_ie->length == 0) { nrf_802154_ack_data_clear(short_addr_le, false, NRF_802154_ACK_DATA_IE); nrf_802154_ack_data_clear(ext_addr_le, true, NRF_802154_ACK_DATA_IE); + } else { + element_id = ieee802154_header_ie_get_element_id(config->ack_ie.header_ie); + +#if defined(CONFIG_NET_L2_OPENTHREAD) + uint8_t vendor_oui_le[IEEE802154_OPENTHREAD_VENDOR_OUI_LEN] = + IEEE802154_OPENTHREAD_THREAD_IE_VENDOR_OUI; + + if (element_id == IEEE802154_HEADER_IE_ELEMENT_ID_VENDOR_SPECIFIC_IE && + memcmp(config->ack_ie.header_ie->content.vendor_specific.vendor_oui, + vendor_oui_le, sizeof(vendor_oui_le)) == 0) { + valid_vendor_specific_ie = true; + } +#endif + + if (element_id != IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE && + !valid_vendor_specific_ie) { + return -ENOTSUP; + } + + nrf_802154_ack_data_set(short_addr_le, false, config->ack_ie.header_ie, + config->ack_ie.header_ie->length + + IEEE802154_HEADER_IE_HEADER_LENGTH, + NRF_802154_ACK_DATA_IE); + nrf_802154_ack_data_set(ext_addr_le, true, config->ack_ie.header_ie, + config->ack_ie.header_ie->length + + IEEE802154_HEADER_IE_HEADER_LENGTH, + NRF_802154_ACK_DATA_IE); } } break; #if defined(CONFIG_IEEE802154_CSL_ENDPOINT) - case IEEE802154_CONFIG_CSL_RX_TIME: { - nrf_802154_csl_writer_anchor_time_set(config->csl_rx_time / NSEC_PER_USEC); + case IEEE802154_CONFIG_EXPECTED_RX_TIME: { + +#if defined(CONFIG_NRF_802154_SER_HOST) + net_time_t period_ns = nrf5_data.csl_period * NSEC_PER_TEN_SYMBOLS; + bool changed = (config->expected_rx_time - nrf5_data.csl_rx_time) % period_ns; + + nrf5_data.csl_rx_time = config->expected_rx_time; + + if (changed) +#endif /* CONFIG_NRF_802154_SER_HOST */ + { + nrf_802154_csl_writer_anchor_time_set( + nrf_802154_timestamp_phr_to_mhr_convert(config->expected_rx_time / + NSEC_PER_USEC)); + } } break; case IEEE802154_CONFIG_RX_SLOT: { @@ -922,9 +979,12 @@ static int nrf5_configure(const struct device *dev, config->rx_slot.channel, DRX_SLOT_RX); } break; - case IEEE802154_CONFIG_CSL_PERIOD: + case IEEE802154_CONFIG_CSL_PERIOD: { nrf_802154_csl_writer_period_set(config->csl_period); - break; +#if defined(CONFIG_NRF_802154_SER_HOST) + nrf5_data.csl_period = config->csl_period; +#endif + } break; #endif /* CONFIG_IEEE802154_CSL_ENDPOINT */ #if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) @@ -935,6 +995,11 @@ static int nrf5_configure(const struct device *dev, break; #endif /* CONFIG_IEEE802154_NRF5_MULTIPLE_CCA */ + case IEEE802154_CONFIG_RX_ON_WHEN_IDLE: + nrf_802154_rx_on_when_idle_set(config->rx_on_when_idle); + nrf5_data.rx_on_when_idle = config->rx_on_when_idle; + break; + default: return -EINVAL; } @@ -994,13 +1059,10 @@ void nrf_802154_received_timestamp_raw(uint8_t *data, int8_t power, uint8_t lqi, nrf_802154_timestamp_end_to_phr_convert(time, data[0]); #endif - if (data[ACK_REQUEST_BYTE] & ACK_REQUEST_BIT) { - nrf5_data.rx_frames[i].ack_fpb = nrf5_data.last_frame_ack_fpb; - } else { - nrf5_data.rx_frames[i].ack_fpb = false; - } - + nrf5_data.rx_frames[i].ack_fpb = nrf5_data.last_frame_ack_fpb; + nrf5_data.rx_frames[i].ack_seb = nrf5_data.last_frame_ack_seb; nrf5_data.last_frame_ack_fpb = false; + nrf5_data.last_frame_ack_seb = false; k_fifo_put(&nrf5_data.rx_fifo, &nrf5_data.rx_frames[i]); @@ -1012,22 +1074,16 @@ void nrf_802154_received_timestamp_raw(uint8_t *data, int8_t power, uint8_t lqi, void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) { - const struct device *dev = net_if_get_device(nrf5_data.iface); + const struct device *dev = nrf5_get_device(); #if defined(CONFIG_IEEE802154_CSL_ENDPOINT) - if (id == DRX_SLOT_RX) { - __ASSERT_NO_MSG(nrf5_data.event_handler); -#if !defined(CONFIG_IEEE802154_CSL_DEBUG) - /* When CSL debug option is used we intentionally avoid notifying the higher layer - * about the finalization of a DRX slot, so that the radio stays in receive state - * for receiving "out of slot" frames. - * As a side effect, regular failure notifications would be reported with the - * incorrect ID. - */ - nrf5_data.event_handler(dev, IEEE802154_EVENT_SLEEP, NULL); -#endif - if (error == NRF_802154_RX_ERROR_DELAYED_TIMEOUT) { + if (id == DRX_SLOT_RX && error == NRF_802154_RX_ERROR_DELAYED_TIMEOUT) { + if (!nrf5_data.rx_on_when_idle) { + /* Transition to RxOff done automatically by the driver */ return; + } else if (nrf5_data.event_handler) { + /* Notify the higher layer to allow it to transition if needed */ + nrf5_data.event_handler(dev, IEEE802154_EVENT_RX_OFF, NULL); } } #else @@ -1060,6 +1116,8 @@ void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) } nrf5_data.last_frame_ack_fpb = false; + nrf5_data.last_frame_ack_seb = false; + if (nrf5_data.event_handler) { nrf5_data.event_handler(dev, IEEE802154_EVENT_RX_FAILED, (void *)&reason); } @@ -1067,8 +1125,8 @@ void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) void nrf_802154_tx_ack_started(const uint8_t *data) { - nrf5_data.last_frame_ack_fpb = - data[FRAME_PENDING_BYTE] & FRAME_PENDING_BIT; + nrf5_data.last_frame_ack_fpb = data[FRAME_PENDING_OFFSET] & FRAME_PENDING_BIT; + nrf5_data.last_frame_ack_seb = data[SECURITY_ENABLED_OFFSET] & SECURITY_ENABLED_BIT; } void nrf_802154_transmitted_raw(uint8_t *frame, @@ -1129,7 +1187,7 @@ void nrf_802154_energy_detected(const nrf_802154_energy_detected_t *result) energy_scan_done_cb_t callback = nrf5_data.energy_scan_done; nrf5_data.energy_scan_done = NULL; - callback(net_if_get_device(nrf5_data.iface), result->ed_dbm); + callback(nrf5_get_device(), result->ed_dbm); } } @@ -1139,7 +1197,7 @@ void nrf_802154_energy_detection_failed(nrf_802154_ed_error_t error) energy_scan_done_cb_t callback = nrf5_data.energy_scan_done; nrf5_data.energy_scan_done = NULL; - callback(net_if_get_device(nrf5_data.iface), SHRT_MAX); + callback(nrf5_get_device(), SHRT_MAX); } } @@ -1155,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_nrf5.h b/drivers/ieee802154/ieee802154_nrf5.h index 2cb41debbb86f72..0d4d9c9accfb098 100644 --- a/drivers/ieee802154/ieee802154_nrf5.h +++ b/drivers/ieee802154/ieee802154_nrf5.h @@ -19,6 +19,7 @@ struct nrf5_802154_rx_frame { uint8_t lqi; /* Last received frame LQI value. */ int8_t rssi; /* Last received frame RSSI value. */ bool ack_fpb; /* FPB value in ACK sent for the received frame. */ + bool ack_seb; /* SEB value in ACK sent for the received frame. */ }; struct nrf5_802154_data { @@ -45,6 +46,9 @@ struct nrf5_802154_data { /* Frame pending bit value in ACK sent for the last received frame. */ bool last_frame_ack_fpb; + /* Security Enabled bit value in ACK sent for the last received frame. */ + bool last_frame_ack_seb; + /* CCA complete semaphore. Unlocked when CCA is complete. */ struct k_sem cca_wait; @@ -92,6 +96,23 @@ struct nrf5_802154_data { /* The maximum number of extra CCA attempts to be performed before transmission. */ uint8_t max_extra_cca_attempts; #endif + + /* The TX power in dBm. */ + int8_t txpwr; + + /* The radio channel. */ + uint8_t channel; + +#if defined(CONFIG_NRF_802154_SER_HOST) && defined(CONFIG_IEEE802154_CSL_ENDPOINT) + /* The last configured value of CSL period in units of 10 symbols. */ + uint32_t csl_period; + + /* The last configured value of CSL phase time in nanoseconds. */ + net_time_t csl_rx_time; +#endif /* CONFIG_NRF_802154_SER_HOST && CONFIG_IEEE802154_CSL_ENDPOINT */ + + /* Indicates if RxOnWhenIdle mode is enabled. */ + bool rx_on_when_idle; }; #endif /* ZEPHYR_DRIVERS_IEEE802154_IEEE802154_NRF5_H_ */ diff --git a/drivers/ieee802154/ieee802154_rf2xx.c b/drivers/ieee802154/ieee802154_rf2xx.c index 870eb8a2f70422c..4d7c188ce675bc3 100644 --- a/drivers/ieee802154/ieee802154_rf2xx.c +++ b/drivers/ieee802154/ieee802154_rf2xx.c @@ -291,9 +291,12 @@ static void rf2xx_process_trx_end(const struct device *dev) } } -static void rf2xx_thread_main(void *arg) +static void rf2xx_thread_main(void *p1, void *p2, void *p3) { - struct rf2xx_context *ctx = arg; + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct rf2xx_context *ctx = p1; uint8_t isr_status; while (true) { @@ -1036,7 +1039,7 @@ static int rf2xx_init(const struct device *dev) k_thread_create(&ctx->trx_thread, ctx->trx_stack, CONFIG_IEEE802154_RF2XX_RX_STACK_SIZE, - (k_thread_entry_t) rf2xx_thread_main, + rf2xx_thread_main, ctx, NULL, NULL, K_PRIO_COOP(2), 0, K_NO_WAIT); @@ -1081,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 cdb420d97471ecd..72bcf5b8ebf6c03 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 683a3de9f1209b6..9aeb9198b310a64 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -3,15 +3,23 @@ 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) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_QDEC input_gpio_qdec.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GT911 input_gt911.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_ITE_IT8XXX2_KBD input_ite_it8xxx2_kbd.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_KBD_MATRIX input_kbd_matrix.c) zephyr_library_sources_ifdef(CONFIG_INPUT_NPCX_KBD input_npcx_kbd.c) zephyr_library_sources_ifdef(CONFIG_INPUT_STMPE811 input_stmpe811.c) zephyr_library_sources_ifdef(CONFIG_INPUT_XPT2046 input_xpt2046.c) +# zephyr-keep-sorted-stop if (CONFIG_INPUT_SDL_TOUCH) zephyr_library_sources(input_sdl_touch.c) @@ -21,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 0e33eef6607501d..41c93241f2aa036 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -5,16 +5,24 @@ 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" source "drivers/input/Kconfig.gpio_qdec" source "drivers/input/Kconfig.gt911" +source "drivers/input/Kconfig.it8xxx2" +source "drivers/input/Kconfig.kbd_matrix" source "drivers/input/Kconfig.npcx" source "drivers/input/Kconfig.sdl" source "drivers/input/Kconfig.stmpe811" source "drivers/input/Kconfig.xpt2046" +# zephyr-keep-sorted-stop endmenu # Input Drivers diff --git a/drivers/input/Kconfig.analog_axis b/drivers/input/Kconfig.analog_axis new file mode 100644 index 000000000000000..472b611acea8e22 --- /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 000000000000000..17460c94c6465ec --- /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 000000000000000..568797800f38528 --- /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.gpio_kbd_matrix b/drivers/input/Kconfig.gpio_kbd_matrix new file mode 100644 index 000000000000000..1ded27c12588157 --- /dev/null +++ b/drivers/input/Kconfig.gpio_kbd_matrix @@ -0,0 +1,10 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_GPIO_KBD_MATRIX + bool "GPIO based keyboard matrix input driver" + default y + depends on DT_HAS_GPIO_KBD_MATRIX_ENABLED + select INPUT_KBD_MATRIX + help + GPIO keyboard matrix input driver. diff --git a/drivers/input/Kconfig.it8xxx2 b/drivers/input/Kconfig.it8xxx2 new file mode 100644 index 000000000000000..0c59b3425342fd3 --- /dev/null +++ b/drivers/input/Kconfig.it8xxx2 @@ -0,0 +1,10 @@ +# Copyright (c) 2021 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_ITE_IT8XXX2_KBD + bool "ITE keyboard scanning driver" + default y + depends on DT_HAS_ITE_IT8XXX2_KBD_ENABLED + select INPUT_KBD_MATRIX + help + This option enables the ITE keyboard scan driver. diff --git a/drivers/input/Kconfig.kbd_matrix b/drivers/input/Kconfig.kbd_matrix new file mode 100644 index 000000000000000..4532b270f9c0353 --- /dev/null +++ b/drivers/input/Kconfig.kbd_matrix @@ -0,0 +1,60 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_KBD_MATRIX + bool + depends on MULTITHREADING + help + Enable library used for keyboard matrix drivers. + +if INPUT_KBD_MATRIX + +config INPUT_KBD_MATRIX_THREAD_STACK_SIZE + int "Stack size for the keyboard matrix thread" + default 1024 + 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 e6936aeb2eeaab8..07c2e301944bdb2 100644 --- a/drivers/input/Kconfig.npcx +++ b/drivers/input/Kconfig.npcx @@ -3,41 +3,19 @@ # Copyright (c) 2022 Nuvoton Technology Corporation. # SPDX-License-Identifier: Apache-2.0 -menuconfig INPUT_NPCX_KBD +config INPUT_NPCX_KBD bool "Nuvoton NPCX embedded controller (EC) keyboard scan driver" default y depends on DT_HAS_NUVOTON_NPCX_KBD_ENABLED - select MULTITHREADING + select INPUT_KBD_MATRIX help This option enables the keyboard scan driver for NPCX family of processors. -if INPUT_NPCX_KBD - -config INPUT_NPCX_KBD_POLL_PERIOD_MS - int "Keyscan NPCX Poll Period" - default 5 - help - Defines the poll period in msecs between between matrix scans. - config INPUT_NPCX_KBD_KSO_HIGH_DRIVE bool "Select quasi-bidirectional buffers for KSO pins" default y + depends on INPUT_NPCX_KBD help Select quasi-bidirectional buffers for KSO pins to reduce the low-to-high transition time. - -config INPUT_NPCX_KBD_POLL_COL_OUTPUT_SETTLE_TIME_US - int "keyboard matrix poll column output settle time" - default 50 - help - Delay (us) between setting column output and waiting for it - to settle - -config INPUT_NPCX_KBD_THREAD_STACK_SIZE - int "Stack size for the kscan thread" - default 1024 - help - Size of the stack used for the kscan thread. - -endif # INPUT_NPCX_KBD diff --git a/drivers/input/input_analog_axis.c b/drivers/input/input_analog_axis.c new file mode 100644 index 000000000000000..ace693ddf585c39 --- /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 000000000000000..3d29af8b96fec41 --- /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 6cebddf337903f6..9409deb045a5e40 100644 --- a/drivers/input/input_cst816s.c +++ b/drivers/input/input_cst816s.c @@ -173,12 +173,11 @@ static void cst816s_chip_reset(const struct device *dev) int ret; if (gpio_is_ready_dt(&config->rst_gpio)) { - ret = gpio_pin_configure_dt(&config->rst_gpio, GPIO_OUTPUT_INACTIVE); + ret = gpio_pin_configure_dt(&config->rst_gpio, GPIO_OUTPUT_ACTIVE); if (ret < 0) { LOG_ERR("Could not configure reset GPIO pin"); return; } - gpio_pin_set_dt(&config->rst_gpio, 1); k_msleep(CST816S_RESET_DELAY); gpio_pin_set_dt(&config->rst_gpio, 0); k_msleep(CST816S_WAIT_DELAY); diff --git a/drivers/input/input_esp32_touch_sensor.c b/drivers/input/input_esp32_touch_sensor.c new file mode 100644 index 000000000000000..9f6858da1c7f893 --- /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 00649ee4e71b46c..fea0aa26c11a166 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. */ @@ -153,8 +159,8 @@ static int ft5336_init(const struct device *dev) k_work_init(&data->work, ft5336_work_handler); if (config->reset_gpio.port != NULL) { - /* Enable reset GPIO, and pull down */ - r = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); + /* Enable reset GPIO and assert reset */ + r = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_ACTIVE); if (r < 0) { LOG_ERR("Could not enable reset GPIO"); return r; @@ -166,14 +172,13 @@ static int ft5336_init(const struct device *dev) */ k_sleep(K_MSEC(5)); /* Pull reset pin high to complete reset sequence */ - r = gpio_pin_set_dt(&config->reset_gpio, 1); + r = gpio_pin_set_dt(&config->reset_gpio, 0); if (r < 0) { return r; } } #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 new file mode 100644 index 000000000000000..4c82e132f0708f8 --- /dev/null +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -0,0 +1,338 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT gpio_kbd_matrix + +#include +#include + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(input_gpio_kbd_matrix, CONFIG_INPUT_LOG_LEVEL); + +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 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, + struct gpio_kbd_matrix_data); + +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; + uint32_t state; + + if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE) { + state = 0; + } else if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL) { + state = BIT_MASK(common->col_size); + } else { + 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 (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); + } + } + } + + data->last_col_state = state; +} + +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; + 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]; + + if (gpio_pin_get_dt(gpio)) { + val |= BIT(i); + } + } + + 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; + 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) { + LOG_ERR("Pin %d interrupt configuration failed: %d", i, ret); + return; + } + } +} + +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; + + for (i = 0; i < common->col_size; i++) { + const struct gpio_dt_spec *gpio = &cfg->col_gpio[i]; + + if (!gpio_is_ready_dt(gpio)) { + LOG_ERR("%s is not ready", gpio->port->name); + return -ENODEV; + } + + 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; + } + } + + for (i = 0; i < common->row_size; i++) { + const struct gpio_dt_spec *gpio = &cfg->row_gpio[i]; + struct gpio_callback *gpio_cb; + + if (!gpio_is_ready_dt(gpio)) { + LOG_ERR("%s is not ready", gpio->port->name); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(gpio, GPIO_INPUT); + if (ret != 0) { + LOG_ERR("Pin %d configuration failed: %d", i, ret); + return ret; + } + + 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) { + LOG_ERR("Could not set gpio callback"); + return ret; + } + } + + 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 0; +} + +static const struct input_kbd_matrix_api gpio_kbd_matrix_api = { + .drive_column = gpio_kbd_matrix_drive_column, + .read_row = gpio_kbd_matrix_read_row, + .set_detect_mode = gpio_kbd_matrix_set_detect_mode, +}; + +#define INPUT_GPIO_KBD_MATRIX_INIT(n) \ + BUILD_ASSERT(DT_INST_PROP_LEN(n, col_gpios) <= 32, "invalid col-size"); \ + \ + INPUT_KBD_MATRIX_DT_INST_DEFINE_ROW_COL( \ + n, DT_INST_PROP_LEN(n, row_gpios), DT_INST_PROP_LEN(n, col_gpios)); \ + \ + 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, (,)) \ + }; \ + static const struct gpio_dt_spec gpio_kbd_matrix_col_gpio_##n[DT_INST_PROP_LEN( \ + 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( \ + n, &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, \ + .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; \ + \ + DEVICE_DT_INST_DEFINE(n, gpio_kbd_matrix_init, NULL, \ + &gpio_kbd_matrix_data_##n, &gpio_kbd_matrix_cfg_##n, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(INPUT_GPIO_KBD_MATRIX_INIT) diff --git a/drivers/input/input_gpio_keys.c b/drivers/input/input_gpio_keys.c index bf157d594719a2d..cd277c19fdc9e5d 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 2b1a3578b349b62..66066d32acc72a0 100644 --- a/drivers/input/input_gpio_qdec.c +++ b/drivers/input/input_gpio_qdec.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include LOG_MODULE_REGISTER(input_gpio_qdec, CONFIG_INPUT_LOG_LEVEL); @@ -20,8 +22,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 +41,7 @@ struct gpio_qdec_data { struct k_work event_work; struct k_work_delayable idle_work; struct gpio_callback gpio_cb; + atomic_t polling; }; /* Positive transitions */ @@ -49,18 +56,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; } @@ -79,6 +163,11 @@ static void gpio_qdec_sample_timer_timeout(struct k_timer *timer) 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 +217,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 +224,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 +233,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 +252,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 +267,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,9 +278,28 @@ 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); LOG_DBG("Device %s initialized", dev->name); @@ -225,10 +310,31 @@ static int gpio_qdec_init(const struct device *dev) 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), \ diff --git a/drivers/input/input_gt911.c b/drivers/input/input_gt911.c index f62be5f1e0fbe3b..01699c06377128e 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) @@ -230,7 +230,7 @@ static int gt911_init(const struct device *dev) return -ENODEV; } - r = gpio_pin_configure_dt(&config->rst_gpio, GPIO_OUTPUT_INACTIVE); + r = gpio_pin_configure_dt(&config->rst_gpio, GPIO_OUTPUT_ACTIVE); if (r < 0) { LOG_ERR("Could not configure reset GPIO pin"); return r; @@ -253,10 +253,10 @@ static int gt911_init(const struct device *dev) /* Delay at least 10 ms after power on before we configure gt911 */ k_sleep(K_MSEC(20)); /* reset the device and confgiure the addr mode0 */ - gpio_pin_set_dt(&config->rst_gpio, 0); + gpio_pin_set_dt(&config->rst_gpio, 1); /* hold down at least 1us, 1ms here */ k_sleep(K_MSEC(1)); - gpio_pin_set_dt(&config->rst_gpio, 1); + gpio_pin_set_dt(&config->rst_gpio, 0); /* hold down at least 5ms. This is the point the INT pin must be low. */ k_sleep(K_MSEC(5)); /* hold down 50ms to make sure the address available */ diff --git a/drivers/input/input_ite_it8xxx2_kbd.c b/drivers/input/input_ite_it8xxx2_kbd.c new file mode 100644 index 000000000000000..5e62e6ee32e1a43 --- /dev/null +++ b/drivers/input/input_ite_it8xxx2_kbd.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2021 ITE Corporation. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ite_it8xxx2_kbd + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(input_ite_it8xxx2_kbd); + +#define KEYBOARD_KSI_PIN_COUNT IT8XXX2_DT_INST_WUCCTRL_LEN(0) + +struct it8xxx2_kbd_wuc_map_cfg { + /* WUC control device structure */ + const struct device *wucs; + /* WUC pin mask */ + uint8_t mask; +}; + +struct it8xxx2_kbd_config { + struct input_kbd_matrix_common_config common; + /* Keyboard scan controller base address */ + struct kscan_it8xxx2_regs *base; + /* Keyboard scan input (KSI) wake-up irq */ + int irq; + /* KSI[7:0] wake-up input source configuration list */ + const struct it8xxx2_kbd_wuc_map_cfg *wuc_map_list; + /* KSI[7:0]/KSO[17:0] keyboard scan alternate configuration */ + const struct pinctrl_dev_config *pcfg; + /* KSO16 GPIO cells */ + struct gpio_dt_spec kso16_gpios; + /* KSO17 GPIO cells */ + struct gpio_dt_spec kso17_gpios; +}; + +struct it8xxx2_kbd_data { + struct input_kbd_matrix_common_data common; + /* KSI[7:0] wake-up interrupt status mask */ + uint8_t ksi_pin_mask; +}; + +INPUT_KBD_STRUCT_CHECK(struct it8xxx2_kbd_config, struct it8xxx2_kbd_data); + +static void it8xxx2_kbd_drive_column(const struct device *dev, int col) +{ + const struct it8xxx2_kbd_config *const config = dev->config; + const struct input_kbd_matrix_common_config *common = &config->common; + struct kscan_it8xxx2_regs *const inst = config->base; + int mask; + + /* Tri-state all outputs */ + if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE) { + mask = 0x3ffff; + /* Assert all outputs */ + } else if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL) { + mask = 0; + /* Assert a single output */ + } else { + mask = 0x3ffff ^ BIT(col); + } + + /* Set KSO[17:0] output data */ + inst->KBS_KSOL = (uint8_t) (mask & 0xff); + inst->KBS_KSOH1 = (uint8_t) ((mask >> 8) & 0xff); + if (common->col_size > 16) { + inst->KBS_KSOH2 = (uint8_t) ((mask >> 16) & 0xff); + } +} + +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; + + /* Bits are active-low, so toggle it (return 1 means key pressed) */ + return (inst->KBS_KSI ^ 0xff); +} + +static void it8xxx2_kbd_isr(const struct device *dev) +{ + const struct it8xxx2_kbd_config *const config = dev->config; + struct it8xxx2_kbd_data *data = dev->data; + + /* + * W/C wakeup interrupt status of KSI[7:0] pins + * + * NOTE: We want to clear the status as soon as possible, + * so clear KSI[7:0] pins at a time. + */ + it8xxx2_wuc_clear_status(config->wuc_map_list[0].wucs, + data->ksi_pin_mask); + + /* W/C interrupt status of KSI[7:0] pins */ + ite_intc_isr_clear(config->irq); + + input_kbd_matrix_poll_start(dev); +} + +static void it8xxx2_kbd_set_detect_mode(const struct device *dev, bool enable) +{ + const struct it8xxx2_kbd_config *const config = dev->config; + struct it8xxx2_kbd_data *data = dev->data; + + if (enable) { + /* + * W/C wakeup interrupt status of KSI[7:0] pins + * + * NOTE: We want to clear the status as soon as possible, + * so clear KSI[7:0] pins at a time. + */ + it8xxx2_wuc_clear_status(config->wuc_map_list[0].wucs, + data->ksi_pin_mask); + + /* W/C interrupt status of KSI[7:0] pins */ + ite_intc_isr_clear(config->irq); + + irq_enable(config->irq); + } else { + irq_disable(config->irq); + } +} + +static int it8xxx2_kbd_init(const struct device *dev) +{ + const struct it8xxx2_kbd_config *const config = dev->config; + const struct input_kbd_matrix_common_config *common = &config->common; + struct it8xxx2_kbd_data *data = dev->data; + struct kscan_it8xxx2_regs *const inst = config->base; + int status; + + /* Disable wakeup and interrupt of KSI pins before configuring */ + it8xxx2_kbd_set_detect_mode(dev, false); + + if (common->col_size > 16) { + /* + * For KSO[16] and KSO[17]: + * 1.GPOTRC: + * Bit[x] = 1b: Enable the open-drain mode of KSO pin + * 2.GPCRCx: + * Bit[7:6] = 00b: Select alternate KSO function + * Bit[2] = 1b: Enable the internal pull-up of KSO pin + * + * NOTE: Set input temporarily for gpio_pin_configure(), after + * that pinctrl_apply_state() set to alternate function + * immediately. + */ + gpio_pin_configure_dt(&config->kso16_gpios, GPIO_INPUT); + gpio_pin_configure_dt(&config->kso17_gpios, GPIO_INPUT); + } + /* + * Enable the internal pull-up and kbs mode of the KSI[7:0] pins. + * Enable the internal pull-up and kbs mode of the KSO[15:0] pins. + * Enable the open-drain mode of the KSO[17:0] pins. + */ + status = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (status < 0) { + LOG_ERR("Failed to configure KSI[7:0] and KSO[17:0] pins"); + return status; + } + + /* KSO[17:0] pins output low */ + inst->KBS_KSOL = 0x00; + inst->KBS_KSOH1 = 0x00; + if (common->col_size > 16) { + inst->KBS_KSOH2 = 0x00; + } + + for (int i = 0; i < KEYBOARD_KSI_PIN_COUNT; i++) { + /* Select wakeup interrupt falling-edge triggered of KSI[7:0] pins */ + it8xxx2_wuc_set_polarity(config->wuc_map_list[i].wucs, + config->wuc_map_list[i].mask, + WUC_TYPE_EDGE_FALLING); + /* W/C wakeup interrupt status of KSI[7:0] pins */ + it8xxx2_wuc_clear_status(config->wuc_map_list[i].wucs, + config->wuc_map_list[i].mask); + /* Enable wakeup interrupt of KSI[7:0] pins */ + it8xxx2_wuc_enable(config->wuc_map_list[i].wucs, + config->wuc_map_list[i].mask); + + /* + * We want to clear KSI[7:0] pins status at a time when wakeup + * interrupt fire, so gather the KSI[7:0] pin mask value here. + */ + if (config->wuc_map_list[i].wucs != config->wuc_map_list[0].wucs) { + LOG_ERR("KSI%d pin isn't in the same wuc node!", i); + } + data->ksi_pin_mask |= config->wuc_map_list[i].mask; + } + + /* W/C interrupt status of KSI[7:0] pins */ + ite_intc_isr_clear(config->irq); + + irq_connect_dynamic(DT_INST_IRQN(0), 0, + (void (*)(const void *))it8xxx2_kbd_isr, + (const void *)dev, 0); + + return input_kbd_matrix_common_init(dev); +} + +static const struct it8xxx2_kbd_wuc_map_cfg + it8xxx2_kbd_wuc[IT8XXX2_DT_INST_WUCCTRL_LEN(0)] = IT8XXX2_DT_WUC_ITEMS_LIST(0); + +PINCTRL_DT_INST_DEFINE(0); + +INPUT_KBD_MATRIX_DT_INST_DEFINE(0); + +static const struct input_kbd_matrix_api it8xxx2_kbd_api = { + .drive_column = it8xxx2_kbd_drive_column, + .read_row = it8xxx2_kbd_read_row, + .set_detect_mode = it8xxx2_kbd_set_detect_mode, +}; + +static const struct it8xxx2_kbd_config it8xxx2_kbd_cfg_0 = { + .common = INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT(0, &it8xxx2_kbd_api), + .base = (struct kscan_it8xxx2_regs *)DT_INST_REG_ADDR_BY_IDX(0, 0), + .irq = DT_INST_IRQN(0), + .wuc_map_list = it8xxx2_kbd_wuc, + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), + .kso16_gpios = GPIO_DT_SPEC_INST_GET(0, kso16_gpios), + .kso17_gpios = GPIO_DT_SPEC_INST_GET(0, kso17_gpios), +}; + +static struct it8xxx2_kbd_data it8xxx2_kbd_data_0; + +DEVICE_DT_INST_DEFINE(0, &it8xxx2_kbd_init, NULL, + &it8xxx2_kbd_data_0, &it8xxx2_kbd_cfg_0, + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); + +BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, + "only one ite,it8xxx2-kbd compatible node can be supported"); +BUILD_ASSERT(IN_RANGE(DT_INST_PROP(0, row_size), 1, 8), "invalid row-size"); +BUILD_ASSERT(IN_RANGE(DT_INST_PROP(0, col_size), 16, 18), "invalid col-size"); diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c new file mode 100644 index 000000000000000..095a9bb0cfd50f2 --- /dev/null +++ b/drivers/input/input_kbd_matrix.c @@ -0,0 +1,346 @@ +/* + * Copyright 2019 Intel Corporation + * Copyright 2022 Nuvoton Technology Corporation. + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(input_kbd_matrix, CONFIG_INPUT_LOG_LEVEL); + +void input_kbd_matrix_poll_start(const struct device *dev) +{ + struct input_kbd_matrix_common_data *data = dev->data; + + k_sem_give(&data->poll_lock); +} + +static bool input_kbd_matrix_ghosting(const struct device *dev) +{ + const struct input_kbd_matrix_common_config *cfg = dev->config; + const kbd_row_t *state = cfg->matrix_new_state; + + /* + * Matrix keyboard designs are suceptible to ghosting. + * An extra key appears to be pressed when 3 keys belonging to the same + * block are pressed. For example, in the following block: + * + * . . w . q . + * . . . . . . + * . . . . . . + * . . m . a . + * + * the key m would look as pressed if the user pressed keys w, q and a + * simultaneously. A block can also be formed, with not adjacent + * columns. + */ + for (int c = 0; c < cfg->col_size; c++) { + if (!state[c]) { + continue; + } + + for (int c_next = c + 1; c_next < cfg->col_size; c_next++) { + /* + * We AND the columns to detect a "block". This is an + * indication of ghosting, due to current flowing from + * a key which was never pressed. In our case, current + * flowing is a bit set to 1 as we flipped the bits + * when the matrix was scanned. Now we OR the colums + * using z&(z-1) which is non-zero only if z has more + * than one bit set. + */ + kbd_row_t common_row_bits = state[c] & state[c_next]; + + if (common_row_bits & (common_row_bits - 1)) { + return true; + } + } + } + + 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; + kbd_row_t row; + kbd_row_t key_event = 0U; + + for (int col = 0; col < cfg->col_size; 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); + + if (cfg->actual_key_mask != NULL) { + row &= cfg->actual_key_mask[col]; + } + + cfg->matrix_new_state[col] = row; + key_event |= row; + } + + input_kbd_matrix_drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE); + + return key_event != 0U; +} + +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; + kbd_row_t *matrix_new_state = cfg->matrix_new_state; + uint32_t cycles_now; + kbd_row_t row_changed; + kbd_row_t deb_col; + + cycles_now = k_cycle_get_32(); + + data->scan_clk_cycle[data->scan_cycles_idx] = cycles_now; + + /* + * The intent of this loop is to gather information related to key + * changes. + */ + for (int c = 0; c < cfg->col_size; c++) { + /* Check if there was an update from the previous scan */ + row_changed = matrix_new_state[c] ^ cfg->matrix_previous_state[c]; + + if (!row_changed) { + continue; + } + + for (int r = 0; r < cfg->row_size; r++) { + uint8_t cyc_idx = c * cfg->row_size + r; + + /* + * Index all they keys that changed for each row in + * order to debounce each key in terms of it + */ + if (row_changed & BIT(r)) { + cfg->scan_cycle_idx[cyc_idx] = data->scan_cycles_idx; + } + } + + cfg->matrix_unstable_state[c] |= row_changed; + cfg->matrix_previous_state[c] = matrix_new_state[c]; + } + + for (int c = 0; c < cfg->col_size; c++) { + deb_col = cfg->matrix_unstable_state[c]; + + if (!deb_col) { + continue; + } + + /* Debouncing for each row key occurs here */ + for (int r = 0; r < cfg->row_size; r++) { + 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)) { + continue; + } + + uint8_t cyc_idx = c * cfg->row_size + r; + uint8_t scan_cyc_idx = cfg->scan_cycle_idx[cyc_idx]; + uint32_t scan_clk_cycle = data->scan_clk_cycle[scan_cyc_idx]; + + /* Convert the clock cycle differences to usec */ + 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 (deb_t_us < (row_bit ? cfg->debounce_down_us : cfg->debounce_up_us)) { + /* Need more time to debounce */ + continue; + } + + 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) { + /* Key state did not change */ + continue; + } + + /* + * The current row has been debounced, therefore update + * the stable state. Then, proceed to notify the + * application about the keys pressed. + */ + cfg->matrix_stable_state[c] ^= mask; + + input_report_abs(dev, INPUT_ABS_X, c, false, K_FOREVER); + input_report_abs(dev, INPUT_ABS_Y, r, false, K_FOREVER); + input_report_key(dev, INPUT_BTN_TOUCH, row_bit, true, K_FOREVER); + } + } + + data->scan_cycles_idx = (data->scan_cycles_idx + 1) % INPUT_KBD_MATRIX_SCAN_OCURRENCES; +} + +static bool input_kbd_matrix_check_key_events(const struct device *dev) +{ + const struct input_kbd_matrix_common_config *cfg = dev->config; + bool key_pressed; + + /* Scan the matrix */ + key_pressed = input_kbd_matrix_scan(dev); + + for (int c = 0; c < cfg->col_size; c++) { + LOG_DBG("c=%2d u=" PRIkbdrow " p=" PRIkbdrow " n=" PRIkbdrow, + c, + cfg->matrix_unstable_state[c], + cfg->matrix_previous_state[c], + cfg->matrix_new_state[c]); + } + + /* Abort if ghosting is detected */ + if (cfg->ghostkey_check && input_kbd_matrix_ghosting(dev)) { + return key_pressed; + } + + input_kbd_matrix_update_state(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; + k_timepoint_t poll_time_end; + uint32_t current_cycles; + uint32_t cycles_diff; + uint32_t wait_period_us; + + 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 = input_kbd_matrix_poll_timeout(dev); + } else if (sys_timepoint_expired(poll_time_end)) { + break; + } + + /* + * Subtract the time invested from the sleep period in order to + * compensate for the time invested in debouncing a key + */ + current_cycles = k_cycle_get_32(); + cycles_diff = current_cycles - start_period_cycles; + wait_period_us = cfg->poll_period_us - k_cyc_to_us_floor32(cycles_diff); + + wait_period_us = CLAMP(wait_period_us, + USEC_PER_MSEC, cfg->poll_period_us); + + LOG_DBG("wait_period_us: %d", wait_period_us); + + /* Allow other threads to run while we sleep */ + k_usleep(wait_period_us); + } +} + +static void input_kbd_matrix_polling_thread(void *arg1, void *unused2, void *unused3) +{ + const struct device *dev = arg1; + const struct input_kbd_matrix_common_config *cfg = dev->config; + const struct input_kbd_matrix_api *api = cfg->api; + struct input_kbd_matrix_common_data *data = dev->data; + + ARG_UNUSED(unused2); + ARG_UNUSED(unused3); + + while (true) { + 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"); + + /* Disable interrupt of KSI pins and start polling */ + api->set_detect_mode(dev, false); + + input_kbd_matrix_poll(dev); + } +} + +int input_kbd_matrix_common_init(const struct device *dev) +{ + struct input_kbd_matrix_common_data *data = dev->data; + + k_sem_init(&data->poll_lock, 0, 1); + + k_thread_create(&data->thread, data->thread_stack, + K_KERNEL_STACK_SIZEOF(data->thread_stack), + input_kbd_matrix_polling_thread, (void *)dev, NULL, NULL, + 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 ff6f08e16761c01..7b2469d1d5f19f2 100644 --- a/drivers/input/input_npcx_kbd.c +++ b/drivers/input/input_npcx_kbd.c @@ -11,27 +11,20 @@ #include #include -#include +#include #include #include +#include +#include #include -#define LOG_LEVEL CONFIG_INPUT_LOG_LEVEL -LOG_MODULE_REGISTER(input_npcx_kbd); +LOG_MODULE_REGISTER(input_npcx_kbd, CONFIG_INPUT_LOG_LEVEL); -#define KEYBOARD_COLUMN_DRIVE_ALL -2 -#define KEYBOARD_COLUMN_DRIVE_NONE -1 - -/* Number of tracked scan times */ -#define SCAN_OCURRENCES 30U - -#define KSCAN_ROW_SIZE DT_INST_PROP(0, row_size) -#define KSCAN_COL_SIZE DT_INST_PROP(0, col_size) - -#define HAS_GHOSTING_ENABLED !DT_INST_PROP(0, no_ghostkey_check) +#define ROW_SIZE DT_INST_PROP(0, row_size) /* Driver config */ -struct input_npcx_kbd_config { +struct npcx_kbd_config { + struct input_kbd_matrix_common_config common; /* Keyboard scan controller base address */ struct kbs_reg *base; /* Clock configuration */ @@ -42,73 +35,59 @@ struct input_npcx_kbd_config { int irq; /* Size of keyboard inputs-wui mapping array */ int wui_size; - uint8_t row_size; - uint8_t col_size; - uint32_t deb_time_press; - uint32_t deb_time_rel; /* Mapping table between keyboard inputs and wui */ struct npcx_wui wui_maps[]; }; -struct input_npcx_kbd_data { - int64_t poll_timeout_us; - uint32_t poll_period_us; - uint8_t matrix_stable_state[KSCAN_COL_SIZE]; - uint8_t matrix_unstable_state[KSCAN_COL_SIZE]; - uint8_t matrix_previous_state[KSCAN_COL_SIZE]; - uint8_t matrix_new_state[KSCAN_COL_SIZE]; - /* Index in to the scan_clock_cycle to indicate start of debouncing */ - uint8_t scan_cycle_idx[KSCAN_COL_SIZE * KSCAN_ROW_SIZE]; - struct miwu_callback ksi_callback[KSCAN_ROW_SIZE]; - /* Track previous "elapsed clock cycles" per matrix scan. This - * is used to calculate the debouncing time for every key - */ - uint8_t scan_clk_cycle[SCAN_OCURRENCES]; - struct k_sem poll_lock; - uint8_t scan_cycles_idx; - struct k_thread thread; - - K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_INPUT_NPCX_KBD_THREAD_STACK_SIZE); +struct npcx_kbd_data { + struct input_kbd_matrix_common_data common; + struct miwu_callback ksi_callback[ROW_SIZE]; }; +INPUT_KBD_STRUCT_CHECK(struct npcx_kbd_config, struct npcx_kbd_data); + /* Keyboard scan local functions */ -static void input_npcx_kbd_ksi_isr(const struct device *dev, struct npcx_wui *wui) +static void npcx_kbd_ksi_isr(const struct device *dev, struct npcx_wui *wui) { ARG_UNUSED(wui); - struct input_npcx_kbd_data *const data = dev->data; - k_sem_give(&data->poll_lock); + input_kbd_matrix_poll_start(dev); } -static int input_npcx_kbd_resume_detection(const struct device *dev, bool resume) +static void npcx_kbd_set_detect_mode(const struct device *dev, bool enabled) { - const struct input_npcx_kbd_config *const config = dev->config; + 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]); + } - if (resume) { irq_enable(config->irq); } else { irq_disable(config->irq); } - - return 0; } -static int input_npcx_kbd_drive_column(const struct device *dev, int col) +static void npcx_kbd_drive_column(const struct device *dev, int col) { - const struct input_npcx_kbd_config *config = dev->config; + 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; uint32_t mask; - if (col >= config->col_size) { - return -EINVAL; + if (col >= common->col_size) { + LOG_ERR("invalid column: %d", col); + return; } - if (col == KEYBOARD_COLUMN_DRIVE_NONE) { + if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE) { /* Drive all lines to high: key detection is disabled */ mask = ~0; - } else if (col == KEYBOARD_COLUMN_DRIVE_ALL) { + } else if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL) { /* Drive all lines to low for detection any key press */ - mask = ~(BIT(config->col_size) - 1); + mask = ~BIT_MASK(common->col_size); } else { /* * Drive one line to low for determining which key's state @@ -121,278 +100,27 @@ static int input_npcx_kbd_drive_column(const struct device *dev, int col) inst->KBSOUT0 = (mask & 0xFFFF); inst->KBSOUT1 = ((mask >> 16) & 0x03); - - return 0; } -static int input_npcx_kbd_read_row(const struct device *dev) +static kbd_row_t npcx_kbd_read_row(const struct device *dev) { - const struct input_npcx_kbd_config *config = dev->config; + 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; /* 1 means key pressed, otherwise means key released. */ - val = (~val & (BIT(config->row_size) - 1)); + val = ~val & BIT_MASK(common->row_size); return val; } -static bool is_matrix_ghosting(const struct device *dev, const uint8_t *state) -{ - const struct input_npcx_kbd_config *const config = dev->config; - - /* - * Matrix keyboard designs are suceptible to ghosting. - * An extra key appears to be pressed when 3 keys belonging to the same - * block are pressed. For example, in the following block: - * - * . . w . q . - * . . . . . . - * . . . . . . - * . . m . a . - * - * the key m would look as pressed if the user pressed keys w, q and a - * simultaneously. A block can also be formed, with not adjacent - * columns. - */ - for (int c = 0; c < config->col_size; c++) { - if (!state[c]) { - continue; - } - - for (int c_next = c + 1; c_next < config->col_size; c_next++) { - /* - * We AND the columns to detect a "block". This is an - * indication of ghosting, due to current flowing from - * a key which was never pressed. In our case, current - * flowing is a bit set to 1 as we flipped the bits - * when the matrix was scanned. Now we OR the colums - * 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]; - - if (common_row_bits & (common_row_bits - 1)) { - return true; - } - } - } - - return false; -} - -static bool read_keyboard_matrix(const struct device *dev, uint8_t *new_state) -{ - const struct input_npcx_kbd_config *const config = dev->config; - int row; - uint8_t key_event = 0U; - - for (int col = 0; col < config->col_size; col++) { - input_npcx_kbd_drive_column(dev, col); - - /* Allow the matrix to stabilize before reading it */ - k_busy_wait(CONFIG_INPUT_NPCX_KBD_POLL_COL_OUTPUT_SETTLE_TIME_US); - - row = input_npcx_kbd_read_row(dev); - new_state[col] = row & 0xFF; - key_event |= row; - } - - input_npcx_kbd_drive_column(dev, KEYBOARD_COLUMN_DRIVE_NONE); - - return key_event != 0U; -} - -static void update_matrix_state(const struct device *dev, uint8_t *matrix_new_state) -{ - const struct input_npcx_kbd_config *const config = dev->config; - struct input_npcx_kbd_data *const data = dev->data; - uint32_t cycles_now = k_cycle_get_32(); - uint8_t row_changed = 0U; - uint8_t deb_col; - - data->scan_clk_cycle[data->scan_cycles_idx] = cycles_now; - - /* - * The intent of this loop is to gather information related to key - * changes. - */ - for (int c = 0; c < config->col_size; c++) { - /* Check if there was an update from the previous scan */ - row_changed = matrix_new_state[c] ^ data->matrix_previous_state[c]; - - if (!row_changed) { - continue; - } - - for (int r = 0; r < config->row_size; r++) { - uint8_t cyc_idx = c * config->row_size + r; - - /* - * Index all they keys that changed for each row in - * order to debounce each key in terms of it - */ - if (row_changed & BIT(r)) { - data->scan_cycle_idx[cyc_idx] = data->scan_cycles_idx; - } - } - - data->matrix_unstable_state[c] |= row_changed; - data->matrix_previous_state[c] = matrix_new_state[c]; - } - - for (int c = 0; c < config->col_size; c++) { - deb_col = data->matrix_unstable_state[c]; - - if (!deb_col) { - continue; - } - - /* Debouncing for each row key occurs here */ - for (int r = 0; r < config->row_size; r++) { - uint8_t mask = BIT(r); - uint8_t row_bit = matrix_new_state[c] & mask; - - /* Continue if we already debounce a key */ - if (!(deb_col & mask)) { - continue; - } - - uint8_t cyc_idx = c * config->row_size + r; - /* Convert the clock cycle differences to usec */ - uint32_t debt = k_cyc_to_us_floor32( - cycles_now - data->scan_clk_cycle[data->scan_cycle_idx[cyc_idx]]); - - /* Does the key requires more time to be debounced? */ - if (debt < (row_bit ? config->deb_time_press : config->deb_time_rel)) { - /* Need more time to debounce */ - continue; - } - - data->matrix_unstable_state[c] &= ~row_bit; - - /* Check if there was a change in the stable state */ - if ((data->matrix_stable_state[c] & mask) == row_bit) { - /* Key state did not change */ - continue; - } - - /* - * The current row has been debounced, therefore update - * the stable state. Then, proceed to notify the - * application about the keys pressed. - */ - data->matrix_stable_state[c] ^= mask; - - input_report_abs(dev, INPUT_ABS_X, c, false, K_FOREVER); - input_report_abs(dev, INPUT_ABS_Y, r, false, K_FOREVER); - input_report_key(dev, INPUT_BTN_TOUCH, row_bit, true, K_FOREVER); - } - } -} - -static bool check_key_events(const struct device *dev) -{ - const struct input_npcx_kbd_config *const config = dev->config; - struct input_npcx_kbd_data *const data = dev->data; - uint8_t *matrix_new_state = data->matrix_new_state; - bool key_pressed = false; - - if (++data->scan_cycles_idx >= SCAN_OCURRENCES) { - data->scan_cycles_idx = 0U; - } - - /* Scan the matrix */ - key_pressed = read_keyboard_matrix(dev, matrix_new_state); - - for (int c = 0; c < config->col_size; c++) { - LOG_DBG("U%x, P%x, N%x", data->matrix_unstable_state[c], - data->matrix_previous_state[c], matrix_new_state[c]); - } - - /* Abort if ghosting is detected */ - if (HAS_GHOSTING_ENABLED && is_matrix_ghosting(dev, matrix_new_state)) { - return key_pressed; - } - - update_matrix_state(dev, matrix_new_state); - - return key_pressed; -} - -static void kbd_matrix_poll(const struct device *dev) -{ - struct input_npcx_kbd_data *const data = dev->data; - k_timepoint_t poll_time_end = sys_timepoint_calc(K_USEC(data->poll_timeout_us)); - uint32_t current_cycles; - uint32_t cycles_diff; - uint32_t wait_period; - - while (true) { - uint32_t start_period_cycles = k_cycle_get_32(); - - if (check_key_events(dev)) { - poll_time_end = sys_timepoint_calc(K_USEC(data->poll_timeout_us)); - } else if (sys_timepoint_expired(poll_time_end)) { - break; - } - - /* - * Subtract the time invested from the sleep period in order to - * compensate for the time invested in debouncing a key - */ - current_cycles = k_cycle_get_32(); - cycles_diff = current_cycles - start_period_cycles; - wait_period = data->poll_period_us - k_cyc_to_us_floor32(cycles_diff); - - /* Override wait_period in case it is less than 1 ms */ - if (wait_period < USEC_PER_MSEC) { - wait_period = USEC_PER_MSEC; - } - - /* - * Wait period results in a larger number when current cycles - * counter wrap. In this case, the whole poll period is used - */ - if (wait_period > data->poll_period_us) { - LOG_DBG("wait_period: %u", wait_period); - - wait_period = data->poll_period_us; - } - - /* Allow other threads to run while we sleep */ - k_usleep(wait_period); - } -} - -static void kbd_matrix_polling_thread(const struct device *dev, void *dummy2, void *dummy3) -{ - struct input_npcx_kbd_data *const data = dev->data; - - ARG_UNUSED(dummy2); - ARG_UNUSED(dummy3); - - while (true) { - /* Enable interrupt of KSI pins */ - input_npcx_kbd_resume_detection(dev, true); - - input_npcx_kbd_drive_column(dev, KEYBOARD_COLUMN_DRIVE_ALL); - k_sem_take(&data->poll_lock, K_FOREVER); - LOG_DBG("Start KB scan"); - - /* Disable interrupt of KSI pins and start polling */ - input_npcx_kbd_resume_detection(dev, false); - - kbd_matrix_poll(dev); - } -} - -static void input_npcx_kbd_init_ksi_wui_callback(const struct device *dev, - struct miwu_callback *callback, - const struct npcx_wui *wui, - miwu_dev_callback_handler_t handler) +static void npcx_kbd_init_ksi_wui_callback(const struct device *dev, + struct miwu_callback *callback, + const struct npcx_wui *wui, + miwu_dev_callback_handler_t handler) { /* KSI signal which has no wake-up input source */ if (wui->table == NPCX_MIWU_TABLE_NONE) { @@ -404,15 +132,16 @@ static void input_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); } -static int input_npcx_kbd_init(const struct device *dev) +static int npcx_kbd_init(const struct device *dev) { const struct device *clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE); - const struct input_npcx_kbd_config *const config = dev->config; - struct input_npcx_kbd_data *const data = dev->data; + const struct npcx_kbd_config *const config = dev->config; + const struct input_kbd_matrix_common_config *common = &config->common; + struct npcx_kbd_data *const data = dev->data; struct kbs_reg *const inst = config->base; int ret; @@ -425,6 +154,7 @@ static int input_npcx_kbd_init(const struct device *dev) ret = clock_control_on(clk_dev, (clock_control_subsys_t)&config->clk_cfg); if (ret < 0) { LOG_ERR("Turn on KBSCAN clock fail %d", ret); + return -EIO; } /* Pull-up KBSIN0-7 internally */ @@ -450,13 +180,18 @@ static int input_npcx_kbd_init(const struct device *dev) } /* Drive all column lines to low for detection any key press */ - input_npcx_kbd_drive_column(dev, KEYBOARD_COLUMN_DRIVE_NONE); + npcx_kbd_drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE); + + if (common->row_size != ROW_SIZE) { + LOG_ERR("Unexpected ROW_SIZE: %d != %d", common->row_size, ROW_SIZE); + return -EINVAL; + } /* Configure wake-up input and callback for keyboard input signal */ - for (int i = 0; i < config->row_size; i++) { - input_npcx_kbd_init_ksi_wui_callback( + for (int i = 0; i < common->row_size; i++) { + npcx_kbd_init_ksi_wui_callback( dev, &data->ksi_callback[i], &config->wui_maps[i], - input_npcx_kbd_ksi_isr); + npcx_kbd_ksi_isr); } /* Configure pin-mux for keyboard scan device */ @@ -466,43 +201,36 @@ static int input_npcx_kbd_init(const struct device *dev) return ret; } - /* Initialize semaphore used by keyboard scan task and driver */ - k_sem_init(&data->poll_lock, 0, 1); - - /* Time figures are transformed from msec to usec */ - data->poll_period_us = (uint32_t)(CONFIG_INPUT_NPCX_KBD_POLL_PERIOD_MS * USEC_PER_MSEC); - data->poll_timeout_us = 100 * USEC_PER_MSEC; - - k_thread_create(&data->thread, data->thread_stack, - CONFIG_INPUT_NPCX_KBD_THREAD_STACK_SIZE, - (k_thread_entry_t)kbd_matrix_polling_thread, (void *)dev, NULL, NULL, - K_PRIO_COOP(4), 0, K_NO_WAIT); - - k_thread_name_set(&data->thread, "npcx-kbd"); - - return 0; + return input_kbd_matrix_common_init(dev); } PINCTRL_DT_INST_DEFINE(0); -static const struct input_npcx_kbd_config npcx_kbd_cfg = { +INPUT_KBD_MATRIX_DT_INST_DEFINE(0); + +static const struct input_kbd_matrix_api npcx_kbd_api = { + .drive_column = npcx_kbd_drive_column, + .read_row = npcx_kbd_read_row, + .set_detect_mode = npcx_kbd_set_detect_mode, +}; + +static const struct npcx_kbd_config npcx_kbd_cfg_0 = { + .common = INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT(0, &npcx_kbd_api), .base = (struct kbs_reg *)DT_INST_REG_ADDR(0), .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), .clk_cfg = NPCX_DT_CLK_CFG_ITEM(0), .irq = DT_INST_IRQN(0), .wui_size = NPCX_DT_WUI_ITEMS_LEN(0), .wui_maps = NPCX_DT_WUI_ITEMS_LIST(0), - .row_size = KSCAN_ROW_SIZE, - .col_size = KSCAN_COL_SIZE, - .deb_time_press = DT_INST_PROP(0, debounce_down_ms), - .deb_time_rel = DT_INST_PROP(0, debounce_up_ms), }; -static struct input_npcx_kbd_data npcx_kbd_data; +static struct npcx_kbd_data npcx_kbd_data_0; -DEVICE_DT_INST_DEFINE(0, input_npcx_kbd_init, NULL, - &npcx_kbd_data, &npcx_kbd_cfg, +DEVICE_DT_INST_DEFINE(0, npcx_kbd_init, NULL, + &npcx_kbd_data_0, &npcx_kbd_cfg_0, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "only one nuvoton,npcx-kbd compatible node can be supported"); +BUILD_ASSERT(IN_RANGE(DT_INST_PROP(0, row_size), 1, 8), "invalid row-size"); +BUILD_ASSERT(IN_RANGE(DT_INST_PROP(0, col_size), 1, 18), "invalid col-size"); diff --git a/drivers/input/linux_evdev.c b/drivers/input/linux_evdev.c new file mode 100644 index 000000000000000..55d412d567c2651 --- /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 000000000000000..be65ace084afc57 --- /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 000000000000000..153fa4ef6c2c827 --- /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 c4d92304cf0cf37..0df052e60456b12 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -32,11 +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_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 16ed7d4091072ad..a956afdf1f6024e 100644 --- a/drivers/interrupt_controller/Kconfig +++ b/drivers/interrupt_controller/Kconfig @@ -102,4 +102,8 @@ source "drivers/interrupt_controller/Kconfig.nxp_pint" source "drivers/interrupt_controller/Kconfig.vim" +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 caa9a93a284ea57..a047a832331dcf0 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 501cf0f4a46eedf..0aae541021efa05 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 000000000000000..b2dbc9b2afac5c3 --- /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 c1e16c7c1c554d6..d4f91a3fbd22f20 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.renesas_ra b/drivers/interrupt_controller/Kconfig.renesas_ra new file mode 100644 index 000000000000000..1105ea428b02f24 --- /dev/null +++ b/drivers/interrupt_controller/Kconfig.renesas_ra @@ -0,0 +1,9 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +config RENESAS_RA_ICU + bool "Renesas RA series interrupt controller unit" + default y + depends on DT_HAS_RENESAS_RA_INTERRUPT_CONTROLLER_UNIT_ENABLED + help + Renesas RA series interrupt controller unit diff --git a/drivers/interrupt_controller/intc_dw_ace.c b/drivers/interrupt_controller/intc_dw_ace.c index a876756a34ffb4d..9bda4bddcfa4b5c 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_eirq_nxp_s32.c b/drivers/interrupt_controller/intc_eirq_nxp_s32.c index 51631e0546c2717..2526aecad4ddd2f 100644 --- a/drivers/interrupt_controller/intc_eirq_nxp_s32.c +++ b/drivers/interrupt_controller/intc_eirq_nxp_s32.c @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_siul2_eirq + +#include #include #include #include @@ -124,23 +127,17 @@ static int eirq_nxp_s32_init(const struct device *dev) return 0; } -#define EIRQ_NXP_S32_NODE(n) DT_NODELABEL(eirq##n) - #define EIRQ_NXP_S32_CALLBACK(line, n) \ void nxp_s32_icu_##n##_eirq_line_##line##_callback(void) \ { \ - const struct device *dev = DEVICE_DT_GET(EIRQ_NXP_S32_NODE(n)); \ - \ - eirq_nxp_s32_callback(dev, line); \ + eirq_nxp_s32_callback(DEVICE_DT_INST_GET(n), line); \ } #define EIRQ_NXP_S32_CHANNEL_CONFIG(idx, n) \ { \ .hwChannel = idx, \ - .digFilterEn = DT_PROP_OR(DT_CHILD(EIRQ_NXP_S32_NODE(n), line_##idx), \ - filter_enable, 0), \ - .maxFilterCnt = DT_PROP_OR(DT_CHILD(EIRQ_NXP_S32_NODE(n), line_##idx), \ - filter_counter, 0), \ + .digFilterEn = DT_INST_PROP_OR(DT_CHILD(n, line_##idx), filter_enable, 0), \ + .maxFilterCnt = DT_INST_PROP_OR(DT_CHILD(n, line_##idx), filter_counter, 0), \ .intSel = SIUL2_ICU_IRQ, \ .intEdgeSel = SIUL2_ICU_DISABLE, \ .callback = NULL, \ @@ -155,8 +152,7 @@ static int eirq_nxp_s32_init(const struct device *dev) #define EIRQ_NXP_S32_INSTANCE_CONFIG(n) \ static const Siul2_Icu_Ip_InstanceConfigType eirq_##n##_instance_nxp_s32_cfg = { \ - .intFilterClk = DT_PROP_OR(EIRQ_NXP_S32_NODE(n), \ - filter_prescaler, (0)), \ + .intFilterClk = DT_INST_PROP_OR(n, filter_prescaler, 0), \ .altIntFilterClk = 0U, \ } @@ -176,42 +172,45 @@ static int eirq_nxp_s32_init(const struct device *dev) #define _EIRQ_NXP_S32_IRQ_NAME(name) DT_CAT3(SIUL2_EXT_IRQ_, name, _ISR) #define EIRQ_NXP_S32_IRQ_NAME(idx, n) \ - COND_CODE_1(DT_NODE_HAS_PROP(EIRQ_NXP_S32_NODE(n), interrupt_names), \ - (_EIRQ_NXP_S32_IRQ_NAME( \ - DT_STRING_TOKEN_BY_IDX(EIRQ_NXP_S32_NODE(n), interrupt_names, idx))), \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, interrupt_names), \ + (_EIRQ_NXP_S32_IRQ_NAME(DT_INST_STRING_TOKEN_BY_IDX(n, interrupt_names, idx))), \ (DT_CAT3(SIUL2_, n, _ICU_EIRQ_SINGLE_INT_HANDLER))) #define _EIRQ_NXP_S32_IRQ_CONFIG(idx, n) \ do { \ - IRQ_CONNECT(DT_IRQ_BY_IDX(EIRQ_NXP_S32_NODE(n), idx, irq), \ - DT_IRQ_BY_IDX(EIRQ_NXP_S32_NODE(n), idx, priority), \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, idx, irq), \ + DT_INST_IRQ_BY_IDX(n, idx, priority), \ EIRQ_NXP_S32_IRQ_NAME(idx, n), \ - DEVICE_DT_GET(EIRQ_NXP_S32_NODE(n)), \ - COND_CODE_1(CONFIG_GIC, \ - (DT_IRQ_BY_IDX(EIRQ_NXP_S32_NODE(n), idx, flags)), \ - (0))); \ - irq_enable(DT_IRQ_BY_IDX(EIRQ_NXP_S32_NODE(n), idx, irq)); \ + DEVICE_DT_INST_GET(n), \ + COND_CODE_1(CONFIG_GIC, (DT_INST_IRQ_BY_IDX(n, idx, flags)), (0))); \ + irq_enable(DT_INST_IRQ_BY_IDX(n, idx, irq)); \ } while (false); #define EIRQ_NXP_S32_IRQ_CONFIG(n) \ - LISTIFY(DT_NUM_IRQS(EIRQ_NXP_S32_NODE(n)), _EIRQ_NXP_S32_IRQ_CONFIG, (), n) + LISTIFY(DT_NUM_IRQS(DT_DRV_INST(n)), _EIRQ_NXP_S32_IRQ_CONFIG, (), n) + +#define EIRQ_NXP_S32_HW_INSTANCE_CHECK(i, n) \ + (((DT_REG_ADDR(DT_INST_PARENT(n))) == IP_SIUL2_##i##_BASE) ? i : 0) + +#define EIRQ_NXP_S32_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET SIUL2_INSTANCE_COUNT, EIRQ_NXP_S32_HW_INSTANCE_CHECK, (|), n) #define EIRQ_NXP_S32_INIT_DEVICE(n) \ EIRQ_NXP_S32_CONFIG(n) \ - PINCTRL_DT_DEFINE(EIRQ_NXP_S32_NODE(n)); \ + PINCTRL_DT_INST_DEFINE(n); \ static const struct eirq_nxp_s32_config eirq_nxp_s32_conf_##n = { \ - .instance = n, \ - .disr0 = (mem_addr_t)DT_REG_ADDR_BY_NAME(EIRQ_NXP_S32_NODE(n), disr0), \ - .direr0 = (mem_addr_t)DT_REG_ADDR_BY_NAME(EIRQ_NXP_S32_NODE(n), direr0), \ + .instance = EIRQ_NXP_S32_HW_INSTANCE(n), \ + .disr0 = (mem_addr_t)DT_INST_REG_ADDR_BY_NAME(n, disr0), \ + .direr0 = (mem_addr_t)DT_INST_REG_ADDR_BY_NAME(n, direr0), \ .icu_cfg = (Siul2_Icu_Ip_ConfigType *)&eirq_##n##_nxp_s32_cfg, \ - .pincfg = PINCTRL_DT_DEV_CONFIG_GET(EIRQ_NXP_S32_NODE(n)) \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n) \ }; \ static struct eirq_nxp_s32_cb eirq_nxp_s32_cb_##n[NXP_S32_NUM_CHANNELS]; \ static struct eirq_nxp_s32_data eirq_nxp_s32_data_##n = { \ .cb = eirq_nxp_s32_cb_##n, \ }; \ static int eirq_nxp_s32_init##n(const struct device *dev); \ - DEVICE_DT_DEFINE(EIRQ_NXP_S32_NODE(n), \ + DEVICE_DT_INST_DEFINE(n, \ eirq_nxp_s32_init##n, \ NULL, \ &eirq_nxp_s32_data_##n, \ @@ -233,18 +232,4 @@ static int eirq_nxp_s32_init(const struct device *dev) return 0; \ } -#if DT_NODE_HAS_STATUS(EIRQ_NXP_S32_NODE(0), okay) -EIRQ_NXP_S32_INIT_DEVICE(0) -#endif - -#if DT_NODE_HAS_STATUS(EIRQ_NXP_S32_NODE(1), okay) -EIRQ_NXP_S32_INIT_DEVICE(1) -#endif - -#if DT_NODE_HAS_STATUS(EIRQ_NXP_S32_NODE(4), okay) -EIRQ_NXP_S32_INIT_DEVICE(4) -#endif - -#if DT_NODE_HAS_STATUS(EIRQ_NXP_S32_NODE(5), okay) -EIRQ_NXP_S32_INIT_DEVICE(5) -#endif +DT_INST_FOREACH_STATUS_OKAY(EIRQ_NXP_S32_INIT_DEVICE) diff --git a/drivers/interrupt_controller/intc_exti_stm32.c b/drivers/interrupt_controller/intc_exti_stm32.c index 064d23cae2077de..f5f8bdc7d6ec44f 100644 --- a/drivers/interrupt_controller/intc_exti_stm32.c +++ b/drivers/interrupt_controller/intc_exti_stm32.c @@ -73,8 +73,6 @@ void stm32_exti_enable(int line) void stm32_exti_disable(int line) { - z_stm32_hsem_lock(CFG_HW_EXTI_SEMID, HSEM_LOCK_DEFAULT_RETRY); - if (line < 32) { #if defined(CONFIG_SOC_SERIES_STM32H7X) && defined(CONFIG_CPU_CORTEX_M4) LL_C2_EXTI_DisableIT_0_31(BIT((uint32_t)line)); @@ -84,7 +82,6 @@ void stm32_exti_disable(int line) } else { __ASSERT_NO_MSG(line); } - z_stm32_hsem_unlock(CFG_HW_EXTI_SEMID); } /** diff --git a/drivers/interrupt_controller/intc_ioapic.c b/drivers/interrupt_controller/intc_ioapic.c index 41a6266a699a8ee..0748ddccf768247 100644 --- a/drivers/interrupt_controller/intc_ioapic.c +++ b/drivers/interrupt_controller/intc_ioapic.c @@ -89,7 +89,6 @@ DEVICE_MMIO_TOPLEVEL_STATIC(ioapic_regs, DT_DRV_INST(0)); static __pinned_bss uint32_t ioapic_rtes; #ifdef CONFIG_PM_DEVICE -#include #define BITS_PER_IRQ 4 #define IOAPIC_BITFIELD_HI_LO 0 @@ -126,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_loapic.c b/drivers/interrupt_controller/intc_loapic.c index 742ae530596e8af..c7faaa39cdb0a50 100644 --- a/drivers/interrupt_controller/intc_loapic.c +++ b/drivers/interrupt_controller/intc_loapic.c @@ -65,7 +65,6 @@ #define LOAPIC_SSPND_BITS_PER_IRQ 1 /* Just the one for enable disable*/ #define LOAPIC_SUSPEND_BITS_REQD (ROUND_UP((LOAPIC_IRQ_COUNT * LOAPIC_SSPND_BITS_PER_IRQ), 32)) #ifdef CONFIG_PM_DEVICE -#include __pinned_bss uint32_t loapic_suspend_buf[LOAPIC_SUSPEND_BITS_REQD / 32] = {0}; #endif diff --git a/drivers/interrupt_controller/intc_nuclei_eclic.S b/drivers/interrupt_controller/intc_nuclei_eclic.S new file mode 100644 index 000000000000000..b077d28175184dc --- /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 9f831e5653077f6..94f4d067ccbfcbd 100644 --- a/drivers/interrupt_controller/intc_nuclei_eclic.c +++ b/drivers/interrupt_controller/intc_nuclei_eclic.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include @@ -87,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)))) @@ -157,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 000000000000000..cd06b23854acff3 --- /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 42f6cbc1f069b16..f5f762e4aba9d60 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Jean-Paul Etienne + * Copyright (c) 2023 Meta * Contributors: 2018 Antmicro * * SPDX-License-Identifier: Apache-2.0 @@ -12,10 +13,14 @@ * for RISC-V processors */ +#include + +#include "sw_isr_common.h" + #include #include #include -#include +#include #include #include @@ -26,58 +31,203 @@ * 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 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 +#define PLIC_REG_MASK BIT_MASK(LOG2(PLIC_REG_SIZE)) + +#ifdef CONFIG_TEST_INTC_PLIC +#define INTC_PLIC_STATIC +#else +#define INTC_PLIC_STATIC static inline +#endif + +typedef void (*riscv_plic_irq_config_func_t)(void); +struct plic_config { + mem_addr_t prio; + mem_addr_t irq_en; + mem_addr_t reg; + mem_addr_t trig; + uint32_t max_prio; + uint32_t num_irqs; + riscv_plic_irq_config_func_t irq_config_func; +}; -#define PLIC_MAX_PRIO DT_INST_PROP(0, riscv_max_priority) -#define PLIC_PRIO (PLIC_BASE_ADDR(0) + PLIC_REG_PRIO_OFFSET) -#define PLIC_IRQ_EN (PLIC_BASE_ADDR(0) + PLIC_REG_IRQ_EN_OFFSET) -#define PLIC_REG (PLIC_BASE_ADDR(0) + PLIC_REG_REGS_OFFSET) +struct plic_stats { + uint16_t *const irq_count; + const int irq_count_len; +}; -#define PLIC_IRQS (CONFIG_NUM_IRQS - CONFIG_2ND_LVL_ISR_TBL_OFFSET) -#define PLIC_EN_SIZE ((PLIC_IRQS >> 5) + 1) +struct plic_data { + struct plic_stats stats; +}; -#define PLIC_EDGE_TRIG_TYPE (PLIC_BASE_ADDR(0) + PLIC_REG_TRIG_TYPE_OFFSET) -#define PLIC_EDGE_TRIG_SHIFT 5 +static uint32_t save_irq; +static const struct device *save_dev; -struct plic_regs_t { - uint32_t threshold_prio; - uint32_t claim_complete; -}; +INTC_PLIC_STATIC uint32_t local_irq_to_reg_index(uint32_t local_irq) +{ + return local_irq >> LOG2(PLIC_REG_SIZE); +} + +INTC_PLIC_STATIC uint32_t local_irq_to_reg_offset(uint32_t local_irq) +{ + return local_irq_to_reg_index(local_irq) * sizeof(uint32_t); +} + +static inline uint32_t get_plic_enabled_size(const struct device *dev) +{ + const struct plic_config *config = dev->config; -static int save_irq; + 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; + + /* + * 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, 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 + (get_first_context(hartid) * CONTEXT_SIZE); +} /** - * @brief return edge irq value or zero + * @brief Determine the PLIC device from the IRQ + * + * @param irq IRQ number + * + * @return PLIC device of that IRQ + */ +static inline const struct device *get_plic_dev_from_irq(uint32_t irq) +{ +#ifdef CONFIG_DYNAMIC_INTERRUPTS + return z_get_sw_isr_device_from_irq(irq); +#else + return DEVICE_DT_INST_GET(0); +#endif +} + +/** + * @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 * routine will return 0 * - * @param irq IRQ number to add to the trigger + * @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(uint32_t 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) { - volatile uint32_t *trig = (volatile uint32_t *)PLIC_EDGE_TRIG_TYPE; + const struct device *dev = get_plic_dev_from_irq(irq); + const uint32_t local_irq = irq_from_level_2(irq); - trig += (irq >> PLIC_EDGE_TRIG_SHIFT); - return *trig & BIT(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; + + 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. * @@ -85,20 +235,14 @@ static int riscv_plic_is_edge_irq(uint32_t irq) */ void riscv_plic_irq_enable(uint32_t irq) { - uint32_t key; - volatile uint32_t *en = (volatile uint32_t *)PLIC_IRQ_EN; - - key = irq_lock(); - en += (irq >> 5); - *en |= (1 << (irq & 31)); - 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. * @@ -106,13 +250,7 @@ void riscv_plic_irq_enable(uint32_t irq) */ void riscv_plic_irq_disable(uint32_t irq) { - uint32_t key; - volatile uint32_t *en = (volatile uint32_t *)PLIC_IRQ_EN; - - key = irq_lock(); - en += (irq >> 5); - *en &= ~(1 << (irq & 31)); - irq_unlock(key); + plic_irq_enable_set_state(irq, false); } /** @@ -125,10 +263,16 @@ void riscv_plic_irq_disable(uint32_t irq) */ int riscv_plic_irq_is_enabled(uint32_t irq) { - volatile uint32_t *en = (volatile uint32_t *)PLIC_IRQ_EN; + 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; - en += (irq >> 5); - return !!(*en & (1 << (irq & 31))); + en_value = sys_read32(en_addr); + en_value &= BIT(local_irq & PLIC_REG_MASK); + + return !!en_value; } /** @@ -143,13 +287,15 @@ int riscv_plic_irq_is_enabled(uint32_t irq) */ void riscv_plic_set_priority(uint32_t irq, uint32_t priority) { - volatile uint32_t *prio = (volatile uint32_t *)PLIC_PRIO; + 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 prio_addr = config->prio + (local_irq * sizeof(uint32_t)); - if (priority > PLIC_MAX_PRIO) - priority = PLIC_MAX_PRIO; + if (priority > config->max_prio) + priority = config->max_prio; - prio += irq; - *prio = priority; + sys_write32(priority, prio_addr); } /** @@ -158,24 +304,39 @@ void riscv_plic_set_priority(uint32_t irq, uint32_t priority) * This routine returns the RISCV PLIC-specific interrupt line causing an * interrupt. * + * @param dev Optional device pointer to get the interrupt line's controller + * * @return PLIC-specific interrupt line causing an interrupt. */ -int riscv_plic_get_irq(void) +unsigned int riscv_plic_get_irq(void) { return save_irq; } -static void plic_irq_handler(const void *arg) +const struct device *riscv_plic_get_dev(void) { - volatile struct plic_regs_t *regs = - (volatile struct plic_regs_t *) PLIC_REG; + return save_dev; +} - uint32_t irq; +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 */ - irq = regs->claim_complete; + 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 @@ -183,29 +344,37 @@ static void plic_irq_handler(const void *arg) * as IRQ number held by the claim_complete register is * cleared upon read. */ - save_irq = irq; + save_irq = local_irq; + save_dev = dev; /* * If the IRQ is out of range, call z_irq_spurious. * A call to z_irq_spurious will not return. */ - if (irq == 0U || irq >= PLIC_IRQS) + if (local_irq == 0U || local_irq >= config->num_irqs) { z_irq_spurious(NULL); + } - edge_irq = riscv_plic_is_edge_irq(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) - regs->claim_complete = save_irq; + if (trig_val == PLIC_TRIG_EDGE) { + sys_write32(local_irq, claim_complete_addr); + } +#endif - irq += CONFIG_2ND_LVL_ISR_TBL_OFFSET; + const uint32_t parent_irq = COND_CODE_1(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS), + (z_get_sw_isr_irq_from_device(dev)), (0U)); + const uint32_t irq = irq_to_level_2(local_irq) | parent_irq; + const unsigned int isr_offset = + COND_CODE_1(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS), (z_get_sw_isr_table_idx(irq)), + (irq_from_level_2(irq) + CONFIG_2ND_LVL_ISR_TBL_OFFSET)); /* Call the corresponding IRQ handler in _sw_isr_table */ - ite = (struct _isr_table_entry *)&_sw_isr_table[irq]; + ite = (struct _isr_table_entry *)&_sw_isr_table[isr_offset]; ite->isr(ite->arg); /* @@ -213,51 +382,205 @@ static void plic_irq_handler(const void *arg) * PLIC controller that the IRQ has been handled * for level triggered interrupts. */ - if (!edge_irq) - regs->claim_complete = save_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 } /** * @brief Initialize the Platform Level Interrupt Controller * + * @param dev PLIC device struct + * * @retval 0 on success. */ static int plic_init(const struct device *dev) { + const struct plic_config *config = dev->config; + mem_addr_t en_addr, thres_prio_addr; + mem_addr_t prio_addr = config->prio; + + /* 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 */ + for (uint32_t i = 0; i < config->num_irqs; i++) { + sys_write32(0U, prio_addr + (i * sizeof(uint32_t))); + } + + /* Configure IRQ for PLIC driver */ + config->irq_config_func(); - volatile uint32_t *en = (volatile uint32_t *)PLIC_IRQ_EN; - volatile uint32_t *prio = (volatile uint32_t *)PLIC_PRIO; - volatile struct plic_regs_t *regs = - (volatile struct plic_regs_t *)PLIC_REG; - int i; + 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); - /* Ensure that all interrupts are disabled initially */ - for (i = 0; i < PLIC_EN_SIZE; i++) { - *en = 0U; - en++; + *plic = device_get_binding(argv[1]); + if (*plic == NULL) { + shell_error(sh, "PLIC device (%s) not found!\n", argv[1]); + return -ENODEV; } - /* Set priority of each interrupt line to 0 initially */ - for (i = 0; i < PLIC_IRQS; i++) { - *prio = 0U; - prio++; + 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; } - /* Set threshold priority to 0 */ - regs->threshold_prio = 0U; + const struct plic_data *data = dev->data; + struct plic_stats stat = data->stats; - /* Setup IRQ handler for PLIC driver */ - IRQ_CONNECT(RISCV_MACHINE_EXT_IRQ, - 0, - plic_irq_handler, - NULL, - 0); + if (argc > 2) { + min_hit = (uint16_t)atoi(argv[2]); + shell_print(sh, "IRQ line with > %d hits:", min_hit); + } - /* Enable IRQ for PLIC driver */ - irq_enable(RISCV_MACHINE_EXT_IRQ); + 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; } -DEVICE_DT_INST_DEFINE(0, plic_init, NULL, NULL, NULL, - PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, NULL); +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) \ + static void plic_irq_config_func_##n(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), 0, plic_irq_handler, DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } + +#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), \ + .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, \ + }; \ + PLIC_INTC_IRQ_FUNC_DEFINE(n) + +#define PLIC_INTC_DEVICE_INIT(n) \ + PLIC_INTC_CONFIG_INIT(n) \ + PLIC_INTC_DATA_INIT(n) \ + DEVICE_DT_INST_DEFINE(n, &plic_init, NULL, \ + PLIC_INTC_DATA(n), &plic_config_##n, \ + PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(PLIC_INTC_DEVICE_INIT) 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 000000000000000..57b9ac731abef5a --- /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_swerv_pic.c b/drivers/interrupt_controller/intc_swerv_pic.c index 5c52ab49614d0c9..96eb248d27c7bd6 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 efec4d2478eb7e3..2d5d2233ab2e3ad 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/CMakeLists.txt b/drivers/ipm/CMakeLists.txt index a6c41f845e43ef7..cc79cce4f83fd1a 100644 --- a/drivers/ipm/CMakeLists.txt +++ b/drivers/ipm/CMakeLists.txt @@ -6,7 +6,6 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_IPM_MCUX ipm_mcux.c) zephyr_library_sources_ifdef(CONFIG_IPM_IMX ipm_imx.c) -zephyr_library_sources_ifdef(CONFIG_IPM_IMX_REV2 ipm_imx.c) zephyr_library_sources_ifdef(CONFIG_IPM_MHU ipm_mhu.c) zephyr_library_sources_ifdef(CONFIG_IPM_STM32_IPCC ipm_stm32_ipcc.c) zephyr_library_sources_ifdef(CONFIG_IPM_NRFX ipm_nrfx_ipc.c) diff --git a/drivers/ipm/Kconfig.imx b/drivers/ipm/Kconfig.imx index f945483f0be3835..67fbc370ac8609e 100644 --- a/drivers/ipm/Kconfig.imx +++ b/drivers/ipm/Kconfig.imx @@ -15,17 +15,11 @@ config IPM_IMX help Driver for NXP i.MX messaging unit -config IPM_IMX_REV2 - bool "IMX IPM driver (rev 2)" - default y - depends on DT_HAS_NXP_IMX_MU_REV2_ENABLED - help - Rev 2 driver for NXP i.MX messaging unit (MCUX-based) +if IPM_IMX choice prompt "IMX IPM max data size" default IPM_IMX_MAX_DATA_SIZE_16 - depends on IPM_IMX || IPM_IMX_REV2 help Select maximum message size for NXP i.MX messaging unit. @@ -55,7 +49,6 @@ config IPM_IMX_MAX_DATA_SIZE default 4 if IPM_IMX_MAX_DATA_SIZE_4 default 8 if IPM_IMX_MAX_DATA_SIZE_8 default 16 if IPM_IMX_MAX_DATA_SIZE_16 - depends on IPM_IMX || IPM_IMX_REV2 config IPM_IMX_MAX_ID_VAL int @@ -63,10 +56,10 @@ config IPM_IMX_MAX_ID_VAL default 3 if IPM_IMX_MAX_DATA_SIZE_4 default 1 if IPM_IMX_MAX_DATA_SIZE_8 default 0 if IPM_IMX_MAX_DATA_SIZE_16 - depends on IPM_IMX || IPM_IMX_REV2 config IPM_IMX_FW_READY_REPLY bool "Send FW_READY reply message" - depends on IPM_IMX || IPM_IMX_REV2 help Send FW_READY reply to check for FW boot completion + +endif # IPM_IMX diff --git a/drivers/ipm/ipm_esp32.c b/drivers/ipm/ipm_esp32.c index cbe6e42d90fd093..4fc504610a69c9b 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/ipm/ipm_handlers.c b/drivers/ipm/ipm_handlers.c index 647f87c543f80f8..259644ae8d0e694 100644 --- a/drivers/ipm/ipm_handlers.c +++ b/drivers/ipm/ipm_handlers.c @@ -4,15 +4,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include static inline int z_vrfy_ipm_send(const struct device *dev, int wait, uint32_t id, const void *data, int size) { - Z_OOPS(Z_SYSCALL_DRIVER_IPM(dev, send)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(data, size)); + K_OOPS(K_SYSCALL_DRIVER_IPM(dev, send)); + K_OOPS(K_SYSCALL_MEMORY_READ(data, size)); return z_impl_ipm_send((const struct device *)dev, wait, id, (const void *)data, size); } @@ -20,21 +20,21 @@ static inline int z_vrfy_ipm_send(const struct device *dev, int wait, static inline int z_vrfy_ipm_max_data_size_get(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_IPM(dev, max_data_size_get)); + K_OOPS(K_SYSCALL_DRIVER_IPM(dev, max_data_size_get)); return z_impl_ipm_max_data_size_get((const struct device *)dev); } #include static inline uint32_t z_vrfy_ipm_max_id_val_get(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_IPM(dev, max_id_val_get)); + K_OOPS(K_SYSCALL_DRIVER_IPM(dev, max_id_val_get)); return z_impl_ipm_max_id_val_get((const struct device *)dev); } #include static inline int z_vrfy_ipm_set_enabled(const struct device *dev, int enable) { - Z_OOPS(Z_SYSCALL_DRIVER_IPM(dev, set_enabled)); + K_OOPS(K_SYSCALL_DRIVER_IPM(dev, set_enabled)); return z_impl_ipm_set_enabled((const struct device *)dev, enable); } #include diff --git a/drivers/ipm/ipm_imx.c b/drivers/ipm/ipm_imx.c index f0fc5488670ca87..7a4b3b1e2101180 100644 --- a/drivers/ipm/ipm_imx.c +++ b/drivers/ipm/ipm_imx.c @@ -1,9 +1,10 @@ /* - * Copyright (c) 2018, NXP + * Copyright 2018,2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_imx_mu #include #include @@ -12,11 +13,11 @@ #include #include #include -#if defined(CONFIG_IPM_IMX_REV2) -#define DT_DRV_COMPAT nxp_imx_mu_rev2 + +#ifdef CONFIG_HAS_MCUX +/* MCUX HAL uses a different header file than the i.MX HAL for this IP block */ #include "fsl_mu.h" #else -#define DT_DRV_COMPAT nxp_imx_mu #include #endif @@ -38,7 +39,7 @@ struct imx_mu_data { void *user_data; }; -#if defined(CONFIG_IPM_IMX_REV2) +#if defined(CONFIG_HAS_MCUX) /*! * @brief Check RX full status. * @@ -127,7 +128,7 @@ static void imx_mu_isr(const struct device *dev) } if (all_registers_full) { for (i = 0; i < IMX_IPM_DATA_REGS; i++) { -#if defined(CONFIG_IPM_IMX_REV2) +#if defined(CONFIG_HAS_MCUX) data32[i] = MU_ReceiveMsg(base, (id * IMX_IPM_DATA_REGS) + i); #else @@ -166,7 +167,7 @@ static int imx_mu_ipm_send(const struct device *dev, int wait, uint32_t id, const struct imx_mu_config *config = dev->config; MU_Type *base = MU(config); uint32_t data32[IMX_IPM_DATA_REGS] = {0}; -#if !IS_ENABLED(CONFIG_IPM_IMX_REV2) +#if !IS_ENABLED(CONFIG_HAS_MCUX) mu_status_t status; #endif int i; @@ -182,7 +183,7 @@ static int imx_mu_ipm_send(const struct device *dev, int wait, uint32_t id, /* Actual message is passing using 32 bits registers */ memcpy(data32, data, size); -#if defined(CONFIG_IPM_IMX_REV2) +#if defined(CONFIG_HAS_MCUX) if (wait) { for (i = 0; i < IMX_IPM_DATA_REGS; i++) { MU_SendMsgNonBlocking(base, id * IMX_IPM_DATA_REGS + i, @@ -249,7 +250,7 @@ static int imx_mu_ipm_set_enabled(const struct device *dev, int enable) { const struct imx_mu_config *config = dev->config; MU_Type *base = MU(config); -#if defined(CONFIG_IPM_IMX_REV2) +#if defined(CONFIG_HAS_MCUX) #if CONFIG_IPM_IMX_MAX_DATA_SIZE_4 if (enable) { MU_EnableInterrupts(base, kMU_Rx0FullInterruptEnable); diff --git a/drivers/ipm/ipm_ivshmem.c b/drivers/ipm/ipm_ivshmem.c index deda3f519506d33..46e009fb6340482 100644 --- a/drivers/ipm/ipm_ivshmem.c +++ b/drivers/ipm/ipm_ivshmem.c @@ -102,7 +102,7 @@ static int ivshmem_ipm_init(const struct device *dev) k_thread_create(&ivshmem_ev_loop_thread, ivshmem_ev_loop_stack, CONFIG_IPM_IVSHMEM_EVENT_LOOP_STACK_SIZE, - (k_thread_entry_t)ivshmem_ipm_event_loop_thread, + ivshmem_ipm_event_loop_thread, (void *)dev, NULL, NULL, CONFIG_IPM_IVSHMEM_EVENT_LOOP_PRIO, 0, K_NO_WAIT); diff --git a/drivers/kscan/CMakeLists.txt b/drivers/kscan/CMakeLists.txt index d650f17f9171019..005c53ab4b73a09 100644 --- a/drivers/kscan/CMakeLists.txt +++ b/drivers/kscan/CMakeLists.txt @@ -4,7 +4,6 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/kscan.h) zephyr_library() -zephyr_library_sources_ifdef(CONFIG_KSCAN_ITE_IT8XXX2 kscan_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_XEC kscan_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_HT16K33 kscan_ht16k33.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_INPUT kscan_input.c) diff --git a/drivers/kscan/Kconfig b/drivers/kscan/Kconfig index 02ef0987cc68a31..a2a786c31e39e36 100644 --- a/drivers/kscan/Kconfig +++ b/drivers/kscan/Kconfig @@ -10,7 +10,6 @@ menuconfig KSCAN if KSCAN -source "drivers/kscan/Kconfig.it8xxx2" source "drivers/kscan/Kconfig.xec" source "drivers/kscan/Kconfig.ht16k33" source "drivers/kscan/Kconfig.input" diff --git a/drivers/kscan/Kconfig.it8xxx2 b/drivers/kscan/Kconfig.it8xxx2 deleted file mode 100644 index da5cead4b78930b..000000000000000 --- a/drivers/kscan/Kconfig.it8xxx2 +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2021 ITE Corporation. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - -menuconfig KSCAN_ITE_IT8XXX2 - bool "ITE KSCAN driver" - default y - depends on DT_HAS_ITE_IT8XXX2_KSCAN_ENABLED - select MULTITHREADING - help - This option enables the ITE keyboard scan driver. - -if KSCAN_ITE_IT8XXX2 - -config KSCAN_ITE_IT8XXX2_COLUMN_SIZE - int "KSCAN_ITE_IT8XXX2_COLUMN_SIZE" - range 16 18 - default 16 - help - Adjust the value to your keyboard columns. The maximum - column size for the ITE family is 18. - -config KSCAN_ITE_IT8XXX2_ROW_SIZE - int "KSCAN_ITE_IT8XXX2_ROW_SIZE" - default 8 - help - Adjust the value to your keyboard rows. The maximum - row size for the ITE family is 8. - -config KSCAN_ITE_IT8XXX2_DEBOUNCE_DOWN - int "KSCAN_ITE_IT8XXX2_DEBOUNCE_DOWN" - default 9 - help - Determines the time in msecs for debouncing a key press. - -config KSCAN_ITE_IT8XXX2_DEBOUNCE_UP - int "KSCAN_ITE_IT8XXX2_DEBOUNCE_UP" - default 30 - help - Determines the time in msecs for debouncing a key release. - -config KSCAN_ITE_IT8XXX2_POLL_PERIOD - int "KSCAN_ITE_IT8XXX2_POLL_PERIOD" - default 3 - help - Defines the poll period in msecs between matrix scans. - -endif # KSCAN_ITE_IT8XXX2 diff --git a/drivers/kscan/kscan_handlers.c b/drivers/kscan/kscan_handlers.c index b2d36ba39431d76..98809687430a803 100644 --- a/drivers/kscan/kscan_handlers.c +++ b/drivers/kscan/kscan_handlers.c @@ -5,13 +5,13 @@ */ #include -#include +#include static inline int z_vrfy_kscan_config(const struct device *dev, kscan_callback_t callback_isr) { - Z_OOPS(Z_SYSCALL_DRIVER_KSCAN(dev, config)); - Z_OOPS(Z_SYSCALL_VERIFY_MSG(callback_isr == 0, + K_OOPS(K_SYSCALL_DRIVER_KSCAN(dev, config)); + K_OOPS(K_SYSCALL_VERIFY_MSG(callback_isr == 0, "callback cannot be set from user mode")); return z_impl_kscan_config((const struct device *)dev, callback_isr); } @@ -19,7 +19,7 @@ static inline int z_vrfy_kscan_config(const struct device *dev, static inline int z_vrfy_kscan_disable_callback(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_KSCAN(dev, disable_callback)); + K_OOPS(K_SYSCALL_DRIVER_KSCAN(dev, disable_callback)); return z_impl_kscan_disable_callback((const struct device *)dev); } @@ -27,7 +27,7 @@ static inline int z_vrfy_kscan_disable_callback(const struct device *dev) static int z_vrfy_kscan_enable_callback(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_KSCAN(dev, enable_callback)); + K_OOPS(K_SYSCALL_DRIVER_KSCAN(dev, enable_callback)); return z_impl_kscan_enable_callback((const struct device *)dev); } diff --git a/drivers/kscan/kscan_ite_it8xxx2.c b/drivers/kscan/kscan_ite_it8xxx2.c deleted file mode 100644 index 85d47d9d230e203..000000000000000 --- a/drivers/kscan/kscan_ite_it8xxx2.c +++ /dev/null @@ -1,589 +0,0 @@ -/* - * Copyright (c) 2021 ITE Corporation. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT ite_it8xxx2_kscan - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#define LOG_LEVEL CONFIG_KSCAN_LOG_LEVEL -LOG_MODULE_REGISTER(kscan_ite_it8xxx2); - -#define KEYBOARD_KSI_PIN_COUNT IT8XXX2_DT_INST_WUCCTRL_LEN(0) -#define KEYBOARD_COLUMN_DRIVE_ALL -2 -#define KEYBOARD_COLUMN_DRIVE_NONE -1 -/* Free run timer counts transform to micro-seconds (clock source is 32768Hz) */ -#define CLOCK_32K_HW_CYCLES_TO_US(X) \ - (uint32_t)((((uint64_t)(X) * 1000000U) / \ - sys_clock_hw_cycles_per_sec())) -/* Milli-second transform to micro-second */ -#define MS_TO_US 1000U -/* Number of tracked scan times */ -#define SCAN_OCURRENCES 30U -/* Thread stack size */ -#define TASK_STACK_SIZE 1024 - -/* Device config */ -enum kscan_pin_func { - KSO16 = 0, - KSO17, -}; - -struct kscan_wuc_map_cfg { - /* WUC control device structure */ - const struct device *wucs; - /* WUC pin mask */ - uint8_t mask; -}; - -struct kscan_it8xxx2_config { - /* Keyboard scan controller base address */ - struct kscan_it8xxx2_regs *base; - /* Keyboard scan input (KSI) wake-up irq */ - int irq; - /* KSI[7:0] wake-up input source configuration list */ - const struct kscan_wuc_map_cfg *wuc_map_list; - /* KSI[7:0]/KSO[17:0] keyboard scan alternate configuration */ - const struct pinctrl_dev_config *pcfg; - /* KSO16 GPIO cells */ - struct gpio_dt_spec kso16_gpios; - /* KSO17 GPIO cells */ - struct gpio_dt_spec kso17_gpios; -}; - -/* Device data */ -struct kscan_it8xxx2_data { - /* Variables in usec units */ - uint32_t deb_time_press; - uint32_t deb_time_rel; - int32_t poll_timeout; - uint32_t poll_period; - uint8_t matrix_stable_state[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE]; - uint8_t matrix_unstable_state[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE]; - uint8_t matrix_previous_state[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE]; - /* Index in to the scan_clock_cycle to indicate start of debouncing */ - uint8_t scan_cycle_idx[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE] - [CONFIG_KSCAN_ITE_IT8XXX2_ROW_SIZE]; - /* - * Track previous "elapsed clock cycles" per matrix scan. This - * is used to calculate the debouncing time for every key - */ - uint8_t scan_clk_cycle[SCAN_OCURRENCES]; - struct k_sem poll_lock; - uint8_t scan_cycles_idx; - kscan_callback_t callback; - struct k_thread thread; - atomic_t enable_scan; - /* KSI[7:0] wake-up interrupt status mask */ - uint8_t ksi_pin_mask; - - K_KERNEL_STACK_MEMBER(thread_stack, TASK_STACK_SIZE); -}; - -static void drive_keyboard_column(const struct device *dev, int col) -{ - const struct kscan_it8xxx2_config *const config = dev->config; - struct kscan_it8xxx2_regs *const inst = config->base; - int mask; - - /* Tri-state all outputs */ - if (col == KEYBOARD_COLUMN_DRIVE_NONE) { - mask = 0x3ffff; - /* Assert all outputs */ - } else if (col == KEYBOARD_COLUMN_DRIVE_ALL) { - mask = 0; - /* Assert a single output */ - } else { - mask = 0x3ffff ^ BIT(col); - } - - /* Set KSO[17:0] output data */ - inst->KBS_KSOL = (uint8_t) (mask & 0xff); - inst->KBS_KSOH1 = (uint8_t) ((mask >> 8) & 0xff); -#if (CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE > 16) - inst->KBS_KSOH2 = (uint8_t) ((mask >> 16) & 0xff); -#endif -} - -static uint8_t read_keyboard_row(const struct device *dev) -{ - const struct kscan_it8xxx2_config *const config = dev->config; - struct kscan_it8xxx2_regs *const inst = config->base; - - /* Bits are active-low, so toggle it (return 1 means key pressed) */ - return (inst->KBS_KSI ^ 0xff); -} - -static bool is_matrix_ghosting(const uint8_t *state) -{ - /* - * Matrix keyboard designs are susceptible to ghosting. - * An extra key appears to be pressed when 3 keys - * belonging to the same block are pressed. - * for example, in the following block - * - * . . w . q . - * . . . . . . - * . . . . . . - * . . m . a . - * - * the key m would look as pressed if the user pressed keys - * w, q and a simultaneously. A block can also be formed, - * with not adjacent columns. - */ - for (int c = 0; c < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; c++) { - if (!state[c]) - continue; - - for (int c_n = c + 1; c_n < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; c_n++) { - /* - * We AND the columns to detect a "block". - * this is an indication of ghosting, due to current - * flowing from a key which was never pressed. in our - * case, current flowing is a bit set to 1 as we - * flipped the bits when the matrix was scanned. - * now we OR the columns 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_n]; - - if (common_row_bits & (common_row_bits - 1)) - return true; - } - } - - return false; -} - -static bool read_keyboard_matrix(const struct device *dev, uint8_t *new_state) -{ - uint8_t row; - uint8_t key_event = 0U; - - for (int col = 0; col < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; col++) { - /* Drive specific column low and others high */ - drive_keyboard_column(dev, col); - /* Allow the matrix to stabilize before reading it */ - k_busy_wait(50U); - row = read_keyboard_row(dev); - new_state[col] = row; - - key_event |= row; - } - - drive_keyboard_column(dev, KEYBOARD_COLUMN_DRIVE_NONE); - - return key_event != 0U ? true : false; -} - -static void keyboard_raw_interrupt(const struct device *dev) -{ - const struct kscan_it8xxx2_config *const config = dev->config; - struct kscan_it8xxx2_data *data = dev->data; - - /* - * W/C wakeup interrupt status of KSI[7:0] pins - * - * NOTE: We want to clear the status as soon as possible, - * so clear KSI[7:0] pins at a time. - */ - it8xxx2_wuc_clear_status(config->wuc_map_list[0].wucs, - data->ksi_pin_mask); - - /* W/C interrupt status of KSI[7:0] pins */ - ite_intc_isr_clear(config->irq); - - /* Release poll lock semaphore */ - k_sem_give(&data->poll_lock); -} - -void keyboard_raw_enable_interrupt(const struct device *dev, int enable) -{ - const struct kscan_it8xxx2_config *const config = dev->config; - struct kscan_it8xxx2_data *data = dev->data; - - if (enable) { - /* - * W/C wakeup interrupt status of KSI[7:0] pins - * - * NOTE: We want to clear the status as soon as possible, - * so clear KSI[7:0] pins at a time. - */ - it8xxx2_wuc_clear_status(config->wuc_map_list[0].wucs, - data->ksi_pin_mask); - - /* W/C interrupt status of KSI[7:0] pins */ - ite_intc_isr_clear(config->irq); - - irq_enable(config->irq); - } else { - irq_disable(config->irq); - } -} - -static bool check_key_events(const struct device *dev) -{ - struct kscan_it8xxx2_data *data = dev->data; - uint8_t matrix_new_state[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE] = {0U}; - bool key_pressed = false; - uint32_t cycles_now = k_cycle_get_32(); - uint8_t row_changed = 0U; - uint8_t deb_col; - - if (++data->scan_cycles_idx >= SCAN_OCURRENCES) { - data->scan_cycles_idx = 0U; - } - - data->scan_clk_cycle[data->scan_cycles_idx] = cycles_now; - - /* Scan the matrix */ - key_pressed = read_keyboard_matrix(dev, matrix_new_state); - - /* Abort if ghosting is detected */ - if (is_matrix_ghosting(matrix_new_state)) { - return false; - } - - /* - * The intent of this loop is to gather information related to key - * changes - */ - for (int c = 0; c < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; c++) { - /* Check if there was an update from the previous scan */ - row_changed = matrix_new_state[c] ^ - data->matrix_previous_state[c]; - - if (!row_changed) - continue; - - for (int r = 0; r < CONFIG_KSCAN_ITE_IT8XXX2_ROW_SIZE; r++) { - /* - * Index all they keys that changed for each row - * in order to debounce each key in terms of it - */ - if (row_changed & BIT(r)) - data->scan_cycle_idx[c][r] = - data->scan_cycles_idx; - } - - data->matrix_unstable_state[c] |= row_changed; - data->matrix_previous_state[c] = matrix_new_state[c]; - } - - for (int c = 0; c < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; c++) { - deb_col = data->matrix_unstable_state[c]; - - if (!deb_col) - continue; - - /* Debouncing for each row key occurs here */ - for (int r = 0; r < CONFIG_KSCAN_ITE_IT8XXX2_ROW_SIZE; r++) { - uint8_t mask = BIT(r); - uint8_t row_bit = matrix_new_state[c] & mask; - - /* Continue if we already debounce a key */ - if (!(deb_col & mask)) - continue; - - /* Convert the clock cycle differences to usec */ - uint32_t debt = CLOCK_32K_HW_CYCLES_TO_US(cycles_now - - data->scan_clk_cycle[data->scan_cycle_idx[c][r]]); - - /* Does the key requires more time to be debounced ? */ - if (debt < (row_bit ? data->deb_time_press : - data->deb_time_rel)) { - /* Need more time to debounce */ - continue; - } - - data->matrix_unstable_state[c] &= ~row_bit; - - /* Check if there was a change in the stable state */ - if ((data->matrix_stable_state[c] & mask) == row_bit) { - /* Key state did not change */ - continue; - } - - /* - * The current row has been debounced, therefore update - * the stable state. Then, proceed to notify the - * application about the keys pressed. - */ - data->matrix_stable_state[c] ^= mask; - if ((atomic_get(&data->enable_scan) == 1U) && - (data->callback != NULL)) { - data->callback(dev, r, c, - row_bit ? true : false); - } - } - } - - return key_pressed; -} - -/** - * @brief Determine if a timer is expired. - * - * @param start_cycles The starting time of HW cycle. - * @param timeout Pointer to the period time. - * - * @retval true If timer is expired; - * false If timer isn't expired. - */ -static bool poll_expired(uint32_t start_cycles, int32_t *timeout) -{ - uint32_t now_cycles; - uint32_t microsecs_spent; - - now_cycles = k_cycle_get_32(); - microsecs_spent = CLOCK_32K_HW_CYCLES_TO_US(now_cycles - start_cycles); - - /* Update the timeout value */ - *timeout -= microsecs_spent; - - return !(*timeout >= 0); -} - -void polling_task(const struct device *dev, void *dummy2, void *dummy3) -{ - struct kscan_it8xxx2_data *data = dev->data; - int32_t local_poll_timeout = data->poll_timeout; - uint32_t current_cycles; - uint32_t cycles_delta; - uint32_t wait_period; - - ARG_UNUSED(dummy2); - ARG_UNUSED(dummy3); - - while (true) { - /* Init all KSO output low */ - drive_keyboard_column(dev, KEYBOARD_COLUMN_DRIVE_ALL); - /* Enable wakeup and interrupt of KSI pins */ - keyboard_raw_enable_interrupt(dev, 1); - /* Wait poll lock semaphore */ - k_sem_take(&data->poll_lock, K_FOREVER); - /* Disable wakeup and interrupt of KSI pins after fired */ - keyboard_raw_enable_interrupt(dev, 0); - - uint32_t start_poll_cycles = k_cycle_get_32(); - - while (atomic_get(&data->enable_scan) == 1U) { - uint32_t start_period_cycles = k_cycle_get_32(); - - if (check_key_events(dev)) { - start_poll_cycles = k_cycle_get_32(); - } else if (poll_expired(start_poll_cycles, - &local_poll_timeout)) { - break; - } - - /* - * Subtract the time invested from the sleep period - * in order to compensate for the time invested - * in debouncing a key - */ - current_cycles = k_cycle_get_32(); - cycles_delta = current_cycles - start_period_cycles; - wait_period = data->poll_period - - CLOCK_32K_HW_CYCLES_TO_US(cycles_delta); - - /* Override wait_period in case it's less than 1000 us */ - if (wait_period < MS_TO_US) { - wait_period = MS_TO_US; - } - - /* - * Wait period results in a larger number when - * current cycles counter wrap. In this case, the - * whole poll period is used - */ - if (wait_period > data->poll_period) { - LOG_DBG("wait_period : %u", wait_period); - wait_period = data->poll_period; - } - - /* Allow other threads to run while we sleep */ - k_usleep(wait_period); - } - } -} - -static int kscan_it8xxx2_init(const struct device *dev) -{ - const struct kscan_it8xxx2_config *const config = dev->config; - struct kscan_it8xxx2_data *data = dev->data; - struct kscan_it8xxx2_regs *const inst = config->base; - int status; - - /* Disable wakeup and interrupt of KSI pins before configuring */ - keyboard_raw_enable_interrupt(dev, 0); - -#if (CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE > 16) - /* - * For KSO[16] and KSO[17]: - * 1.GPOTRC: - * Bit[x] = 1b: Enable the open-drain mode of KSO pin - * 2.GPCRCx: - * Bit[7:6] = 00b: Select alternate KSO function - * Bit[2] = 1b: Enable the internal pull-up of KSO pin - * - * NOTE: Set input temporarily for gpio_pin_configure(), after that - * pinctrl_apply_state() set to alternate function immediately. - */ - gpio_pin_configure_dt(&config->kso16_gpios, GPIO_INPUT); - gpio_pin_configure_dt(&config->kso17_gpios, GPIO_INPUT); -#endif - /* - * Enable the internal pull-up and kbs mode of the KSI[7:0] pins. - * Enable the internal pull-up and kbs mode of the KSO[15:0] pins. - * Enable the open-drain mode of the KSO[17:0] pins. - */ - status = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); - if (status < 0) { - LOG_ERR("Failed to configure KSI[7:0] and KSO[17:0] pins"); - return status; - } - - /* KSO[17:0] pins output low */ - inst->KBS_KSOL = 0x00; - inst->KBS_KSOH1 = 0x00; -#if (CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE > 16) - inst->KBS_KSOH2 = 0x00; -#endif - - for (int i = 0; i < KEYBOARD_KSI_PIN_COUNT; i++) { - /* Select wakeup interrupt falling-edge triggered of KSI[7:0] pins */ - it8xxx2_wuc_set_polarity(config->wuc_map_list[i].wucs, - config->wuc_map_list[i].mask, - WUC_TYPE_EDGE_FALLING); - /* W/C wakeup interrupt status of KSI[7:0] pins */ - it8xxx2_wuc_clear_status(config->wuc_map_list[i].wucs, - config->wuc_map_list[i].mask); - /* Enable wakeup interrupt of KSI[7:0] pins */ - it8xxx2_wuc_enable(config->wuc_map_list[i].wucs, - config->wuc_map_list[i].mask); - - /* - * We want to clear KSI[7:0] pins status at a time when wakeup - * interrupt fire, so gather the KSI[7:0] pin mask value here. - */ - if (IS_ENABLED(CONFIG_LOG)) { - if (config->wuc_map_list[i].wucs != config->wuc_map_list[0].wucs) { - LOG_ERR("KSI%d pin isn't in the same wuc node!", i); - } - } - data->ksi_pin_mask |= config->wuc_map_list[i].mask; - } - - /* W/C interrupt status of KSI[7:0] pins */ - ite_intc_isr_clear(config->irq); - - /* Kconfig.it8xxx2 time figures are transformed from msec to usec */ - data->deb_time_press = - (uint32_t) (CONFIG_KSCAN_ITE_IT8XXX2_DEBOUNCE_DOWN * MS_TO_US); - data->deb_time_rel = - (uint32_t) (CONFIG_KSCAN_ITE_IT8XXX2_DEBOUNCE_UP * MS_TO_US); - data->poll_period = - (uint32_t) (CONFIG_KSCAN_ITE_IT8XXX2_POLL_PERIOD * MS_TO_US); - data->poll_timeout = 100 * MS_TO_US; - - /* Init null for callback function */ - data->callback = NULL; - - /* Create poll lock semaphore */ - k_sem_init(&data->poll_lock, 0, 1); - - /* Enable keyboard scan loop */ - atomic_set(&data->enable_scan, 1); - - irq_connect_dynamic(DT_INST_IRQN(0), 0, - (void (*)(const void *))keyboard_raw_interrupt, - (const void *)dev, 0); - - /* Create keyboard scan task */ - k_thread_create(&data->thread, data->thread_stack, - TASK_STACK_SIZE, - (void (*)(void *, void *, void *))polling_task, - (void *)dev, NULL, NULL, - K_PRIO_COOP(4), 0, K_NO_WAIT); - - return 0; -} - -static int kscan_it8xxx2_configure(const struct device *dev, - kscan_callback_t callback) -{ - struct kscan_it8xxx2_data *data = dev->data; - - if (!callback) { - return -EINVAL; - } - - /* Setup callback function */ - data->callback = callback; - - return 0; -} - -static int kscan_it8xxx2_disable_callback(const struct device *dev) -{ - struct kscan_it8xxx2_data *data = dev->data; - - /* Disable keyboard scan loop */ - atomic_set(&data->enable_scan, 0); - - return 0; -} - -static int kscan_it8xxx2_enable_callback(const struct device *dev) -{ - struct kscan_it8xxx2_data *data = dev->data; - - /* Enable keyboard scan loop */ - atomic_set(&data->enable_scan, 1); - - return 0; -} - -static const struct kscan_driver_api kscan_it8xxx2_driver_api = { - .config = kscan_it8xxx2_configure, - .disable_callback = kscan_it8xxx2_disable_callback, - .enable_callback = kscan_it8xxx2_enable_callback, -}; - -static const struct kscan_wuc_map_cfg kscan_wuc_0[IT8XXX2_DT_INST_WUCCTRL_LEN(0)] = - IT8XXX2_DT_WUC_ITEMS_LIST(0); - -PINCTRL_DT_INST_DEFINE(0); - -static const struct kscan_it8xxx2_config kscan_it8xxx2_cfg_0 = { - .base = (struct kscan_it8xxx2_regs *)DT_INST_REG_ADDR_BY_IDX(0, 0), - .irq = DT_INST_IRQN(0), - .wuc_map_list = kscan_wuc_0, - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), - .kso16_gpios = GPIO_DT_SPEC_INST_GET(0, kso16_gpios), - .kso17_gpios = GPIO_DT_SPEC_INST_GET(0, kso17_gpios), -}; - -static struct kscan_it8xxx2_data kscan_it8xxx2_kbd_data; - -DEVICE_DT_INST_DEFINE(0, - &kscan_it8xxx2_init, - NULL, - &kscan_it8xxx2_kbd_data, - &kscan_it8xxx2_cfg_0, - POST_KERNEL, - CONFIG_KSCAN_INIT_PRIORITY, - &kscan_it8xxx2_driver_api); diff --git a/drivers/kscan/kscan_mchp_xec.c b/drivers/kscan/kscan_mchp_xec.c index e0960b1c9463ef5..e3e8fa4043ecde6 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/ht16k33.c b/drivers/led/ht16k33.c index 0db398e55fffd87..8df5b7553f62036 100644 --- a/drivers/led/ht16k33.c +++ b/drivers/led/ht16k33.c @@ -247,8 +247,12 @@ static bool ht16k33_process_keyscan_data(const struct device *dev) return pressed; } -static void ht16k33_irq_thread(struct ht16k33_data *data) +static void ht16k33_irq_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct ht16k33_data *data = p1; bool pressed; while (true) { @@ -420,7 +424,7 @@ static int ht16k33_init(const struct device *dev) k_thread_create(&data->irq_thread, data->irq_thread_stack, CONFIG_HT16K33_KEYSCAN_IRQ_THREAD_STACK_SIZE, - (k_thread_entry_t)ht16k33_irq_thread, data, NULL, NULL, + ht16k33_irq_thread, data, NULL, NULL, K_PRIO_COOP(CONFIG_HT16K33_KEYSCAN_IRQ_THREAD_PRIO), 0, K_NO_WAIT); #endif /* CONFIG_HT16K33_KEYSCAN */ diff --git a/drivers/led/led_handlers.c b/drivers/led/led_handlers.c index a3a37fb49e1878f..a089846e6951ec4 100644 --- a/drivers/led/led_handlers.c +++ b/drivers/led/led_handlers.c @@ -4,13 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include static inline int z_vrfy_led_blink(const struct device *dev, uint32_t led, uint32_t delay_on, uint32_t delay_off) { - Z_OOPS(Z_SYSCALL_DRIVER_LED(dev, blink)); + K_OOPS(K_SYSCALL_DRIVER_LED(dev, blink)); return z_impl_led_blink((const struct device *)dev, led, delay_on, delay_off); } @@ -19,8 +19,8 @@ static inline int z_vrfy_led_blink(const struct device *dev, uint32_t led, static inline int z_vrfy_led_get_info(const struct device *dev, uint32_t led, const struct led_info **info) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_LED)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(info, sizeof(*info))); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_LED)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(info, sizeof(*info))); return z_impl_led_get_info(dev, led, info); } #include @@ -29,7 +29,7 @@ static inline int z_vrfy_led_set_brightness(const struct device *dev, uint32_t led, uint8_t value) { - Z_OOPS(Z_SYSCALL_DRIVER_LED(dev, set_brightness)); + K_OOPS(K_SYSCALL_DRIVER_LED(dev, set_brightness)); return z_impl_led_set_brightness((const struct device *)dev, led, value); } @@ -39,8 +39,8 @@ static inline int z_vrfy_led_write_channels(const struct device *dev, uint32_t start_channel, uint32_t num_channels, const uint8_t *buf) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_LED)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(buf, num_channels)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_LED)); + K_OOPS(K_SYSCALL_MEMORY_READ(buf, num_channels)); return z_impl_led_write_channels(dev, start_channel, num_channels, buf); } #include @@ -48,7 +48,7 @@ z_vrfy_led_write_channels(const struct device *dev, uint32_t start_channel, static inline int z_vrfy_led_set_channel(const struct device *dev, uint32_t channel, uint8_t value) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_LED)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_LED)); return z_impl_led_set_channel(dev, channel, value); } #include @@ -56,22 +56,22 @@ static inline int z_vrfy_led_set_channel(const struct device *dev, static inline int z_vrfy_led_set_color(const struct device *dev, uint32_t led, uint8_t num_colors, const uint8_t *color) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_LED)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(color, num_colors)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_LED)); + K_OOPS(K_SYSCALL_MEMORY_READ(color, num_colors)); return z_impl_led_set_color(dev, led, num_colors, color); } #include static inline int z_vrfy_led_on(const struct device *dev, uint32_t led) { - Z_OOPS(Z_SYSCALL_DRIVER_LED(dev, on)); + K_OOPS(K_SYSCALL_DRIVER_LED(dev, on)); return z_impl_led_on((const struct device *)dev, led); } #include static inline int z_vrfy_led_off(const struct device *dev, uint32_t led) { - Z_OOPS(Z_SYSCALL_DRIVER_LED(dev, off)); + K_OOPS(K_SYSCALL_DRIVER_LED(dev, off)); return z_impl_led_off((const struct device *)dev, led); } #include diff --git a/drivers/led/led_pwm.c b/drivers/led/led_pwm.c index 72cb616a6e551f6..7a860ec97b74885 100644 --- a/drivers/led/led_pwm.c +++ b/drivers/led/led_pwm.c @@ -116,7 +116,7 @@ static int led_pwm_pm_action(const struct device *dev, err = pm_device_action_run(led->dev, action); if (err && (err != -EALREADY)) { - LOG_ERR("Cannot switch PWM %p power state", led->dev); + LOG_DBG("Cannot switch PWM %p power state (err = %d)", led->dev, err); } } diff --git a/drivers/led/ncp5623.c b/drivers/led/ncp5623.c index 3cb58d4bc48e59a..0fd0f128d37bcc9 100644 --- a/drivers/led/ncp5623.c +++ b/drivers/led/ncp5623.c @@ -149,9 +149,10 @@ static int ncp5623_led_init(const struct device *dev) return -ENODEV; } - if (led_info->num_colors != 3 || led_info->num_colors != 1) { - LOG_ERR("%s: invalid number of colors %d (must be %d or 1)", dev->name, - led_info->num_colors, NCP5623_CHANNEL_COUNT); + if (led_info->num_colors != NCP5623_CHANNEL_COUNT) { + LOG_ERR("%s: invalid number of colors %d (must be %d with a single LED)", + dev->name, led_info->num_colors, NCP5623_CHANNEL_COUNT); + return -EINVAL; } } else if (config->num_leds <= 3) { /* three single-channel LEDs */ for (i = 0; i < config->num_leds; i++) { diff --git a/drivers/led_strip/CMakeLists.txt b/drivers/led_strip/CMakeLists.txt index 6c950cac5969dff..aa4e95722a7163a 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 fc91250c2f221de..469b6d3f915de64 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 000000000000000..b2bb2654977b36e --- /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/led_strip/ws2812_spi.c b/drivers/led_strip/ws2812_spi.c index c562d5c3dad743a..44cfecebc9ea52d 100644 --- a/drivers/led_strip/ws2812_spi.c +++ b/drivers/led_strip/ws2812_spi.c @@ -34,8 +34,6 @@ LOG_MODULE_REGISTER(ws2812_spi); * isn't an EEPROM) */ #define SPI_OPER(idx) (SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | \ - COND_CODE_1(DT_INST_PROP(idx, spi_cpol), (SPI_MODE_CPOL), (0)) | \ - COND_CODE_1(DT_INST_PROP(idx, spi_cpha), (SPI_MODE_CPHA), (0)) | \ SPI_WORD_SET(SPI_FRAME_BITS)) struct ws2812_spi_cfg { diff --git a/drivers/lora/Kconfig b/drivers/lora/Kconfig index ddc1e50e62509a1..585f122c3d6fd41 100644 --- a/drivers/lora/Kconfig +++ b/drivers/lora/Kconfig @@ -21,7 +21,6 @@ source "subsys/logging/Kconfig.template.log_config" config LORA_SHELL bool "LoRa Shell" - default y depends on SHELL help Enable LoRa Shell for testing. diff --git a/drivers/mbox/mbox_andes_plic_sw.c b/drivers/mbox/mbox_andes_plic_sw.c index bc01da73a303290..e2c287ae216c66a 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_handlers.c b/drivers/mbox/mbox_handlers.c index 55b2b010c83b404..c4e43f74fe5230c 100644 --- a/drivers/mbox/mbox_handlers.c +++ b/drivers/mbox/mbox_handlers.c @@ -4,16 +4,16 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include static inline int z_vrfy_mbox_send(const struct mbox_channel *channel, const struct mbox_msg *msg) { - Z_OOPS(Z_SYSCALL_MEMORY_READ(channel, sizeof(struct mbox_channel))); - Z_OOPS(Z_SYSCALL_DRIVER_MBOX(channel->dev, send)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(msg, sizeof(struct mbox_msg))); - Z_OOPS(Z_SYSCALL_MEMORY_READ(msg->data, msg->size)); + K_OOPS(K_SYSCALL_MEMORY_READ(channel, sizeof(struct mbox_channel))); + K_OOPS(K_SYSCALL_DRIVER_MBOX(channel->dev, send)); + K_OOPS(K_SYSCALL_MEMORY_READ(msg, sizeof(struct mbox_msg))); + K_OOPS(K_SYSCALL_MEMORY_READ(msg->data, msg->size)); return z_impl_mbox_send(channel, msg); } @@ -21,7 +21,7 @@ static inline int z_vrfy_mbox_send(const struct mbox_channel *channel, static inline int z_vrfy_mbox_mtu_get(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_MBOX(dev, mtu_get)); + K_OOPS(K_SYSCALL_DRIVER_MBOX(dev, mtu_get)); return z_impl_mbox_mtu_get(dev); } @@ -29,7 +29,7 @@ static inline int z_vrfy_mbox_mtu_get(const struct device *dev) static inline uint32_t z_vrfy_mbox_max_channels_get(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_MBOX(dev, max_channels_get)); + K_OOPS(K_SYSCALL_DRIVER_MBOX(dev, max_channels_get)); return z_impl_mbox_max_channels_get(dev); } @@ -37,8 +37,8 @@ static inline uint32_t z_vrfy_mbox_max_channels_get(const struct device *dev) static inline int z_vrfy_mbox_set_enabled(const struct mbox_channel *channel, bool enable) { - Z_OOPS(Z_SYSCALL_MEMORY_READ(channel, sizeof(struct mbox_channel))); - Z_OOPS(Z_SYSCALL_DRIVER_MBOX(channel->dev, set_enabled)); + K_OOPS(K_SYSCALL_MEMORY_READ(channel, sizeof(struct mbox_channel))); + K_OOPS(K_SYSCALL_DRIVER_MBOX(channel->dev, set_enabled)); return z_impl_mbox_set_enabled(channel, enable); } diff --git a/drivers/mbox/mbox_nxp_imx_mu.c b/drivers/mbox/mbox_nxp_imx_mu.c index 3c708b95eca5aba..664a88e20651a32 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_s32_mru.c b/drivers/mbox/mbox_nxp_s32_mru.c index 287ba89eff8d4eb..2c6246d8dce37a6 100644 --- a/drivers/mbox/mbox_nxp_s32_mru.c +++ b/drivers/mbox/mbox_nxp_s32_mru.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_mru + #include #include #include @@ -19,22 +21,11 @@ LOG_MODULE_REGISTER(nxp_s32_mru); #define MRU_MBOX_SIZE 4 #define MRU_CHANNEL_OFFSET 0x1000 -#define MRU_NODE(n) DT_NODELABEL(mru##n) -#define MRU_BASE(n) ((RTU_MRU_Type *)DT_REG_ADDR(MRU_NODE(n))) -#define MRU_RX_CHANNELS(n) DT_PROP_OR(MRU_NODE(n), rx_channels, 0) -#define MRU_MBOX_ADDR(n, ch, mb) \ - (DT_REG_ADDR(MRU_NODE(n)) + ((ch + 1) * MRU_CHANNEL_OFFSET) + (MRU_MBOX_SIZE * mb)) - /* Utility macros to convert from GIC index to interrupt group index */ #define _MRU_IRQ_17 MRU_IP_INT_GROUP_0 #define _MRU_IRQ_18 MRU_IP_INT_GROUP_1 #define MRU_INT_GROUP(irq) _CONCAT(_MRU_IRQ_, irq) -#define _CONCAT7(...) DT_CAT7(__VA_ARGS__) -#define MRU_ISR_FUNC(n) \ - _CONCAT7(Mru_Ip_RTU, CONFIG_NXP_S32_RTU_INDEX, _MRU, n, _Int, \ - MRU_INT_GROUP(DT_IRQN(MRU_NODE(n))), _IRQHandler) - struct nxp_s32_mru_data { mbox_callback_t cb[MRU_MAX_CHANNELS]; void *user_data[MRU_MAX_CHANNELS]; @@ -44,6 +35,7 @@ struct nxp_s32_mru_config { RTU_MRU_Type *base; Mru_Ip_ConfigType hw_cfg; void (*config_irq)(void); + uint8_t irq_group; }; static inline bool is_rx_channel_valid(const struct device *dev, uint32_t ch) @@ -178,6 +170,13 @@ static int nxp_s32_mru_init(const struct device *dev) return 0; } +void nxp_s32_mru_isr(const struct device *dev) +{ + const struct nxp_s32_mru_config *config = dev->config; + + Mru_Ip_IrqHandler(config->hw_cfg.InstanceId, config->irq_group); +} + static const struct mbox_driver_api nxp_s32_mru_driver_api = { .send = nxp_s32_mru_send, .register_callback = nxp_s32_mru_register_callback, @@ -186,18 +185,26 @@ static const struct mbox_driver_api nxp_s32_mru_driver_api = { .set_enabled = nxp_s32_mru_set_enabled, }; -#define MRU_ISR_FUNC_DECLARE(n) extern void MRU_ISR_FUNC(n)(void) +#define MRU_BASE(n) ((RTU_MRU_Type *)DT_INST_REG_ADDR(n)) +#define MRU_RX_CHANNELS(n) DT_INST_PROP_OR(n, rx_channels, 0) +#define MRU_MBOX_ADDR(n, ch, mb) \ + (DT_INST_REG_ADDR(n) + ((ch + 1) * MRU_CHANNEL_OFFSET) + (MRU_MBOX_SIZE * mb)) + +#define MRU_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_MRU_##i##_BASE) ? i : 0) + +#define MRU_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET RTU_MRU_INSTANCE_COUNT, MRU_HW_INSTANCE_CHECK, (|), n) #define MRU_INIT_IRQ_FUNC(n) \ - MRU_ISR_FUNC_DECLARE(n); \ static void nxp_s32_mru_##n##_init_irq(void) \ { \ - IRQ_CONNECT(DT_IRQN(MRU_NODE(n)), \ - DT_IRQ(MRU_NODE(n), priority), \ - MRU_ISR_FUNC(n), \ - NULL, \ - DT_IRQ(MRU_NODE(n), flags)); \ - irq_enable(DT_IRQN(MRU_NODE(n))); \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + nxp_s32_mru_isr, \ + DEVICE_DT_INST_GET(n), \ + DT_INST_IRQ(n, flags)); \ + irq_enable(DT_INST_IRQN(n)); \ } #define MRU_CH_RX_CFG(i, n) \ @@ -208,7 +215,6 @@ static const struct mbox_driver_api nxp_s32_mru_driver_api = { static uint32_t nxp_s32_mru_##n##_ch_##i##_buf[MRU_MAX_MBOX_PER_CHAN]; \ static const Mru_Ip_ReceiveChannelType nxp_s32_mru_##n##_ch_##i##_rx_cfg = { \ .ChannelId = i, \ - .InstanceId = n, \ .ChannelIndex = i, \ .NumRxMB = MRU_MAX_MBOX_PER_CHAN, \ .MBAddList = nxp_s32_mru_##n##_ch_##i##_rx_mbox_addr, \ @@ -224,7 +230,7 @@ static const struct mbox_driver_api nxp_s32_mru_driver_api = { #define MRU_CH_RX_LINK_CFG(i, n) \ static const Mru_Ip_MBLinkReceiveChannelType \ nxp_s32_mru_##n##_ch_##i##_rx_link_cfg[MRU_MAX_MBOX_PER_CHAN][MRU_MAX_INT_GROUPS] = {\ - MRU_CH_RX_LINK_CFG_MBOX(0, n, i, MRU_INT_GROUP(DT_IRQN(MRU_NODE(n)))) \ + MRU_CH_RX_LINK_CFG_MBOX(0, n, i, MRU_INT_GROUP(DT_INST_IRQN(n))) \ } #define MRU_CH_CFG(i, n) \ @@ -232,7 +238,7 @@ static const struct mbox_driver_api nxp_s32_mru_driver_api = { .ChCFG0Add = &MRU_BASE(n)->CHXCONFIG[i].CH_CFG0, \ .ChCFG0 = RTU_MRU_CH_CFG0_IE(0) | RTU_MRU_CH_CFG0_MBE0(0), \ .ChCFG1Add = &MRU_BASE(n)->CHXCONFIG[i].CH_CFG1, \ - .ChCFG1 = RTU_MRU_CH_CFG1_MBIC0(MRU_INT_GROUP(DT_IRQN(MRU_NODE(n)))), \ + .ChCFG1 = RTU_MRU_CH_CFG1_MBIC0(MRU_INT_GROUP(DT_INST_IRQN(n))), \ .ChMBSTATAdd = &MRU_BASE(n)->CHXCONFIG[i].CH_MBSTAT, \ .NumMailbox = MRU_MAX_MBOX_PER_CHAN, \ .MBLinkReceiveChCfg = nxp_s32_mru_##n##_ch_##i##_rx_link_cfg \ @@ -242,7 +248,7 @@ static const struct mbox_driver_api nxp_s32_mru_driver_api = { #define MRU_CALLBACK_WRAPPER_FUNC(n) \ void nxp_s32_mru_##n##_cb(uint8_t channel, const uint32_t *buf, uint8_t mbox_count) \ { \ - const struct device *dev = DEVICE_DT_GET(MRU_NODE(n)); \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ struct nxp_s32_mru_data *data = dev->data; \ \ if (is_rx_channel_valid(dev, channel)) { \ @@ -271,53 +277,24 @@ static const struct mbox_driver_api nxp_s32_mru_driver_api = { static struct nxp_s32_mru_config nxp_s32_mru_##n##_config = { \ .base = MRU_BASE(n), \ .hw_cfg = { \ - .InstanceId = n, \ + .InstanceId = MRU_HW_INSTANCE(n), \ .StateIndex = n, \ .NumChannel = MRU_RX_CHANNELS(n), \ .ChannelCfg = COND_CODE_0(MRU_RX_CHANNELS(n), \ (NULL), (nxp_s32_mru_##n##_ch_cfg)), \ .NOTIFYAdd = { \ - &MRU_BASE(n)->NOTIFY0, \ - &MRU_BASE(n)->NOTIFY1 \ + &MRU_BASE(n)->NOTIFY[0], \ + &MRU_BASE(n)->NOTIFY[1] \ }, \ }, \ + .irq_group = MRU_INT_GROUP(DT_INST_IRQN(n)), \ .config_irq = COND_CODE_0(MRU_RX_CHANNELS(n), \ (NULL), (nxp_s32_mru_##n##_init_irq)), \ }; \ \ - DEVICE_DT_DEFINE(MRU_NODE(n), nxp_s32_mru_init, NULL, \ + DEVICE_DT_INST_DEFINE(n, nxp_s32_mru_init, NULL, \ &nxp_s32_mru_##n##_data, &nxp_s32_mru_##n##_config, \ POST_KERNEL, CONFIG_MBOX_INIT_PRIORITY, \ - &nxp_s32_mru_driver_api) - -#if DT_NODE_HAS_STATUS(MRU_NODE(0), okay) -MRU_INSTANCE_DEFINE(0); -#endif - -#if DT_NODE_HAS_STATUS(MRU_NODE(1), okay) -MRU_INSTANCE_DEFINE(1); -#endif - -#if DT_NODE_HAS_STATUS(MRU_NODE(2), okay) -MRU_INSTANCE_DEFINE(2); -#endif - -#if DT_NODE_HAS_STATUS(MRU_NODE(3), okay) -MRU_INSTANCE_DEFINE(3); -#endif - -#if DT_NODE_HAS_STATUS(MRU_NODE(4), okay) -MRU_INSTANCE_DEFINE(4); -#endif - -#if DT_NODE_HAS_STATUS(MRU_NODE(5), okay) -MRU_INSTANCE_DEFINE(5); -#endif - -#if DT_NODE_HAS_STATUS(MRU_NODE(6), okay) -MRU_INSTANCE_DEFINE(6); -#endif + &nxp_s32_mru_driver_api); -#if DT_NODE_HAS_STATUS(MRU_NODE(7), okay) -MRU_INSTANCE_DEFINE(7); -#endif +DT_INST_FOREACH_STATUS_OKAY(MRU_INSTANCE_DEFINE) diff --git a/drivers/mdio/CMakeLists.txt b/drivers/mdio/CMakeLists.txt index 4972626cdb5781b..30c6b9f83062041 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 ddca38359fa6550..2ff20df0b24d1e9 100644 --- a/drivers/mdio/Kconfig +++ b/drivers/mdio/Kconfig @@ -15,7 +15,6 @@ if MDIO config MDIO_SHELL bool "MDIO Shell" - default y depends on SHELL help Enable MDIO Shell. @@ -27,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 bdc8fb1221eee82..9c4d8f8bae55fec 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 000000000000000..dd3c734e1b37ccb --- /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 b/drivers/mdio/Kconfig.nxp_s32 deleted file mode 100644 index 07674f7a57dc117..000000000000000 --- a/drivers/mdio/Kconfig.nxp_s32 +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2022 NXP -# SPDX-License-Identifier: Apache-2.0 - -config MDIO_NXP_S32_NETC - bool "NXP S32 NETC External MDIO driver" - default y - depends on DT_HAS_NXP_S32_NETC_EMDIO_ENABLED - select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT - help - Enable NETC External MDIO Controller driver for NXP S32 SoCs. diff --git a/drivers/mdio/Kconfig.nxp_s32_gmac b/drivers/mdio/Kconfig.nxp_s32_gmac new file mode 100644 index 000000000000000..01927b6a6425793 --- /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_netc b/drivers/mdio/Kconfig.nxp_s32_netc new file mode 100644 index 000000000000000..61b02d53809f27f --- /dev/null +++ b/drivers/mdio/Kconfig.nxp_s32_netc @@ -0,0 +1,11 @@ +# Copyright 2022-2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config MDIO_NXP_S32_NETC + bool "NXP S32 NETC External MDIO driver" + default y + depends on DT_HAS_NXP_S32_NETC_EMDIO_ENABLED + depends on ETH_NXP_S32_NETC && DT_HAS_NXP_S32_NETC_PSI_ENABLED + select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT + help + Enable NETC External MDIO Controller driver for NXP S32 SoCs. diff --git a/drivers/mdio/Kconfig.xmc4xxx b/drivers/mdio/Kconfig.xmc4xxx new file mode 100644 index 000000000000000..75793fa1508c329 --- /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 000000000000000..6b5c128e075b77f --- /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 000000000000000..afd7c8ccedb4c9d --- /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_nxp_s32_netc.c b/drivers/mdio/mdio_nxp_s32_netc.c index c8ce0e731b30c8e..ff8a561d974511a 100644 --- a/drivers/mdio/mdio_nxp_s32_netc.c +++ b/drivers/mdio/mdio_nxp_s32_netc.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_netc_emdio + #include #include #include @@ -12,11 +14,9 @@ LOG_MODULE_REGISTER(nxp_s32_emdio, CONFIG_MDIO_LOG_LEVEL); #include -#define MDIO_NODE DT_NODELABEL(emdio) -#define NETC_SWT_IDX 0 - struct nxp_s32_mdio_config { const struct pinctrl_dev_config *pincfg; + uint8_t instance; }; struct nxp_s32_mdio_data { @@ -26,11 +26,12 @@ struct nxp_s32_mdio_data { static int nxp_s32_mdio_read(const struct device *dev, uint8_t prtad, uint8_t regad, uint16_t *regval) { + const struct nxp_s32_mdio_config *cfg = dev->config; struct nxp_s32_mdio_data *data = dev->data; Std_ReturnType status; k_mutex_lock(&data->rw_mutex, K_FOREVER); - status = Netc_EthSwt_Ip_ReadTrcvRegister(NETC_SWT_IDX, prtad, regad, regval); + status = Netc_EthSwt_Ip_ReadTrcvRegister(cfg->instance, prtad, regad, regval); k_mutex_unlock(&data->rw_mutex); return status == E_OK ? 0 : -EIO; @@ -39,11 +40,12 @@ static int nxp_s32_mdio_read(const struct device *dev, uint8_t prtad, static int nxp_s32_mdio_write(const struct device *dev, uint8_t prtad, uint8_t regad, uint16_t regval) { + const struct nxp_s32_mdio_config *cfg = dev->config; struct nxp_s32_mdio_data *data = dev->data; Std_ReturnType status; k_mutex_lock(&data->rw_mutex, K_FOREVER); - status = Netc_EthSwt_Ip_WriteTrcvRegister(NETC_SWT_IDX, prtad, regad, regval); + status = Netc_EthSwt_Ip_WriteTrcvRegister(cfg->instance, prtad, regad, regval); k_mutex_unlock(&data->rw_mutex); return status == E_OK ? 0 : -EIO; @@ -78,19 +80,26 @@ static const struct mdio_driver_api nxp_s32_mdio_api = { .bus_disable = nxp_s32_mdio_noop, }; -PINCTRL_DT_DEFINE(MDIO_NODE); - -static struct nxp_s32_mdio_data nxp_s32_mdio0_data; - -static const struct nxp_s32_mdio_config nxp_s32_mdio0_cfg = { - .pincfg = PINCTRL_DT_DEV_CONFIG_GET(MDIO_NODE), -}; - -DEVICE_DT_DEFINE(MDIO_NODE, - &nxp_s32_mdio_initialize, - NULL, - &nxp_s32_mdio0_data, - &nxp_s32_mdio0_cfg, - POST_KERNEL, - CONFIG_MDIO_INIT_PRIORITY, - &nxp_s32_mdio_api); +#define NXP_S32_MDIO_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_NETC_EMDIO_##n##_BASE) ? i : 0) + +#define NXP_S32_MDIO_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET NETC_F1_INSTANCE_COUNT, NXP_S32_MDIO_HW_INSTANCE_CHECK, (|), n) + +#define NXP_S32_MDIO_INSTANCE_DEFINE(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + static struct nxp_s32_mdio_data nxp_s32_mdio##n##_data; \ + static const struct nxp_s32_mdio_config nxp_s32_mdio##n##_cfg = { \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .instance = NXP_S32_MDIO_HW_INSTANCE(n), \ + }; \ + DEVICE_DT_INST_DEFINE(n, \ + &nxp_s32_mdio_initialize, \ + NULL, \ + &nxp_s32_mdio##n##_data, \ + &nxp_s32_mdio##n##_cfg, \ + POST_KERNEL, \ + CONFIG_MDIO_INIT_PRIORITY, \ + &nxp_s32_mdio_api); + +DT_INST_FOREACH_STATUS_OKAY(NXP_S32_MDIO_INSTANCE_DEFINE) diff --git a/drivers/mdio/mdio_sam.c b/drivers/mdio/mdio_sam.c index 078f12c93381a6f..5665057f7c91e41 100644 --- a/drivers/mdio/mdio_sam.c +++ b/drivers/mdio/mdio_sam.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,9 @@ struct mdio_sam_dev_data { struct mdio_sam_dev_config { Gmac * const regs; const struct pinctrl_dev_config *pcfg; +#ifdef CONFIG_SOC_FAMILY_SAM + const struct atmel_sam_pmc_config clock_cfg; +#endif }; static int mdio_transfer(const struct device *dev, uint8_t prtad, uint8_t regad, @@ -140,6 +144,15 @@ static int mdio_sam_initialize(const struct device *dev) k_sem_init(&data->sem, 1, 1); +#ifdef CONFIG_SOC_FAMILY_SAM + /* Enable GMAC module's clock */ + (void) clock_control_on(SAM_DT_PMC_CONTROLLER, (clock_control_subsys_t) &cfg->clock_cfg); +#else + /* Enable MCLK clock on GMAC */ + MCLK->AHBMASK.reg |= MCLK_AHBMASK_GMAC; + *MCLK_GMAC |= MCLK_GMAC_MASK; +#endif + retval = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); return retval; @@ -154,10 +167,16 @@ static const struct mdio_driver_api mdio_sam_driver_api = { .bus_disable = mdio_sam_bus_disable, }; +#define MDIO_SAM_CLOCK(n) \ + COND_CODE_1(CONFIG_SOC_FAMILY_SAM, \ + (.clock_cfg = SAM_DT_INST_CLOCK_PMC_CFG(n),), () \ + ) + #define MDIO_SAM_CONFIG(n) \ static const struct mdio_sam_dev_config mdio_sam_dev_config_##n = { \ .regs = (Gmac *)DT_INST_REG_ADDR(n), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + MDIO_SAM_CLOCK(n) \ }; #define MDIO_SAM_DEVICE(n) \ diff --git a/drivers/mdio/mdio_shell.c b/drivers/mdio/mdio_shell.c index b70ff7bc1a0a696..376e95244faee3c 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 000000000000000..02ebfc5096d8488 --- /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/CMakeLists.txt b/drivers/memc/CMakeLists.txt index ca967b1a045bfef..8aaedc2207352f3 100644 --- a/drivers/memc/CMakeLists.txt +++ b/drivers/memc/CMakeLists.txt @@ -11,6 +11,7 @@ zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI memc_mcux_flexspi.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_W956A8MBYA memc_mcux_flexspi_w956a8mbya.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_S27KS0641 memc_mcux_flexspi_s27ks0641.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_APS6408L memc_mcux_flexspi_aps6408l.c) +zephyr_library_sources_ifdef(CONFIG_MEMC_NXP_FLEXRAM memc_nxp_flexram.c) zephyr_library_sources_ifdef(CONFIG_MEMC_SAM_SMC memc_sam_smc.c) diff --git a/drivers/memc/Kconfig.mcux b/drivers/memc/Kconfig.mcux index ed7e73929dbee31..e801e7577aeaeb6 100644 --- a/drivers/memc/Kconfig.mcux +++ b/drivers/memc/Kconfig.mcux @@ -1,4 +1,4 @@ -# Copyright (c) 2020-2022 NXP +# Copyright 2020-2023 NXP # Copyright (c) 2021 Basalte bv # Copyright (c) 2023, ithinx GmbH # Copyright (c) 2023, Tonies GmbH @@ -28,4 +28,23 @@ config MEMC_MCUX_FLEXSPI bool select PINCTRL -endif +endif # DT_HAS_NXP_IMX_FLEXSPI_ENABLED + + +if DT_HAS_NXP_FLEXRAM_ENABLED + +config MEMC_NXP_FLEXRAM + bool + default y + +config MEMC_NXP_FLEXRAM_MAGIC_ADDR_API + bool "NXP FlexRAM magic addr API" + help + Enable API to use flexRAM magic address functionality + +config MEMC_NXP_FLEXRAM_ERROR_INTERRUPT + bool "NXP FlexRAM error interrupt" + help + Allow flexram to generate error interrupts + +endif # DT_HAS_NXP_FLEXRAM_ENABLED diff --git a/drivers/memc/memc_mcux_flexspi.c b/drivers/memc/memc_mcux_flexspi.c index d67e730fd916553..84ab86a793a1399 100644 --- a/drivers/memc/memc_mcux_flexspi.c +++ b/drivers/memc/memc_mcux_flexspi.c @@ -26,6 +26,8 @@ read-while-write hazards. This configuration is not recommended." #endif +#define FLEXSPI_MAX_LUT 64U + LOG_MODULE_REGISTER(memc_flexspi, CONFIG_MEMC_LOG_LEVEL); struct memc_flexspi_buf_cfg { @@ -35,6 +37,12 @@ struct memc_flexspi_buf_cfg { uint16_t buf_size; } __packed; +/* Structure tracking LUT offset and usage per each port */ +struct port_lut { + uint8_t lut_offset; + uint8_t lut_used; +}; + /* flexspi device data should be stored in RAM to avoid read-while-write hazards */ struct memc_flexspi_data { FLEXSPI_Type *base; @@ -49,6 +57,7 @@ struct memc_flexspi_data { flexspi_read_sample_clock_t rx_sample_clock; const struct pinctrl_dev_config *pincfg; size_t size[kFLEXSPI_PortCount]; + struct port_lut port_luts[kFLEXSPI_PortCount]; struct memc_flexspi_buf_cfg *buf_cfg; uint8_t buf_cfg_cnt; }; @@ -68,16 +77,6 @@ bool memc_flexspi_is_running_xip(const struct device *dev) return data->xip; } -int memc_flexspi_update_lut(const struct device *dev, uint32_t index, - const uint32_t *cmd, uint32_t count) -{ - struct memc_flexspi_data *data = dev->data; - - FLEXSPI_UpdateLUT(data->base, index, cmd, count); - - return 0; -} - 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) @@ -108,20 +107,65 @@ int memc_flexspi_update_clock(const struct device *dev, int memc_flexspi_set_device_config(const struct device *dev, const flexspi_device_config_t *device_config, + const uint32_t *lut_array, + uint8_t lut_count, flexspi_port_t port) { + flexspi_device_config_t tmp_config; + uint32_t tmp_lut[FLEXSPI_MAX_LUT]; struct memc_flexspi_data *data = dev->data; + const uint32_t *lut_ptr = lut_array; + uint8_t lut_used = 0U; + unsigned int key = 0; if (port >= kFLEXSPI_PortCount) { LOG_ERR("Invalid port number"); return -EINVAL; } + if (data->port_luts[port].lut_used < lut_count) { + /* We cannot reuse the existing LUT slot, + * Check if the LUT table will fit into the remaining LUT slots + */ + for (uint8_t i = 0; i < kFLEXSPI_PortCount; i++) { + lut_used += data->port_luts[i].lut_used; + } + + if ((lut_used + lut_count) > FLEXSPI_MAX_LUT) { + return -ENOBUFS; + } + } + data->size[port] = device_config->flashSize * KB(1); - FLEXSPI_SetFlashConfig(data->base, - (flexspi_device_config_t *) device_config, - port); + if (memc_flexspi_is_running_xip(dev)) { + /* We need to avoid flash access while configuring the FlexSPI. + * To do this, we will copy the LUT array into stack-allocated + * temporary memory + */ + memcpy(tmp_lut, lut_array, lut_count * MEMC_FLEXSPI_CMD_SIZE); + lut_ptr = tmp_lut; + } + + memcpy(&tmp_config, device_config, sizeof(tmp_config)); + /* Update FlexSPI AWRSEQID and ARDSEQID values based on where the LUT + * array will actually be loaded. + */ + if (data->port_luts[port].lut_used < lut_count) { + /* Update lut offset with new value */ + data->port_luts[port].lut_offset = lut_used; + } + data->port_luts[port].lut_used = lut_count; + tmp_config.ARDSeqIndex += data->port_luts[port].lut_offset; + tmp_config.AWRSeqIndex += data->port_luts[port].lut_offset; + + /* Lock IRQs before reconfiguring FlexSPI, to prevent XIP */ + key = irq_lock(); + + FLEXSPI_SetFlashConfig(data->base, &tmp_config, port); + FLEXSPI_UpdateLUT(data->base, data->port_luts[port].lut_offset, + lut_ptr, lut_count); + irq_unlock(key); return 0; } @@ -139,7 +183,11 @@ int memc_flexspi_transfer(const struct device *dev, flexspi_transfer_t *transfer) { struct memc_flexspi_data *data = dev->data; - status_t status = FLEXSPI_TransferBlocking(data->base, transfer); + status_t status; + + /* Adjust transfer LUT index based on port */ + transfer->seqIndex += data->port_luts[transfer->port].lut_offset; + status = FLEXSPI_TransferBlocking(data->base, transfer); if (status != kStatus_Success) { LOG_ERR("Transfer error: %d", status); @@ -161,7 +209,7 @@ void *memc_flexspi_get_ahb_address(const struct device *dev, } for (i = 0; i < port; i++) { - offset += data->size[port]; + offset += data->size[i]; } return data->ahb_base + offset; @@ -252,12 +300,13 @@ static int memc_flexspi_pm_action(const struct device *dev, enum pm_device_actio } #endif -#if defined(CONFIG_XIP) && defined(CONFIG_CODE_FLEXSPI) -#define MEMC_FLEXSPI_CFG_XIP(node_id) DT_SAME_NODE(node_id, DT_NODELABEL(flexspi)) -#elif defined(CONFIG_XIP) && defined(CONFIG_CODE_FLEXSPI2) -#define MEMC_FLEXSPI_CFG_XIP(node_id) DT_SAME_NODE(node_id, DT_NODELABEL(flexspi2)) -#elif defined(CONFIG_SOC_SERIES_IMX_RT6XX) || defined(CONFIG_SOC_SERIES_IMX_RT5XX) -#define MEMC_FLEXSPI_CFG_XIP(node_id) DT_SAME_NODE(node_id, DT_NODELABEL(flexspi)) +#if defined(CONFIG_XIP) && defined(CONFIG_FLASH_MCUX_FLEXSPI_XIP) +/* Checks if image flash base address is in the FlexSPI AHB base region */ +#define MEMC_FLEXSPI_CFG_XIP(node_id) \ + ((CONFIG_FLASH_BASE_ADDRESS) >= DT_REG_ADDR_BY_IDX(node_id, 1)) && \ + ((CONFIG_FLASH_BASE_ADDRESS) < (DT_REG_ADDR_BY_IDX(node_id, 1) + \ + DT_REG_SIZE_BY_IDX(node_id, 1))) + #else #define MEMC_FLEXSPI_CFG_XIP(node_id) false #endif diff --git a/drivers/memc/memc_mcux_flexspi.h b/drivers/memc/memc_mcux_flexspi.h index 3d201c7b6d7f667..a8495fc928907a8 100644 --- a/drivers/memc/memc_mcux_flexspi.h +++ b/drivers/memc/memc_mcux_flexspi.h @@ -1,5 +1,5 @@ /* - * Copyright 2020 NXP + * Copyright 2020,2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,25 +15,94 @@ enum memc_flexspi_clock_t { MEMC_FLEXSPI_CLOCK_42M, }; +/* Size of a command in the LUT table */ +#define MEMC_FLEXSPI_CMD_SIZE 4U + +/** + * @brief Wait for the FlexSPI bus to be idle + * + * Waits for the FlexSPI bus to be idle. Can be used when reconfiguring + * the FlexSPI to make sure no flash access is occurring before changing + * settings. + * + * @param dev: FlexSPI device + */ void memc_flexspi_wait_bus_idle(const struct device *dev); +/** + * @brief Check if FlexSPI is being used in XIP mode. + * + * Checks if the FlexSPI is being used for code execution in the current + * application. + * + * @param dev: FlexSPI device + * @retval true if FlexSPI being used for XIP + */ bool memc_flexspi_is_running_xip(const struct device *dev); -int memc_flexspi_update_lut(const struct device *dev, uint32_t index, - const uint32_t *cmd, uint32_t count); - +/** + * @brief Update clock selection of the FlexSPI device + * + * Updates clock selection of the FlexSPI device to a 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 + * @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); +/** + * @brief configure new FlexSPI device + * + * Configures new device on the FlexSPI bus. + * @param dev: FlexSPI device + * @param device_config: External device configuration. + * @param lut_array: Lookup table of FlexSPI flash commands for device + * @param lut_count: number of command entries (16 bytes each) in LUT + * @param port: FlexSPI port to use for this external device + * @return 0 on success, negative value on failure + */ int memc_flexspi_set_device_config(const struct device *dev, const flexspi_device_config_t *device_config, + const uint32_t *lut_array, + uint8_t lut_count, flexspi_port_t port); + +/** + * @brief Perform software reset of FlexSPI + * + * Software reset of FlexSPI. Does not clear configuration registers. + * @param dev: FlexSPI device + * @return 0 on success, negative value on failure + */ int memc_flexspi_reset(const struct device *dev); +/** + * @brief Send blocking IP transfer + * + * Send blocking IP transfer using FlexSPI. + * @param dev: FlexSPI device + * @param transfer: FlexSPI transfer. seqIndex should be set as though the + * LUT array was loaded at offset 0. + * @return 0 on success, negative value on failure + */ int memc_flexspi_transfer(const struct device *dev, flexspi_transfer_t *transfer); +/** + * @brief Get AHB address for FlexSPI port + * + * Get AHB address for FlexSPI port. This address is memory mapped, and can be + * read from (and written to, for PSRAM) as though it were internal memory. + * @param dev: FlexSPI device + * @param port: FlexSPI port external device is on + * @param offset: byte offset from start of device to get AHB address for + * @return 0 on success, negative value on failure + */ void *memc_flexspi_get_ahb_address(const struct device *dev, flexspi_port_t port, off_t offset); diff --git a/drivers/memc/memc_mcux_flexspi_aps6408l.c b/drivers/memc/memc_mcux_flexspi_aps6408l.c index 0c295221a105a0f..a9b51e77bfa81be 100644 --- a/drivers/memc/memc_mcux_flexspi_aps6408l.c +++ b/drivers/memc/memc_mcux_flexspi_aps6408l.c @@ -215,18 +215,13 @@ static int memc_flexspi_aps6408l_init(const struct device *dev) } if (memc_flexspi_set_device_config(data->controller, &config->config, - config->port)) { + (const uint32_t *) memc_flexspi_aps6408l_lut, + sizeof(memc_flexspi_aps6408l_lut) / MEMC_FLEXSPI_CMD_SIZE, + config->port)) { LOG_ERR("Could not set device configuration"); return -EINVAL; } - if (memc_flexspi_update_lut(data->controller, 0, - (const uint32_t *) memc_flexspi_aps6408l_lut, - sizeof(memc_flexspi_aps6408l_lut) / 4)) { - LOG_ERR("Could not update lut"); - return -EINVAL; - } - memc_flexspi_reset(data->controller); if (memc_flexspi_aps6408l_reset(dev)) { diff --git a/drivers/memc/memc_mcux_flexspi_s27ks0641.c b/drivers/memc/memc_mcux_flexspi_s27ks0641.c index ee7431c920136f7..36fc5bf830690ac 100644 --- a/drivers/memc/memc_mcux_flexspi_s27ks0641.c +++ b/drivers/memc/memc_mcux_flexspi_s27ks0641.c @@ -122,18 +122,13 @@ static int memc_flexspi_s27ks0641_init(const struct device *dev) } if (memc_flexspi_set_device_config(data->controller, &config->config, - config->port)) { + (const uint32_t *) memc_flexspi_s27ks0641_lut, + sizeof(memc_flexspi_s27ks0641_lut) / MEMC_FLEXSPI_CMD_SIZE, + config->port)) { LOG_ERR("Could not set device configuration"); return -EINVAL; } - if (memc_flexspi_update_lut(data->controller, 0, - (const uint32_t *) memc_flexspi_s27ks0641_lut, - sizeof(memc_flexspi_s27ks0641_lut) / 4)) { - LOG_ERR("Could not update lut"); - return -EINVAL; - } - memc_flexspi_reset(data->controller); if (memc_flexspi_s27ks0641_get_vendor_id(dev, &vendor_id)) { diff --git a/drivers/memc/memc_mcux_flexspi_w956a8mbya.c b/drivers/memc/memc_mcux_flexspi_w956a8mbya.c index ad24ecccdc77c7c..60c5949b73fc554 100644 --- a/drivers/memc/memc_mcux_flexspi_w956a8mbya.c +++ b/drivers/memc/memc_mcux_flexspi_w956a8mbya.c @@ -114,18 +114,13 @@ static int memc_flexspi_w956a8mbya_init(const struct device *dev) } if (memc_flexspi_set_device_config(data->controller, &config->config, - config->port)) { + (const uint32_t *) memc_flexspi_w956a8mbya_lut, + sizeof(memc_flexspi_w956a8mbya_lut) / MEMC_FLEXSPI_CMD_SIZE, + config->port)) { LOG_ERR("Could not set device configuration"); return -EINVAL; } - if (memc_flexspi_update_lut(data->controller, 0, - (const uint32_t *) memc_flexspi_w956a8mbya_lut, - sizeof(memc_flexspi_w956a8mbya_lut) / 4)) { - LOG_ERR("Could not update lut"); - return -EINVAL; - } - memc_flexspi_reset(data->controller); if (memc_flexspi_w956a8mbya_get_vendor_id(dev, &vendor_id)) { diff --git a/drivers/memc/memc_nxp_flexram.c b/drivers/memc/memc_nxp_flexram.c new file mode 100644 index 000000000000000..39da8349e1ab657 --- /dev/null +++ b/drivers/memc/memc_nxp_flexram.c @@ -0,0 +1,231 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "memc_nxp_flexram.h" +#include +#include +#include +#include +#include +#include + +#include "fsl_device_registers.h" + + +#if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API) +BUILD_ASSERT(DT_PROP(FLEXRAM_DT_NODE, flexram_has_magic_addr), + "SOC does not support magic flexram addresses"); +#endif + +#define BANK_SIZE (DT_PROP(FLEXRAM_DT_NODE, flexram_bank_size) * 1024) +#define NUM_BANKS DT_PROP(FLEXRAM_DT_NODE, flexram_num_ram_banks) + +#define IS_CHILD_RAM_TYPE(node_id, compat) DT_NODE_HAS_COMPAT(node_id, compat) +#define DOES_RAM_TYPE_EXIST(compat) \ + DT_FOREACH_CHILD_SEP_VARGS(FLEXRAM_DT_NODE, IS_CHILD_RAM_TYPE, (+), compat) + +#if DOES_RAM_TYPE_EXIST(mmio_sram) +#define FIND_OCRAM_NODE(node_id) \ + COND_CODE_1(DT_NODE_HAS_COMPAT(node_id, mmio_sram), (node_id), ()) +#define OCRAM_DT_NODE DT_FOREACH_CHILD(FLEXRAM_DT_NODE, FIND_OCRAM_NODE) +#define OCRAM_START (DT_REG_ADDR(OCRAM_DT_NODE)) +#define OCRAM_END (OCRAM_START + DT_REG_SIZE(OCRAM_DT_NODE)) +#endif /* OCRAM */ +#if DOES_RAM_TYPE_EXIST(nxp_imx_dtcm) +#define FIND_DTCM_NODE(node_id) \ + COND_CODE_1(DT_NODE_HAS_COMPAT(node_id, nxp_imx_dtcm), (node_id), ()) +#define DTCM_DT_NODE DT_FOREACH_CHILD(FLEXRAM_DT_NODE, FIND_DTCM_NODE) +#define DTCM_START (DT_REG_ADDR(DTCM_DT_NODE)) +#define DTCM_END (DTCM_START + DT_REG_SIZE(DTCM_DT_NODE)) +#endif /* DTCM */ +#if DOES_RAM_TYPE_EXIST(nxp_imx_itcm) +#define FIND_ITCM_NODE(node_id) \ + COND_CODE_1(DT_NODE_HAS_COMPAT(node_id, nxp_imx_itcm), (node_id), ()) +#define ITCM_DT_NODE DT_FOREACH_CHILD(FLEXRAM_DT_NODE, FIND_ITCM_NODE) +#define ITCM_START (DT_REG_ADDR(ITCM_DT_NODE)) +#define ITCM_END (ITCM_START + DT_REG_SIZE(ITCM_DT_NODE)) +#endif /* ITCM */ + + +#ifdef FLEXRAM_RUNTIME_BANKS_USED + +#define PLUS_ONE_BANK(node_id, prop, idx) 1 +#define COUNT_BANKS \ + DT_FOREACH_PROP_ELEM_SEP(FLEXRAM_DT_NODE, flexram_bank_spec, PLUS_ONE_BANK, (+)) +BUILD_ASSERT(COUNT_BANKS == NUM_BANKS, "wrong number of flexram banks defined"); + +#ifdef OCRAM_DT_NODE +#define ADD_BANK_IF_OCRAM(node_id, prop, idx) \ + COND_CODE_1(IS_EQ(DT_PROP_BY_IDX(node_id, prop, idx), FLEXRAM_OCRAM), \ + (BANK_SIZE), (0)) +#define OCRAM_TOTAL \ + DT_FOREACH_PROP_ELEM_SEP(FLEXRAM_DT_NODE, flexram_bank_spec, ADD_BANK_IF_OCRAM, (+)) +BUILD_ASSERT((OCRAM_TOTAL) == DT_REG_SIZE(OCRAM_DT_NODE), "OCRAM node size is wrong"); +#endif /* OCRAM */ + +#ifdef DTCM_DT_NODE +#define ADD_BANK_IF_DTCM(node_id, prop, idx) \ + COND_CODE_1(IS_EQ(DT_PROP_BY_IDX(node_id, prop, idx), FLEXRAM_DTCM), \ + (BANK_SIZE), (0)) +#define DTCM_TOTAL \ + DT_FOREACH_PROP_ELEM_SEP(FLEXRAM_DT_NODE, flexram_bank_spec, ADD_BANK_IF_DTCM, (+)) +BUILD_ASSERT((DTCM_TOTAL) == DT_REG_SIZE(DTCM_DT_NODE), "DTCM node size is wrong"); +#endif /* DTCM */ + +#ifdef ITCM_DT_NODE +#define ADD_BANK_IF_ITCM(node_id, prop, idx) \ + COND_CODE_1(IS_EQ(DT_PROP_BY_IDX(node_id, prop, idx), FLEXRAM_ITCM), \ + (BANK_SIZE), (0)) +#define ITCM_TOTAL \ + DT_FOREACH_PROP_ELEM_SEP(FLEXRAM_DT_NODE, flexram_bank_spec, ADD_BANK_IF_ITCM, (+)) +BUILD_ASSERT((ITCM_TOTAL) == DT_REG_SIZE(ITCM_DT_NODE), "ITCM node size is wrong"); +#endif /* ITCM */ + +#endif /* FLEXRAM_RUNTIME_BANKS_USED */ + +static FLEXRAM_Type *const base = (FLEXRAM_Type *) DT_REG_ADDR(FLEXRAM_DT_NODE); + +#ifdef FLEXRAM_INTERRUPTS_USED +static flexram_callback_t flexram_callback; +static void *flexram_user_data; + +void memc_flexram_register_callback(flexram_callback_t callback, void *user_data) +{ + flexram_callback = callback; + flexram_user_data = user_data; +} + +static void nxp_flexram_isr(void *arg) +{ + ARG_UNUSED(arg); + + if (flexram_callback == NULL) { + return; + } + +#if defined(CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT) + if (base->INT_STATUS & FLEXRAM_INT_STATUS_OCRAM_ERR_STATUS_MASK) { + base->INT_STATUS |= FLEXRAM_INT_STATUS_OCRAM_ERR_STATUS_MASK; + flexram_callback(flexram_ocram_access_error, flexram_user_data); + } + if (base->INT_STATUS & FLEXRAM_INT_STATUS_DTCM_ERR_STATUS_MASK) { + base->INT_STATUS |= FLEXRAM_INT_STATUS_DTCM_ERR_STATUS_MASK; + flexram_callback(flexram_dtcm_access_error, flexram_user_data); + } + if (base->INT_STATUS & FLEXRAM_INT_STATUS_ITCM_ERR_STATUS_MASK) { + base->INT_STATUS |= FLEXRAM_INT_STATUS_ITCM_ERR_STATUS_MASK; + flexram_callback(flexram_itcm_access_error, flexram_user_data); + } +#endif /* CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT */ + +#if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API) + if (base->INT_STATUS & FLEXRAM_INT_STATUS_OCRAM_MAM_STATUS_MASK) { + base->INT_STATUS |= FLEXRAM_INT_STATUS_OCRAM_MAM_STATUS_MASK; + flexram_callback(flexram_ocram_magic_addr, flexram_user_data); + } + if (base->INT_STATUS & FLEXRAM_INT_STATUS_DTCM_MAM_STATUS_MASK) { + base->INT_STATUS |= FLEXRAM_INT_STATUS_DTCM_MAM_STATUS_MASK; + flexram_callback(flexram_dtcm_magic_addr, flexram_user_data); + } + if (base->INT_STATUS & FLEXRAM_INT_STATUS_ITCM_MAM_STATUS_MASK) { + base->INT_STATUS |= FLEXRAM_INT_STATUS_ITCM_MAM_STATUS_MASK; + flexram_callback(flexram_itcm_magic_addr, flexram_user_data); + } +#endif /* CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API */ +} + +#if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API) +int memc_flexram_set_ocram_magic_addr(uint32_t ocram_addr) +{ +#ifdef OCRAM_DT_NODE + ocram_addr -= DT_REG_ADDR(OCRAM_DT_NODE); + if (ocram_addr >= DT_REG_SIZE(OCRAM_DT_NODE)) { + return -EINVAL; + } + + base->OCRAM_MAGIC_ADDR &= ~FLEXRAM_OCRAM_MAGIC_ADDR_OCRAM_MAGIC_ADDR_MASK; + base->OCRAM_MAGIC_ADDR |= FLEXRAM_OCRAM_MAGIC_ADDR_OCRAM_MAGIC_ADDR(ocram_addr); + + base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_OCRAM_MAM_STAT_EN_MASK; + return 0; +#else + return -ENODEV; +#endif +} + +int memc_flexram_set_itcm_magic_addr(uint32_t itcm_addr) +{ +#ifdef ITCM_DT_NODE + itcm_addr -= DT_REG_ADDR(ITCM_DT_NODE); + if (itcm_addr >= DT_REG_SIZE(ITCM_DT_NODE)) { + return -EINVAL; + } + + base->ITCM_MAGIC_ADDR &= ~FLEXRAM_ITCM_MAGIC_ADDR_ITCM_MAGIC_ADDR_MASK; + base->ITCM_MAGIC_ADDR |= FLEXRAM_ITCM_MAGIC_ADDR_ITCM_MAGIC_ADDR(itcm_addr); + + base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_ITCM_MAM_STAT_EN_MASK; + return 0; +#else + return -ENODEV; +#endif +} + +int memc_flexram_set_dtcm_magic_addr(uint32_t dtcm_addr) +{ +#ifdef DTCM_DT_NODE + dtcm_addr -= DT_REG_ADDR(DTCM_DT_NODE); + if (dtcm_addr >= DT_REG_SIZE(DTCM_DT_NODE)) { + return -EINVAL; + } + + base->DTCM_MAGIC_ADDR &= ~FLEXRAM_DTCM_MAGIC_ADDR_DTCM_MAGIC_ADDR_MASK; + base->DTCM_MAGIC_ADDR |= FLEXRAM_DTCM_MAGIC_ADDR_DTCM_MAGIC_ADDR(dtcm_addr); + + base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_DTCM_MAM_STAT_EN_MASK; + return 0; +#else + return -ENODEV; +#endif +} +#endif /* CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API */ + +#endif /* FLEXRAM_INTERRUPTS_USED */ + +static int nxp_flexram_init(void) +{ + if (DT_PROP(FLEXRAM_DT_NODE, flexram_tcm_read_wait_mode)) { + base->TCM_CTRL |= FLEXRAM_TCM_CTRL_TCM_WWAIT_EN_MASK; + } + if (DT_PROP(FLEXRAM_DT_NODE, flexram_tcm_write_wait_mode)) { + base->TCM_CTRL |= FLEXRAM_TCM_CTRL_TCM_RWAIT_EN_MASK; + } + +#if defined(CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT) + base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_OCRAM_ERR_SIG_EN_MASK; + base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_DTCM_ERR_SIG_EN_MASK; + base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_ITCM_ERR_SIG_EN_MASK; + base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_OCRAM_ERR_STAT_EN_MASK; + base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_DTCM_ERR_STAT_EN_MASK; + base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_ITCM_ERR_STAT_EN_MASK; +#endif /* CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT */ + +#if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API) + base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_OCRAM_MAM_SIG_EN_MASK; + base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_DTCM_MAM_SIG_EN_MASK; + base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_ITCM_MAM_SIG_EN_MASK; +#endif /* CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API */ + +#ifdef FLEXRAM_INTERRUPTS_USED + IRQ_CONNECT(DT_IRQN(FLEXRAM_DT_NODE), DT_IRQ(FLEXRAM_DT_NODE, priority), + nxp_flexram_isr, NULL, 0); + irq_enable(DT_IRQN(FLEXRAM_DT_NODE)); +#endif /* FLEXRAM_INTERRUPTS_USED */ + + return 0; +} + +SYS_INIT(nxp_flexram_init, EARLY, 0); diff --git a/drivers/memc/memc_nxp_flexram.h b/drivers/memc/memc_nxp_flexram.h new file mode 100644 index 000000000000000..5ea2e89d0cce64e --- /dev/null +++ b/drivers/memc/memc_nxp_flexram.h @@ -0,0 +1,98 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define FLEXRAM_DT_NODE DT_INST(0, nxp_flexram) +#define IOMUXC_GPR_DT_NODE DT_NODELABEL(iomuxcgpr) + +#if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API) || \ + defined(CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT) +#define FLEXRAM_INTERRUPTS_USED +#endif + +#if DT_PROP_HAS_IDX(FLEXRAM_DT_NODE, flexram_bank_spec, 0) +#define FLEXRAM_RUNTIME_BANKS_USED 1 +#endif + +#ifdef FLEXRAM_INTERRUPTS_USED +enum memc_flexram_interrupt_cause { +#ifdef CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT + flexram_ocram_access_error, + flexram_itcm_access_error, + flexram_dtcm_access_error, +#endif +#ifdef CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API + flexram_ocram_magic_addr, + flexram_itcm_magic_addr, + flexram_dtcm_magic_addr, +#endif /* CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API */ +}; + +typedef void (*flexram_callback_t)(enum memc_flexram_interrupt_cause, void *user_data); + +void memc_flexram_register_callback(flexram_callback_t callback, void *user_data); +#endif /* FLEXRAM_INTERRUPTS_USED */ + +#ifdef FLEXRAM_RUNTIME_BANKS_USED + +/* + * call from platform_init to set up flexram if using runtime map + * must be inlined because cannot use stack + */ +#define GPR17_REG_FILL(node_id, prop, idx) + (DT_PROP_BY_IDX(node_id, prop, idx) << (2*idx)) +static inline void memc_flexram_dt_partition(void) +{ + /* iomuxc_gpr must be const (in ROM region) because used in reconfiguring ram */ + static IOMUXC_GPR_Type *const iomuxc_gpr = + (IOMUXC_GPR_Type *) DT_REG_ADDR(IOMUXC_GPR_DT_NODE); + /* do not create stack variables or use any data from ram in this function */ + iomuxc_gpr->GPR17 = DT_FOREACH_PROP_ELEM_SEP(FLEXRAM_DT_NODE, + flexram_bank_spec, GPR17_REG_FILL, (+)); + iomuxc_gpr->GPR16 |= IOMUXC_GPR_GPR16_FLEXRAM_BANK_CFG_SEL_MASK; +} +#endif /* FLEXRAM_RUNTIME_BANKS_USED */ + + +#ifdef CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API +/** @brief Sets magic address for OCRAM + * + * Magic address allows core interrupt from FlexRAM when address + * is accessed. + * + * @param ocram_addr: An address in OCRAM to set magic function on. + * @retval 0 on success + * @retval -EINVAL if ocram_addr is not in OCRAM + * @retval -ENODEV if there is no OCRAM allocation in flexram + */ +int memc_flexram_set_ocram_magic_addr(uint32_t ocram_addr); + +/** @brief Sets magic address for ITCM + * + * Magic address allows core interrupt from FlexRAM when address + * is accessed. + * + * @param itcm_addr: An address in ITCM to set magic function on. + * @retval 0 on success + * @retval -EINVAL if itcm_addr is not in ITCM + * @retval -ENODEV if there is no ITCM allocation in flexram + */ +int memc_flexram_set_itcm_magic_addr(uint32_t itcm_addr); + +/** @brief Sets magic address for DTCM + * + * Magic address allows core interrupt from FlexRAM when address + * is accessed. + * + * @param dtcm_addr: An address in DTCM to set magic function on. + * @retval 0 on success + * @retval -EINVAL if dtcm_addr is not in DTCM + * @retval -ENODEV if there is no DTCM allocation in flexram + */ +int memc_flexram_set_dtcm_magic_addr(uint32_t dtcm_addr); + +#endif /* CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API */ diff --git a/drivers/memc/memc_nxp_s32_qspi.c b/drivers/memc/memc_nxp_s32_qspi.c index b2dc1466d6fcfce..f588a0bd9af7633 100644 --- a/drivers/memc/memc_nxp_s32_qspi.c +++ b/drivers/memc/memc_nxp_s32_qspi.c @@ -78,7 +78,7 @@ uint8_t memc_nxp_s32_qspi_get_instance(const struct device *dev) #define QSPI_DATA_CFG(n) \ IF_ENABLED(FEATURE_QSPI_DDR, ( \ - .dataRate = CONCAT(QSPI_IP_DATA_RATE_, \ + .dataRate = _CONCAT(QSPI_IP_DATA_RATE_, \ DT_INST_STRING_UPPER_TOKEN(n, data_rate)), \ .dataAlign = COND_CODE_1(DT_INST_PROP(n, hold_time_2x), \ (QSPI_IP_FLASH_DATA_ALIGN_2X_REFCLK), \ @@ -115,7 +115,7 @@ uint8_t memc_nxp_s32_qspi_get_instance(const struct device *dev) #define QSPI_DLL_CFG(n, side, side_upper) \ IF_ENABLED(FEATURE_QSPI_HAS_DLL, ( \ .dllSettings##side_upper = { \ - .dllMode = CONCAT(QSPI_IP_DLL_, \ + .dllMode = _CONCAT(QSPI_IP_DLL_, \ DT_INST_STRING_UPPER_TOKEN(n, side##_dll_mode)), \ .freqEnable = DT_INST_PROP(n, side##_dll_freq_enable), \ .coarseDelay = DT_INST_PROP(n, side##_dll_coarse_delay), \ @@ -129,7 +129,7 @@ uint8_t memc_nxp_s32_qspi_get_instance(const struct device *dev) )) #define QSPI_READ_MODE(n, side, side_upper) \ - CONCAT(QSPI_IP_READ_MODE_, DT_INST_STRING_UPPER_TOKEN(n, side##_rx_clock_source)) + _CONCAT(QSPI_IP_READ_MODE_, DT_INST_STRING_UPPER_TOKEN(n, side##_rx_clock_source)) #define QSPI_IDLE_SIGNAL_DRIVE(n, side, side_upper) \ IF_ENABLED(FEATURE_QSPI_CONFIGURABLE_ISD, ( \ @@ -160,7 +160,7 @@ uint8_t memc_nxp_s32_qspi_get_instance(const struct device *dev) BUILD_ASSERT(DT_INST_PROP_LEN(n, ahb_buffers_sizes) == QSPI_IP_AHB_BUFFERS, \ "ahb-buffers-sizes must be of size QSPI_IP_AHB_BUFFERS"); \ BUILD_ASSERT( \ - CONCAT(FEATURE_QSPI_, DT_INST_STRING_UPPER_TOKEN(n, a_rx_clock_source)) == 1,\ + _CONCAT(FEATURE_QSPI_, DT_INST_STRING_UPPER_TOKEN(n, a_rx_clock_source)) == 1,\ "a-rx-clock-source source mode selected is not supported"); \ \ static const Qspi_Ip_ControllerConfigType \ diff --git a/drivers/memc/memc_stm32.c b/drivers/memc/memc_stm32.c index 27786c161239212..1609926b8885cdb 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/CMakeLists.txt b/drivers/mfd/CMakeLists.txt index e8e59dd16928bf6..5141a86c2eeb744 100644 --- a/drivers/mfd/CMakeLists.txt +++ b/drivers/mfd/CMakeLists.txt @@ -3,7 +3,9 @@ zephyr_library() +zephyr_library_sources_ifdef(CONFIG_MFD_MAX20335 mfd_max20335.c) zephyr_library_sources_ifdef(CONFIG_MFD_NCT38XX mfd_nct38xx.c) zephyr_library_sources_ifdef(CONFIG_MFD_NPM1300 mfd_npm1300.c) zephyr_library_sources_ifdef(CONFIG_MFD_NPM6001 mfd_npm6001.c) zephyr_library_sources_ifdef(CONFIG_MFD_AXP192 mfd_axp192.c) +zephyr_library_sources_ifdef(CONFIG_MFD_AD5592 mfd_ad5592.c) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index be84e348c048e69..1a400d6383edc6c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -14,11 +14,13 @@ source "subsys/logging/Kconfig.template.log_config" config MFD_INIT_PRIORITY int "Initialization priority" - default 60 + default 80 help Multi-function devices initialization priority. +source "drivers/mfd/Kconfig.ad5592" source "drivers/mfd/Kconfig.axp192" +source "drivers/mfd/Kconfig.max20335" source "drivers/mfd/Kconfig.nct38xx" source "drivers/mfd/Kconfig.npm1300" source "drivers/mfd/Kconfig.npm6001" diff --git a/drivers/mfd/Kconfig.ad5592 b/drivers/mfd/Kconfig.ad5592 new file mode 100644 index 000000000000000..8b94f5517cb3377 --- /dev/null +++ b/drivers/mfd/Kconfig.ad5592 @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Grinn +# SPDX -License-Identifier: Apache-2.0 + +config MFD_AD5592 + bool "Analog AD5592 SPI configurable ADC/DAC/GPIO chip" + default y + depends on DT_HAS_ADI_AD5592_ENABLED + depends on SPI + help + Enable driver for Analog AD5592. diff --git a/drivers/mfd/Kconfig.max20335 b/drivers/mfd/Kconfig.max20335 new file mode 100644 index 000000000000000..3d146de17f089e4 --- /dev/null +++ b/drivers/mfd/Kconfig.max20335 @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Grinn +# SPDX -License-Identifier: Apache-2.0 + +config MFD_MAX20335 + bool "MAX20335 PMIC multi-function device driver" + default y + depends on DT_HAS_MAXIM_MAX20335_ENABLED + select I2C + help + Enable the Maxim MAX20335 PMIC multi-function device driver diff --git a/drivers/mfd/Kconfig.npm1300 b/drivers/mfd/Kconfig.npm1300 index cc3eb0ef30332ac..506508bd9021033 100644 --- a/drivers/mfd/Kconfig.npm1300 +++ b/drivers/mfd/Kconfig.npm1300 @@ -8,3 +8,10 @@ config MFD_NPM1300 select I2C help Enable the Nordic nPM1300 PMIC multi-function device driver + +config MFD_NPM1300_INIT_PRIORITY + int "nPM1300 MFD initialization priority" + default MFD_INIT_PRIORITY + depends on MFD_NPM1300 + help + Multi-function device initialization priority for nPM1300. diff --git a/drivers/mfd/Kconfig.npm6001 b/drivers/mfd/Kconfig.npm6001 index 10360aa2347c14c..b81c942f2d63c2c 100644 --- a/drivers/mfd/Kconfig.npm6001 +++ b/drivers/mfd/Kconfig.npm6001 @@ -8,3 +8,10 @@ config MFD_NPM6001 select I2C help Enable the Nordic nPM6001 PMIC multi-function device driver + +config MFD_NPM6001_INIT_PRIORITY + int "nPM6001 MFD initialization priority" + default MFD_INIT_PRIORITY + depends on MFD_NPM6001 + help + Multi-function device initialization priority for nPM6001. diff --git a/drivers/mfd/mfd_ad5592.c b/drivers/mfd/mfd_ad5592.c new file mode 100644 index 000000000000000..2c320fa549e0ebc --- /dev/null +++ b/drivers/mfd/mfd_ad5592.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_ad5592 + +#include +#include +#include +#include + +#include + +#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 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 + +#define AD5592_SPI_SPEC_CONF (SPI_WORD_SET(8) | SPI_TRANSFER_MSB | \ + SPI_OP_MODE_MASTER | SPI_MODE_CPOL) + +struct mfd_ad5592_config { + struct gpio_dt_spec reset_gpio; + struct spi_dt_spec bus; +}; + +int mfd_ad5592_read_raw(const struct device *dev, uint16_t *val) +{ + const struct mfd_ad5592_config *config = dev->config; + uint16_t nop_msg = 0; + + struct spi_buf tx_buf[] = { + { + .buf = &nop_msg, + .len = sizeof(nop_msg) + } + }; + + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = 1 + }; + + struct spi_buf rx_buf[] = { + { + .buf = val, + .len = sizeof(uint16_t) + } + }; + + const struct spi_buf_set rx = { + .buffers = rx_buf, + .count = 1 + }; + + return spi_transceive_dt(&config->bus, &tx, &rx); +} + +int mfd_ad5592_write_raw(const struct device *dev, uint16_t val) +{ + const struct mfd_ad5592_config *config = dev->config; + + struct spi_buf tx_buf[] = { + { + .buf = &val, + .len = sizeof(val) + } + }; + + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = 1 + }; + + return spi_write_dt(&config->bus, &tx); +} + +int mfd_ad5592_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, uint16_t *val) +{ + uint16_t data; + uint16_t msg; + int ret; + + switch (reg) { + case AD5592_REG_GPIO_INPUT_EN: + msg = sys_cpu_to_be16(AD5592_GPIO_READBACK_EN | + (AD5592_REG_GPIO_INPUT_EN << AD5592_REG_SHIFT_VAL) | + reg_data); + break; + default: + msg = sys_cpu_to_be16(AD5592_LDAC_READBACK_EN | + (AD5592_REG_READ_AND_LDAC << AD5592_REG_SHIFT_VAL) | + reg << AD5592_REG_READBACK_SHIFT_VAL); + break; + } + + ret = mfd_ad5592_write_raw(dev, msg); + if (ret < 0) { + return ret; + } + + ret = mfd_ad5592_read_raw(dev, &data); + if (ret < 0) { + return ret; + } + + *val = sys_be16_to_cpu(data); + + return 0; +} + +int mfd_ad5592_write_reg(const struct device *dev, uint8_t reg, uint16_t val) +{ + 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); +} + +static int mfd_add592_software_reset(const struct device *dev) +{ + return mfd_ad5592_write_reg(dev, + AD5592_REG_SOFTWARE_RESET, + AD5592_SOFTWARE_RESET_MAGIC_VAL); +} + +static int mfd_ad5592_init(const struct device *dev) +{ + const struct mfd_ad5592_config *config = dev->config; + int ret; + + if (!spi_is_ready_dt(&config->bus)) { + return -ENODEV; + } + + if (!gpio_is_ready_dt(&config->reset_gpio)) { + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + return ret; + } + + ret = mfd_add592_software_reset(dev); + if (ret < 0) { + return ret; + } + + return 0; +} + +#define MFD_AD5592_DEFINE(inst) \ + static const struct mfd_ad5592_config mfd_ad5592_config_##inst = { \ + .reset_gpio = GPIO_DT_SPEC_INST_GET(inst, reset_gpios), \ + .bus = SPI_DT_SPEC_INST_GET(inst, AD5592_SPI_SPEC_CONF, 0), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, mfd_ad5592_init, NULL, \ + NULL, \ + &mfd_ad5592_config_##inst, \ + POST_KERNEL, \ + CONFIG_MFD_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(MFD_AD5592_DEFINE); diff --git a/drivers/mfd/mfd_max20335.c b/drivers/mfd/mfd_max20335.c new file mode 100644 index 000000000000000..7ea6a9f198cfdac --- /dev/null +++ b/drivers/mfd/mfd_max20335.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT maxim_max20335 + +#include + +#include +#include + +#define MAX20335_REG_CHIP_ID 0x00 +#define MAX20335_CHIP_ID_VAL 0x04 + +struct mfd_max20335_config { + struct i2c_dt_spec bus; +}; + +static int mfd_max20335_init(const struct device *dev) +{ + const struct mfd_max20335_config *config = dev->config; + uint8_t val; + int ret; + + if (!i2c_is_ready_dt(&config->bus)) { + return -ENODEV; + } + + ret = i2c_reg_read_byte_dt(&config->bus, MAX20335_REG_CHIP_ID, &val); + if (ret < 0) { + return ret; + } + + if (val != MAX20335_CHIP_ID_VAL) { + return -ENODEV; + } + + return 0; +} + +#define MFD_MA20335_DEFINE(inst) \ + static const struct mfd_max20335_config mfd_max20335_config##inst = { \ + .bus = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, mfd_max20335_init, NULL, NULL, \ + &mfd_max20335_config##inst, POST_KERNEL, \ + CONFIG_MFD_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(MFD_MA20335_DEFINE) diff --git a/drivers/mfd/mfd_npm1300.c b/drivers/mfd/mfd_npm1300.c index d0632422556d2c0..ef06b6da7f000f9 100644 --- a/drivers/mfd/mfd_npm1300.c +++ b/drivers/mfd/mfd_npm1300.c @@ -64,6 +64,7 @@ static const struct event_reg_t event_reg[NPM1300_EVENT_MAX] = { [NPM1300_EVENT_BATTERY_DETECTED] = {0x0EU, 0x01U}, [NPM1300_EVENT_BATTERY_REMOVED] = {0x0EU, 0x02U}, [NPM1300_EVENT_SHIPHOLD_PRESS] = {0x12U, 0x01U}, + [NPM1300_EVENT_SHIPHOLD_RELEASE] = {0x12U, 0x02U}, [NPM1300_EVENT_WATCHDOG_WARN] = {0x12U, 0x08U}, [NPM1300_EVENT_VBUS_DETECTED] = {0x16U, 0x01U}, [NPM1300_EVENT_VBUS_REMOVED] = {0x16U, 0x02U}}; @@ -78,12 +79,14 @@ static void gpio_callback(const struct device *dev, struct gpio_callback *cb, ui static void work_callback(struct k_work *work) { struct mfd_npm1300_data *data = CONTAINER_OF(work, struct mfd_npm1300_data, work); + const struct mfd_npm1300_config *config = data->dev->config; uint8_t buf[MAIN_SIZE]; int ret; /* Read all MAIN registers into temporary buffer */ ret = mfd_npm1300_reg_read_burst(data->dev, MAIN_BASE, 0U, buf, sizeof(buf)); if (ret < 0) { + k_work_submit(&data->work); return; } @@ -96,10 +99,16 @@ static void work_callback(struct k_work *work) ret = mfd_npm1300_reg_write(data->dev, MAIN_BASE, offset, event_reg[i].mask); if (ret < 0) { + k_work_submit(&data->work); return; } } } + + /* Resubmit handler to queue if interrupt is still active */ + if (gpio_pin_get_dt(&config->host_int_gpios) != 0) { + k_work_submit(&data->work); + } } static int mfd_npm1300_init(const struct device *dev) @@ -288,6 +297,6 @@ int mfd_npm1300_remove_callback(const struct device *dev, struct gpio_callback * }; \ \ DEVICE_DT_INST_DEFINE(inst, mfd_npm1300_init, NULL, &data_##inst, &config##inst, \ - POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, NULL); + POST_KERNEL, CONFIG_MFD_NPM1300_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(MFD_NPM1300_DEFINE) diff --git a/drivers/mfd/mfd_npm6001.c b/drivers/mfd/mfd_npm6001.c index 4bed77c49587b6e..1a0777918162640 100644 --- a/drivers/mfd/mfd_npm6001.c +++ b/drivers/mfd/mfd_npm6001.c @@ -87,6 +87,6 @@ static int mfd_npm6001_init(const struct device *dev) }; \ \ DEVICE_DT_INST_DEFINE(inst, mfd_npm6001_init, NULL, NULL, &config##inst, POST_KERNEL, \ - CONFIG_MFD_INIT_PRIORITY, NULL); + CONFIG_MFD_NPM6001_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(MFD_NPM6001_DEFINE) diff --git a/drivers/mipi_dsi/dsi_mcux_2l.c b/drivers/mipi_dsi/dsi_mcux_2l.c index 05d56f9b6a13aa6..62ab1400a22b669 100644 --- a/drivers/mipi_dsi/dsi_mcux_2l.c +++ b/drivers/mipi_dsi/dsi_mcux_2l.c @@ -28,6 +28,7 @@ struct mcux_mipi_dsi_config { MIPI_DSI_HOST_Type *base; dsi_dpi_config_t dpi_config; bool auto_insert_eotp; + bool noncontinuous_hs_clk; const struct device *bit_clk_dev; clock_control_subsys_t bit_clk_subsys; const struct device *esc_clk_dev; @@ -45,6 +46,9 @@ struct mcux_mipi_dsi_config { struct mcux_mipi_dsi_data { dsi_handle_t mipi_handle; struct k_sem transfer_sem; +#ifdef CONFIG_MIPI_DSI_MCUX_2L_SMARTDMA + uint8_t dma_slot; +#endif }; @@ -105,11 +109,7 @@ static int dsi_mcux_tx_color(const struct device *dev, uint8_t channel, dma_cfg.user_data = (struct device *)dev; dma_cfg.head_block = █ dma_cfg.block_count = 1; - if (IS_ENABLED(CONFIG_MIPI_DSI_MCUX_2L_SWAP16)) { - dma_cfg.dma_slot = DMA_SMARTDMA_MIPI_RGB565_DMA_SWAP; - } else { - dma_cfg.dma_slot = DMA_SMARTDMA_MIPI_RGB565_DMA; - } + dma_cfg.dma_slot = data->dma_slot; dma_cfg.channel_direction = MEMORY_TO_PERIPHERAL; ret = dma_config(config->smart_dma, 0, &dma_cfg); if (ret < 0) { @@ -163,7 +163,8 @@ static int dsi_mcux_tx_color(const struct device *dev, uint8_t channel, .sendDscCmd = true, .dscCmd = msg->cmd, .txDataType = kDSI_TxDataDcsLongWr, - .flags = kDSI_TransferUseHighSpeed, + /* default to high speed unless told to use low power */ + .flags = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? 0 : kDSI_TransferUseHighSpeed, }; /* @@ -224,6 +225,9 @@ static int dsi_mcux_attach(const struct device *dev, DSI_GetDefaultConfig(&dsi_config); dsi_config.numLanes = mdev->data_lanes; dsi_config.autoInsertEoTp = config->auto_insert_eotp; + dsi_config.enableNonContinuousHsClk = config->noncontinuous_hs_clk; + + imxrt_pre_init_display_interface(); /* Init the DSI module. */ DSI_Init(config->base, &dsi_config); @@ -241,6 +245,25 @@ static int dsi_mcux_attach(const struct device *dev, if (!device_is_ready(config->smart_dma)) { return -ENODEV; } + + struct mcux_mipi_dsi_data *data = dev->data; + + switch (mdev->pixfmt) { + case MIPI_DSI_PIXFMT_RGB888: + data->dma_slot = DMA_SMARTDMA_MIPI_RGB888_DMA; + break; + case MIPI_DSI_PIXFMT_RGB565: + if (IS_ENABLED(CONFIG_MIPI_DSI_MCUX_2L_SWAP16)) { + data->dma_slot = DMA_SMARTDMA_MIPI_RGB565_DMA_SWAP; + } else { + data->dma_slot = DMA_SMARTDMA_MIPI_RGB565_DMA; + } + break; + default: + LOG_ERR("SMARTDMA does not support pixel_format %u", + mdev->pixfmt); + return -ENODEV; + } #else struct mcux_mipi_dsi_data *data = dev->data; @@ -323,6 +346,24 @@ static int dsi_mcux_attach(const struct device *dev, return 0; } +static int dsi_mcux_detach(const struct device *dev, uint8_t channel, + const struct mipi_dsi_device *mdev) +{ + const struct mcux_mipi_dsi_config *config = dev->config; + + /* Enable DPHY auto power down */ + DSI_DeinitDphy(config->base); + /* Fully power off DPHY */ + config->base->PD_DPHY = 0x1; + /* Deinit MIPI */ + DSI_Deinit(config->base); + /* Call IMX RT clock function to gate clocks and power at SOC level */ + imxrt_deinit_display_interface(); + return 0; +} + + + static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel, struct mipi_dsi_msg *msg) { @@ -336,6 +377,8 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel, dsi_xfer.txData = msg->tx_buf; dsi_xfer.rxDataSize = msg->rx_len; dsi_xfer.rxData = msg->rx_buf; + /* default to high speed unless told to use low power */ + dsi_xfer.flags = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? 0 : kDSI_TransferUseHighSpeed; switch (msg->type) { case MIPI_DSI_DCS_READ: @@ -355,7 +398,6 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel, dsi_xfer.sendDscCmd = true; dsi_xfer.dscCmd = msg->cmd; dsi_xfer.txDataType = kDSI_TxDataDcsLongWr; - dsi_xfer.flags = kDSI_TransferUseHighSpeed; if (msg->flags & MCUX_DSI_2L_FB_DATA) { /* * Special case- transfer framebuffer data using @@ -412,6 +454,7 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel, static struct mipi_dsi_driver_api dsi_mcux_api = { .attach = dsi_mcux_attach, + .detach = dsi_mcux_detach, .transfer = dsi_mcux_transfer, }; @@ -427,8 +470,6 @@ static int mcux_mipi_dsi_init(const struct device *dev) k_sem_init(&data->transfer_sem, 0, 1); - imxrt_pre_init_display_interface(); - if (!device_is_ready(config->bit_clk_dev) || !device_is_ready(config->esc_clk_dev) || !device_is_ready(config->pixel_clk_dev)) { @@ -482,6 +523,7 @@ static int mcux_mipi_dsi_init(const struct device *dev) (.irq_config_func = mipi_dsi_##n##_irq_config_func,)) \ .base = (MIPI_DSI_HOST_Type *)DT_INST_REG_ADDR(id), \ .auto_insert_eotp = DT_INST_PROP(id, autoinsert_eotp), \ + .noncontinuous_hs_clk = DT_INST_PROP(id, noncontinuous_hs_clk), \ .dphy_ref_freq = DT_INST_PROP_OR(id, dphy_ref_frequency, 0), \ .bit_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, dphy)), \ .bit_clk_subsys = \ diff --git a/drivers/misc/CMakeLists.txt b/drivers/misc/CMakeLists.txt index 863f839184e6915..6c4ec2384d935a2 100644 --- a/drivers/misc/CMakeLists.txt +++ b/drivers/misc/CMakeLists.txt @@ -6,3 +6,4 @@ 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) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 66d83fc693d18c9..52c77b4c7eca3dd 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -10,5 +10,6 @@ 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" endmenu diff --git a/drivers/misc/devmux/CMakeLists.txt b/drivers/misc/devmux/CMakeLists.txt new file mode 100644 index 000000000000000..94f74ea57ceabc1 --- /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 000000000000000..4f848b4e06c9ffe --- /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 000000000000000..653236f903dead3 --- /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/pio_rpi_pico/pio_rpi_pico.c b/drivers/misc/pio_rpi_pico/pio_rpi_pico.c index 03a03e824c20be9..5182cdf32b0eab7 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/misc/timeaware_gpio/timeaware_gpio_handlers.c b/drivers/misc/timeaware_gpio/timeaware_gpio_handlers.c index e65dcb2a62c4d8c..1904db4218dad45 100644 --- a/drivers/misc/timeaware_gpio/timeaware_gpio_handlers.c +++ b/drivers/misc/timeaware_gpio/timeaware_gpio_handlers.c @@ -8,8 +8,8 @@ static inline int z_vrfy_tgpio_port_get_time(const struct device *port, uint64_t *current_time) { - Z_OOPS(Z_SYSCALL_DRIVER_TGPIO(port, get_time)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(current_time, sizeof(uint64_t))); + K_OOPS(Z_SYSCALL_DRIVER_TGPIO(port, get_time)); + K_OOPS(Z_SYSCALL_MEMORY_WRITE(current_time, sizeof(uint64_t))); return z_impl_tgpio_port_get_time((const struct device *)port, (uint64_t *)current_time); } #include @@ -17,8 +17,8 @@ static inline int z_vrfy_tgpio_port_get_time(const struct device *port, uint64_t static inline int z_vrfy_tgpio_port_get_cycles_per_second(const struct device *port, uint32_t *cycles) { - Z_OOPS(Z_SYSCALL_DRIVER_TGPIO(port, cyc_per_sec)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(cycles, sizeof(uint32_t))); + K_OOPS(Z_SYSCALL_DRIVER_TGPIO(port, cyc_per_sec)); + K_OOPS(Z_SYSCALL_MEMORY_WRITE(cycles, sizeof(uint32_t))); return z_impl_tgpio_port_get_cycles_per_second((const struct device *)port, (uint32_t *)cycles); } @@ -28,7 +28,7 @@ static inline int z_vrfy_tgpio_pin_periodic_output(const struct device *port, ui uint64_t start_time, uint64_t repeat_interval, bool periodic_enable) { - Z_OOPS(Z_SYSCALL_DRIVER_TGPIO(port, set_perout)); + K_OOPS(Z_SYSCALL_DRIVER_TGPIO(port, set_perout)); return z_impl_tgpio_pin_periodic_output((const struct device *)port, pin, start_time, repeat_interval, periodic_enable); } @@ -36,7 +36,7 @@ static inline int z_vrfy_tgpio_pin_periodic_output(const struct device *port, ui static inline int z_vrfy_tgpio_pin_disable(const struct device *port, uint32_t pin) { - Z_OOPS(Z_SYSCALL_DRIVER_TGPIO(port, pin_disable)); + K_OOPS(Z_SYSCALL_DRIVER_TGPIO(port, pin_disable)); return z_impl_tgpio_pin_disable((const struct device *)port, pin); } #include @@ -44,7 +44,7 @@ static inline int z_vrfy_tgpio_pin_disable(const struct device *port, uint32_t p static inline int z_vrfy_tgpio_pin_config_ext_timestamp(const struct device *port, uint32_t pin, uint32_t event_polarity) { - Z_OOPS(Z_SYSCALL_DRIVER_TGPIO(port, config_ext_ts)); + K_OOPS(Z_SYSCALL_DRIVER_TGPIO(port, config_ext_ts)); return z_impl_tgpio_pin_config_ext_timestamp((const struct device *)port, pin, event_polarity); } @@ -53,7 +53,7 @@ static inline int z_vrfy_tgpio_pin_config_ext_timestamp(const struct device *por static inline int z_vrfy_tgpio_pin_read_ts_ec(const struct device *port, uint32_t pin, uint64_t *timestamp, uint64_t *event_count) { - Z_OOPS(Z_SYSCALL_DRIVER_TGPIO(port, read_ts_ec)); + K_OOPS(Z_SYSCALL_DRIVER_TGPIO(port, read_ts_ec)); return z_impl_tgpio_pin_read_ts_ec((const struct device *)port, pin, (uint64_t *)timestamp, (uint64_t *)event_count); } diff --git a/drivers/misc/timeaware_gpio/timeaware_gpio_intel.c b/drivers/misc/timeaware_gpio/timeaware_gpio_intel.c index 5c1933895529287..ae0e519a4378b84 100644 --- a/drivers/misc/timeaware_gpio/timeaware_gpio_intel.c +++ b/drivers/misc/timeaware_gpio/timeaware_gpio_intel.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include /* TGPIO Register offsets */ #define ART_L 0x00 /* ART lower 32 bit reg */ diff --git a/drivers/mm/mm_drv_bank.c b/drivers/mm/mm_drv_bank.c index 03209ffec4196d5..ca9ad9d051b8d5a 100644 --- a/drivers/mm/mm_drv_bank.c +++ b/drivers/mm/mm_drv_bank.c @@ -18,14 +18,14 @@ #include #include -void sys_mm_drv_bank_init(struct mem_drv_bank *bank, uint32_t bank_pages) +void sys_mm_drv_bank_init(struct sys_mm_drv_bank *bank, uint32_t bank_pages) { bank->unmapped_pages = 0; bank->mapped_pages = bank_pages; bank->max_mapped_pages = bank_pages; } -uint32_t sys_mm_drv_bank_page_mapped(struct mem_drv_bank *bank) +uint32_t sys_mm_drv_bank_page_mapped(struct sys_mm_drv_bank *bank) { bank->unmapped_pages--; bank->mapped_pages++; @@ -35,14 +35,14 @@ uint32_t sys_mm_drv_bank_page_mapped(struct mem_drv_bank *bank) return bank->mapped_pages; } -uint32_t sys_mm_drv_bank_page_unmapped(struct mem_drv_bank *bank) +uint32_t sys_mm_drv_bank_page_unmapped(struct sys_mm_drv_bank *bank) { bank->unmapped_pages++; bank->mapped_pages--; return bank->unmapped_pages; } -void sys_mm_drv_bank_stats_get(struct mem_drv_bank *bank, +void sys_mm_drv_bank_stats_get(struct sys_mm_drv_bank *bank, struct sys_memory_stats *stats) { stats->free_bytes = bank->unmapped_pages * @@ -53,7 +53,7 @@ void sys_mm_drv_bank_stats_get(struct mem_drv_bank *bank, CONFIG_MM_DRV_PAGE_SIZE; } -void sys_mm_drv_bank_stats_reset_max(struct mem_drv_bank *bank) +void sys_mm_drv_bank_stats_reset_max(struct sys_mm_drv_bank *bank) { bank->max_mapped_pages = bank->mapped_pages; } diff --git a/drivers/mm/mm_drv_intel_adsp.h b/drivers/mm/mm_drv_intel_adsp.h index b62e7ceb27db499..8de9ccc42cab62a 100644 --- a/drivers/mm/mm_drv_intel_adsp.h +++ b/drivers/mm/mm_drv_intel_adsp.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c index 55a9b1776a1f15c..ea3bb385b3b271b 100644 --- a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c +++ b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c @@ -27,10 +27,12 @@ #include #include +#define SRAM_BANK_PAGE_NUM (SRAM_BANK_SIZE / CONFIG_MM_DRV_PAGE_SIZE) + static struct k_spinlock tlb_lock; extern struct k_spinlock sys_mm_drv_common_lock; -static struct mem_drv_bank hpsram_bank[L2_SRAM_BANK_NUM]; +static struct sys_mm_drv_bank hpsram_bank[L2_SRAM_BANK_NUM]; #ifdef CONFIG_SOC_INTEL_COMM_WIDGET #include diff --git a/drivers/mm/mm_drv_intel_adsp_tlb.c b/drivers/mm/mm_drv_intel_adsp_tlb.c index 26d69371a2d78dd..315496be8e0041f 100644 --- a/drivers/mm/mm_drv_intel_adsp_tlb.c +++ b/drivers/mm/mm_drv_intel_adsp_tlb.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/modem/CMakeLists.txt b/drivers/modem/CMakeLists.txt index 96a10be34fb3a54..a97568dfc65c519 100644 --- a/drivers/modem/CMakeLists.txt +++ b/drivers/modem/CMakeLists.txt @@ -12,33 +12,30 @@ zephyr_library_sources_ifdef(CONFIG_MODEM_IFACE_UART_ASYNC modem_iface_uart_asyn zephyr_library_sources_ifdef(CONFIG_MODEM_CMD_HANDLER modem_cmd_handler.c) zephyr_library_sources_ifdef(CONFIG_MODEM_SOCKET modem_socket.c) +zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) +zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/lib/sockets) + if(CONFIG_MODEM_UBLOX_SARA) - zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) zephyr_library_sources(ublox-sara-r4.c) endif() if(CONFIG_MODEM_QUECTEL_BG9X) - zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) zephyr_library_sources(quectel-bg9x.c) endif() if(CONFIG_MODEM_WNCM14A2A) - zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) zephyr_library_sources(wncm14a2a.c) endif() if(CONFIG_MODEM_GSM_PPP) - zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) zephyr_library_sources(gsm_ppp.c) endif() if (CONFIG_MODEM_HL7800) - zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) zephyr_library_sources(hl7800.c) endif() if (CONFIG_MODEM_SIM7080) - zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) zephyr_library_sources(simcom-sim7080.c) endif() diff --git a/drivers/modem/Kconfig b/drivers/modem/Kconfig index c233d5db821caa8..02e3557918f6442 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 6869f047dad8b10..0460cda8d961946 100644 --- a/drivers/modem/Kconfig.cellular +++ b/drivers/modem/Kconfig.cellular @@ -11,9 +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_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 @@ -30,4 +32,8 @@ config MODEM_CELLULAR_APN string "APN" default "internet" +config MODEM_CELLULAR_PERIODIC_SCRIPT_MS + int "Periodic script interval in milliseconds" + default 2000 + endif diff --git a/drivers/modem/Kconfig.gsm b/drivers/modem/Kconfig.gsm index 4d5666b6f761c42..101c1e2ece4eee2 100644 --- a/drivers/modem/Kconfig.gsm +++ b/drivers/modem/Kconfig.gsm @@ -37,6 +37,25 @@ config MODEM_GSM_QUECTEL endchoice +choice MODEM_GSM_STATUS_COMMAND + prompt "Select status command Type" + default MODEM_GSM_STATUS_CMD_USE_CREG + help + Use particular type of AT command for cell tower registration status. + +config MODEM_GSM_STATUS_CMD_USE_CREG + bool "CREG command" + +config MODEM_GSM_STATUS_CMD_USE_CEREG + bool "CEREG command" + +endchoice + +config MODEM_GSM_STATUS_COMMAND + string "Status Command" + default "CREG" if MODEM_GSM_STATUS_CMD_USE_CREG + default "CEREG" if MODEM_GSM_STATUS_CMD_USE_CEREG + config MODEM_GSM_RX_STACK_SIZE int "Size of the stack allocated for receiving data from modem" default 512 diff --git a/drivers/modem/Kconfig.hl7800 b/drivers/modem/Kconfig.hl7800 index 01c607c391a8697..615dd5bdf87248d 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 f1e8ff5ef994145..88ea47b832a0a50 100644 --- a/drivers/modem/gsm_ppp.c +++ b/drivers/modem/gsm_ppp.c @@ -169,8 +169,12 @@ static int modem_atoi(const char *s, const int err_value, } #endif -static void gsm_rx(struct gsm_modem *gsm) +static void gsm_rx(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct gsm_modem *gsm = p1; LOG_DBG("starting"); while (true) { @@ -525,7 +529,7 @@ static const struct modem_cmd read_cops_cmd = MODEM_CMD_ARGS_MAX("+COPS:", on_cmd_atcmdinfo_cops, 1U, 4U, ","); static const struct modem_cmd check_net_reg_cmd = - MODEM_CMD("+CREG: ", on_cmd_net_reg_sts, 2U, ","); + MODEM_CMD("+" CONFIG_MODEM_GSM_STATUS_COMMAND, on_cmd_net_reg_sts, 2U, ","); static const struct modem_cmd check_attached_cmd = MODEM_CMD("+CGATT:", on_cmd_atcmdinfo_attached, 1U, ","); @@ -751,7 +755,7 @@ static void gsm_finalize_connection(struct k_work *work) ret = modem_cmd_send_nolock(&gsm->context.iface, &gsm->context.cmd_handler, &check_net_reg_cmd, 1, - "AT+CREG?", + "AT+" CONFIG_MODEM_GSM_STATUS_COMMAND "?", &gsm->sem_response, GSM_CMD_SETUP_TIMEOUT); if ((ret < 0) || ((gsm->net_state != GSM_NET_ROAMING) && @@ -810,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) { @@ -1323,7 +1327,7 @@ static int gsm_init(const struct device *dev) (void)k_thread_create(&gsm->rx_thread, gsm_rx_stack, K_KERNEL_STACK_SIZEOF(gsm_rx_stack), - (k_thread_entry_t) gsm_rx, + gsm_rx, gsm, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); (void)k_thread_name_set(&gsm->rx_thread, "gsm_rx"); diff --git a/drivers/modem/hl7800.c b/drivers/modem/hl7800.c index 291856a01ff6ea5..9846cf86f84e8a4 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; @@ -4482,8 +4557,12 @@ static void process_fw_update_rx(struct net_buf **rx_buf) #endif /* CONFIG_MODEM_HL7800_FW_UPDATE */ /* RX thread */ -static void hl7800_rx(void) +static void hl7800_rx(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + struct net_buf *rx_buf = NULL; struct net_buf *frag = NULL; int i, cmp_res; @@ -4704,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 @@ -4723,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) { @@ -4732,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 @@ -4770,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) { @@ -4780,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; @@ -4794,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. @@ -4805,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); } @@ -4828,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(); @@ -4841,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(); } @@ -4946,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); @@ -4969,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) @@ -4982,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!"); } @@ -5168,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) { @@ -5175,6 +5262,7 @@ static int modem_reset_and_configure(void) } hl7800_stop_rssi_work(); + initialize_sleep_level(); reboot: modem_reset(); @@ -5348,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; @@ -5449,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 @@ -5468,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); @@ -5559,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); @@ -5767,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: @@ -5807,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; @@ -5943,6 +6035,7 @@ static int offload_connect(struct net_context *context, } done: + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -6006,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(); @@ -6105,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); @@ -6212,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. @@ -6225,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, @@ -6330,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); @@ -6390,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); @@ -6426,7 +6521,7 @@ static int hl7800_init(const struct device *dev) k_thread_name_set( k_thread_create(&hl7800_rx_thread, hl7800_rx_stack, K_THREAD_STACK_SIZEOF(hl7800_rx_stack), - (k_thread_entry_t)hl7800_rx, NULL, NULL, NULL, + hl7800_rx, NULL, NULL, NULL, RX_THREAD_PRIORITY, 0, K_NO_WAIT), "hl7800 rx"); diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index e47b04d07619bc4..8aca855f55b7a59 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,26 @@ LOG_MODULE_REGISTER(modem_cellular, CONFIG_MODEM_LOG_LEVEL); #include #include +#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, @@ -80,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; @@ -111,8 +139,10 @@ 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; }; static const char *modem_cellular_state_str(enum modem_cellular_state state) @@ -271,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; @@ -289,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) @@ -341,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), @@ -440,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; @@ -769,13 +860,26 @@ static int modem_cellular_on_await_registered_state_enter(struct modem_cellular_ return -EAGAIN; } + modem_cellular_start_timer(data, MODEM_CELLULAR_PERIODIC_SCRIPT_TIMEOUT); return modem_chat_attach(&data->chat, data->dlci2_pipe); } static void modem_cellular_await_registered_event_handler(struct modem_cellular_data *data, enum modem_cellular_event evt) { + const struct modem_cellular_config *config = + (const struct modem_cellular_config *)data->dev->config; + switch (evt) { + case MODEM_CELLULAR_EVENT_SCRIPT_SUCCESS: + case MODEM_CELLULAR_EVENT_SCRIPT_FAILED: + modem_cellular_start_timer(data, MODEM_CELLULAR_PERIODIC_SCRIPT_TIMEOUT); + break; + + case MODEM_CELLULAR_EVENT_TIMEOUT: + modem_chat_run_script_async(&data->chat, config->periodic_chat_script); + break; + case MODEM_CELLULAR_EVENT_REGISTERED: modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_CARRIER_ON); break; @@ -789,16 +893,35 @@ static void modem_cellular_await_registered_event_handler(struct modem_cellular_ } } +static int modem_cellular_on_await_registered_state_leave(struct modem_cellular_data *data) +{ + modem_cellular_stop_timer(data); + return 0; +} + static int modem_cellular_on_carrier_on_state_enter(struct modem_cellular_data *data) { net_if_carrier_on(modem_ppp_get_iface(data->ppp)); + modem_cellular_start_timer(data, MODEM_CELLULAR_PERIODIC_SCRIPT_TIMEOUT); return 0; } static void modem_cellular_carrier_on_event_handler(struct modem_cellular_data *data, enum modem_cellular_event evt) { + const struct modem_cellular_config *config = + (const struct modem_cellular_config *)data->dev->config; + switch (evt) { + case MODEM_CELLULAR_EVENT_SCRIPT_SUCCESS: + case MODEM_CELLULAR_EVENT_SCRIPT_FAILED: + modem_cellular_start_timer(data, MODEM_CELLULAR_PERIODIC_SCRIPT_TIMEOUT); + break; + + case MODEM_CELLULAR_EVENT_TIMEOUT: + modem_chat_run_script_async(&data->chat, config->periodic_chat_script); + break; + case MODEM_CELLULAR_EVENT_DEREGISTERED: modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_RUN_DIAL_SCRIPT); break; @@ -814,6 +937,7 @@ static void modem_cellular_carrier_on_event_handler(struct modem_cellular_data * static int modem_cellular_on_carrier_on_state_leave(struct modem_cellular_data *data) { + modem_cellular_stop_timer(data); net_if_carrier_off(modem_ppp_get_iface(data->ppp)); modem_chat_release(&data->chat); modem_ppp_release(data->ppp); @@ -1008,6 +1132,10 @@ static int modem_cellular_on_state_leave(struct modem_cellular_data *data) ret = modem_cellular_on_run_dial_script_state_leave(data); break; + case MODEM_CELLULAR_STATE_AWAIT_REGISTERED: + ret = modem_cellular_on_await_registered_state_leave(data); + break; + case MODEM_CELLULAR_STATE_CARRIER_ON: ret = modem_cellular_on_carrier_on_state_leave(data); break; @@ -1136,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) { @@ -1245,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); @@ -1288,8 +1562,14 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_bg95_init_chat_script_cmds, 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", - 0)); + 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, abort_matches, modem_cellular_chat_callback_handler, 10); @@ -1304,6 +1584,63 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_bg95_dial_chat_script_cmds, MODEM_CHAT_SCRIPT_DEFINE(quectel_bg95_dial_chat_script, quectel_bg95_dial_chat_script_cmds, dial_abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_bg95_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(quectel_bg95_periodic_chat_script, + quectel_bg95_periodic_chat_script_cmds, abort_matches, + modem_cellular_chat_callback_handler, 4); +#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("", 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); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg25_g_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(quectel_eg25_g_dial_chat_script, quectel_eg25_g_dial_chat_script_cmds, + dial_abort_matches, modem_cellular_chat_callback_handler, 10); + +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+CSQ", csq_match)); + +MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_periodic_chat_script, + quectel_eg25_g_periodic_chat_script_cmds, abort_matches, + modem_cellular_chat_callback_handler, 4); #endif #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_gsm_ppp) @@ -1324,6 +1661,7 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(zephyr_gsm_ppp_init_chat_script_cmds, 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), /* The 300ms delay after sending the AT+CMUX command is required * for some modems to ensure they get enough time to enter CMUX * mode before sending the first CMUX command. If this delay is @@ -1345,6 +1683,15 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(zephyr_gsm_ppp_dial_chat_script_cmds, MODEM_CHAT_SCRIPT_DEFINE(zephyr_gsm_ppp_dial_chat_script, zephyr_gsm_ppp_dial_chat_script_cmds, dial_abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(zephyr_gsm_ppp_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(zephyr_gsm_ppp_periodic_chat_script, + zephyr_gsm_ppp_periodic_chat_script_cmds, abort_matches, + modem_cellular_chat_callback_handler, 4); #endif #if DT_HAS_COMPAT_STATUS_OKAY(simcom_sim7080) @@ -1365,6 +1712,7 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(simcom_sim7080_init_chat_script_cmds, 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_NONE("AT+CMUX=0,0,5,127", 300)); MODEM_CHAT_SCRIPT_DEFINE(simcom_sim7080_init_chat_script, simcom_sim7080_init_chat_script_cmds, @@ -1380,6 +1728,15 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(simcom_sim7080_dial_chat_script_cmds, MODEM_CHAT_SCRIPT_DEFINE(simcom_sim7080_dial_chat_script, simcom_sim7080_dial_chat_script_cmds, dial_abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(simcom_sim7080_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(simcom_sim7080_periodic_chat_script, + simcom_sim7080_periodic_chat_script_cmds, abort_matches, + modem_cellular_chat_callback_handler, 4); #endif #if DT_HAS_COMPAT_STATUS_OKAY(u_blox_sara_r4) @@ -1400,8 +1757,8 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r4_init_chat_script_cmds, 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", - 0)); + 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_r4_init_chat_script, u_blox_sara_r4_init_chat_script_cmds, abort_matches, modem_cellular_chat_callback_handler, 10); @@ -1416,6 +1773,66 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r4_dial_chat_script_cmds, MODEM_CHAT_SCRIPT_DEFINE(u_blox_sara_r4_dial_chat_script, u_blox_sara_r4_dial_chat_script_cmds, dial_abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r4_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_r4_periodic_chat_script, + u_blox_sara_r4_periodic_chat_script_cmds, abort_matches, + 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) @@ -1436,8 +1853,7 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(swir_hl7800_init_chat_script_cmds, 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", - 0)); + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT+CMUX=0,0,5,127", 0)); MODEM_CHAT_SCRIPT_DEFINE(swir_hl7800_init_chat_script, swir_hl7800_init_chat_script_cmds, abort_matches, modem_cellular_chat_callback_handler, 10); @@ -1453,56 +1869,333 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(swir_hl7800_dial_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=1", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP_NONE("ATD*99***1#", 0)); +MODEM_CHAT_SCRIPT_CMDS_DEFINE(swir_hl7800_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_DEFINE(swir_hl7800_periodic_chat_script, + swir_hl7800_periodic_chat_script_cmds, abort_matches, + modem_cellular_chat_callback_handler, 4); + MODEM_CHAT_SCRIPT_DEFINE(swir_hl7800_dial_chat_script, swir_hl7800_dial_chat_script_cmds, dial_abort_matches, modem_cellular_chat_callback_handler, 10); #endif +#if DT_HAS_COMPAT_STATUS_OKAY(telit_me910g1) +MODEM_CHAT_SCRIPT_CMDS_DEFINE(telit_me910g1_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), + /* The Telit me910g1 often has an error trying + * to set the PDP context. The radio must be on to set + * the context, and this step must be successful. + * It is moved to the init script to allow retries. + */ + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGDCONT=1,\"IP\"," + "\"" CONFIG_MODEM_CELLULAR_APN "\"", + 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+CFUN=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT+CMUX=0,0,5,127,10,3,30,10,2", + 300)); + +MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_init_chat_script, telit_me910g1_init_chat_script_cmds, + abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(telit_me910g1_dial_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("ATD*99***1#", 0)); + +MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_dial_chat_script, telit_me910g1_dial_chat_script_cmds, + dial_abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(telit_me910g1_periodic_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, + telit_me910g1_periodic_chat_script_cmds, abort_matches, + modem_cellular_chat_callback_handler, 4); +#endif + #define MODEM_CELLULAR_INST_NAME(name, inst) \ _CONCAT(_CONCAT(_CONCAT(name, _), DT_DRV_COMPAT), inst) -#define MODEM_CELLULAR_DEVICE(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, {}), \ - .power_pulse_duration_ms = 1500, \ - .reset_pulse_duration_ms = 100, \ - .startup_time_ms = 10000, \ - .shutdown_time_ms = 5000, \ - .init_chat_script = &_CONCAT(DT_DRV_COMPAT, _init_chat_script), \ - .dial_chat_script = &_CONCAT(DT_DRV_COMPAT, _dial_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); +#define MODEM_CELLULAR_DEVICE_QUECTEL_BG95(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, {}), \ + .power_pulse_duration_ms = 1500, \ + .reset_pulse_duration_ms = 100, \ + .startup_time_ms = 10000, \ + .shutdown_time_ms = 5000, \ + .init_chat_script = &quectel_bg95_init_chat_script, \ + .dial_chat_script = &quectel_bg95_dial_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, \ + &modem_cellular_api); + +#define MODEM_CELLULAR_DEVICE_QUECTEL_EG25_G(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, {}), \ + .power_pulse_duration_ms = 1500, \ + .reset_pulse_duration_ms = 500, \ + .startup_time_ms = 15000, \ + .shutdown_time_ms = 5000, \ + .init_chat_script = &quectel_eg25_g_init_chat_script, \ + .dial_chat_script = &quectel_eg25_g_dial_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, \ + &modem_cellular_api); + +#define MODEM_CELLULAR_DEVICE_GSM_PPP(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, {}), \ + .power_pulse_duration_ms = 1500, \ + .reset_pulse_duration_ms = 100, \ + .startup_time_ms = 10000, \ + .shutdown_time_ms = 5000, \ + .init_chat_script = &zephyr_gsm_ppp_init_chat_script, \ + .dial_chat_script = &zephyr_gsm_ppp_dial_chat_script, \ + .periodic_chat_script = &zephyr_gsm_ppp_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_SIMCOM_SIM7080(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, {}), \ + .power_pulse_duration_ms = 1500, \ + .reset_pulse_duration_ms = 100, \ + .startup_time_ms = 10000, \ + .shutdown_time_ms = 5000, \ + .init_chat_script = &simcom_sim7080_init_chat_script, \ + .dial_chat_script = &simcom_sim7080_dial_chat_script, \ + .periodic_chat_script = &simcom_sim7080_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_U_BLOX_SARA_R4(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, {}), \ + .power_pulse_duration_ms = 1500, \ + .reset_pulse_duration_ms = 100, \ + .startup_time_ms = 10000, \ + .shutdown_time_ms = 5000, \ + .init_chat_script = &u_blox_sara_r4_init_chat_script, \ + .dial_chat_script = &u_blox_sara_r4_dial_chat_script, \ + .periodic_chat_script = &u_blox_sara_r4_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_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); \ + \ + 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, {}), \ + .power_pulse_duration_ms = 1500, \ + .reset_pulse_duration_ms = 100, \ + .startup_time_ms = 10000, \ + .shutdown_time_ms = 5000, \ + .init_chat_script = &swir_hl7800_init_chat_script, \ + .dial_chat_script = &swir_hl7800_dial_chat_script, \ + .periodic_chat_script = &swir_hl7800_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_TELIT_ME910G1(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, {}), \ + .power_pulse_duration_ms = 5050, \ + .reset_pulse_duration_ms = 250, \ + .startup_time_ms = 15000, \ + .shutdown_time_ms = 5000, \ + .init_chat_script = &telit_me910g1_init_chat_script, \ + .dial_chat_script = &telit_me910g1_dial_chat_script, \ + .periodic_chat_script = &telit_me910g1_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 DT_DRV_COMPAT quectel_bg95 -DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE) +DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_QUECTEL_BG95) +#undef DT_DRV_COMPAT + +#define DT_DRV_COMPAT quectel_eg25_g +DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_QUECTEL_EG25_G) #undef DT_DRV_COMPAT #define DT_DRV_COMPAT zephyr_gsm_ppp -DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE) +DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_GSM_PPP) #undef DT_DRV_COMPAT #define DT_DRV_COMPAT simcom_sim7080 -DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE) +DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_SIMCOM_SIM7080) #undef DT_DRV_COMPAT #define DT_DRV_COMPAT u_blox_sara_r4 -DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE) +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) +DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_SWIR_HL7800) +#undef DT_DRV_COMPAT + +#define DT_DRV_COMPAT telit_me910g1 +DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_TELIT_ME910G1) #undef DT_DRV_COMPAT diff --git a/drivers/modem/quectel-bg9x.c b/drivers/modem/quectel-bg9x.c index 04bb08d665ebbde..714a7606ab66c1b 100644 --- a/drivers/modem/quectel-bg9x.c +++ b/drivers/modem/quectel-bg9x.c @@ -846,8 +846,12 @@ static ssize_t offload_sendmsg(void *obj, const struct msghdr *msg, int flags) /* Func: modem_rx * Desc: Thread to process all messages received from the Modem. */ -static void modem_rx(void) +static void modem_rx(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + while (true) { /* Wait for incoming data */ @@ -1264,7 +1268,7 @@ static int modem_init(const struct device *dev) /* start RX thread */ k_thread_create(&modem_rx_thread, modem_rx_stack, K_KERNEL_STACK_SIZEOF(modem_rx_stack), - (k_thread_entry_t) modem_rx, + modem_rx, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); /* Init RSSI query */ diff --git a/drivers/modem/simcom-sim7080.c b/drivers/modem/simcom-sim7080.c index 39fb66b6aa1de2d..f0b31a1d1b686c7 100644 --- a/drivers/modem/simcom-sim7080.c +++ b/drivers/modem/simcom-sim7080.c @@ -802,8 +802,12 @@ static int offload_socket(int family, int type, int proto) /* * Process all messages received from the modem. */ -static void modem_rx(void) +static void modem_rx(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + while (true) { /* Wait for incoming data */ modem_iface_uart_rx_wait(&mctx.iface, K_FOREVER); @@ -1462,7 +1466,7 @@ static int parse_cgnsinf(char *gps_buf) gnss_data.run_status = 1; gnss_data.fix_status = 1; - strncpy(gnss_data.utc, utc, sizeof(gnss_data.utc)); + strncpy(gnss_data.utc, utc, sizeof(gnss_data.utc) - 1); ret = gnss_split_on_dot(lat, &number, &fraction); if (ret != 0) { @@ -2414,7 +2418,7 @@ static int modem_init(const struct device *dev) } k_thread_create(&modem_rx_thread, modem_rx_stack, K_KERNEL_STACK_SIZEOF(modem_rx_stack), - (k_thread_entry_t)modem_rx, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); + modem_rx, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); /* Init RSSI query */ k_work_init_delayable(&mdata.rssi_query_work, modem_rssi_query_work); diff --git a/drivers/modem/ublox-sara-r4.c b/drivers/modem/ublox-sara-r4.c index ca70b1465e03b46..a3fe3c45f833cfe 100644 --- a/drivers/modem/ublox-sara-r4.c +++ b/drivers/modem/ublox-sara-r4.c @@ -936,8 +936,12 @@ MODEM_CMD_DEFINE(on_cmd_socknotifycreg) } /* RX thread */ -static void modem_rx(void) +static void modem_rx(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + while (true) { /* wait for incoming data */ modem_iface_uart_rx_wait(&mctx.iface, K_FOREVER); @@ -2220,7 +2224,7 @@ static int modem_init(const struct device *dev) /* start RX thread */ k_thread_create(&modem_rx_thread, modem_rx_stack, K_KERNEL_STACK_SIZEOF(modem_rx_stack), - (k_thread_entry_t) modem_rx, + modem_rx, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); #if defined(CONFIG_MODEM_UBLOX_SARA_RSSI_WORK) diff --git a/drivers/modem/wncm14a2a.c b/drivers/modem/wncm14a2a.c index 520c43125806925..5b60d0aaff557fa 100644 --- a/drivers/modem/wncm14a2a.c +++ b/drivers/modem/wncm14a2a.c @@ -1057,8 +1057,12 @@ static void wncm14a2a_read_rx(struct net_buf **buf) } /* RX thread */ -static void wncm14a2a_rx(void) +static void wncm14a2a_rx(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + struct net_buf *rx_buf = NULL; struct net_buf *frag = NULL; int i; @@ -1430,7 +1434,7 @@ static int wncm14a2a_init(const struct device *dev) /* start RX thread */ k_thread_create(&wncm14a2a_rx_thread, wncm14a2a_rx_stack, K_KERNEL_STACK_SIZEOF(wncm14a2a_rx_stack), - (k_thread_entry_t) wncm14a2a_rx, + wncm14a2a_rx, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); /* init RSSI query */ diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index f6e0faa334a5719..c83f0f42a08ab00 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 cd9a0ee3e1bd38d..2695875ae27f629 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -42,12 +42,15 @@ static void loopback_init(struct net_if *iface) if (IS_ENABLED(CONFIG_NET_IPV4)) { struct in_addr ipv4_loopback = INADDR_LOOPBACK_INIT; + struct in_addr netmask = { { { 255, 0, 0, 0 } } }; ifaddr = net_if_ipv4_addr_add(iface, &ipv4_loopback, NET_ADDR_AUTOCONF, 0); if (!ifaddr) { LOG_ERR("Failed to register IPv4 loopback address"); } + + net_if_ipv4_set_netmask(iface, &netmask); } if (IS_ENABLED(CONFIG_NET_IPV6)) { @@ -107,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 @@ -138,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 ecfdb7c3af19239..70fbe9631a55f52 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/Kconfig b/drivers/pcie/host/Kconfig index 2dcb9bba61290c2..515ef89ce280da2 100644 --- a/drivers/pcie/host/Kconfig +++ b/drivers/pcie/host/Kconfig @@ -82,7 +82,6 @@ config PCIE_PRT config PCIE_SHELL bool "PCIe/new PCI Shell" - default y depends on SHELL help Enable commands for debugging PCI(e) using the built-in shell. diff --git a/drivers/pcie/host/msi.c b/drivers/pcie/host/msi.c index fc04fdccfa13f39..f78f5b171a61a6a 100644 --- a/drivers/pcie/host/msi.c +++ b/drivers/pcie/host/msi.c @@ -38,7 +38,7 @@ static uint32_t pcie_msi_base(pcie_bdf_t bdf, bool *msi) #ifdef CONFIG_PCIE_MSI_MULTI_VECTOR -#include +#include __weak uint8_t arch_pcie_msi_vectors_allocate(unsigned int priority, msi_vector_t *vectors, diff --git a/drivers/pcie/host/pcie.c b/drivers/pcie/host/pcie.c index a4d9fdbe5048525..d8e04a9ed73db3d 100644 --- a/drivers/pcie/host/pcie.c +++ b/drivers/pcie/host/pcie.c @@ -126,6 +126,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 +158,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 +175,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 +184,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 +209,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; } /** diff --git a/drivers/peci/peci_handlers.c b/drivers/peci/peci_handlers.c index 39147019d1c185d..64947a8743d9f54 100644 --- a/drivers/peci/peci_handlers.c +++ b/drivers/peci/peci_handlers.c @@ -5,13 +5,13 @@ */ #include -#include +#include static inline int z_vrfy_peci_config(const struct device *dev, uint32_t bitrate) { - Z_OOPS(Z_SYSCALL_DRIVER_PECI(dev, config)); + K_OOPS(K_SYSCALL_DRIVER_PECI(dev, config)); return z_impl_peci_config(dev, bitrate); } @@ -19,7 +19,7 @@ static inline int z_vrfy_peci_config(const struct device *dev, static inline int z_vrfy_peci_enable(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_PECI(dev, enable)); + K_OOPS(K_SYSCALL_DRIVER_PECI(dev, enable)); return z_impl_peci_enable(dev); } @@ -27,7 +27,7 @@ static inline int z_vrfy_peci_enable(const struct device *dev) static inline int z_vrfy_peci_disable(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_PECI(dev, disable)); + K_OOPS(K_SYSCALL_DRIVER_PECI(dev, disable)); return z_impl_peci_disable(dev); } @@ -38,8 +38,8 @@ static inline int z_vrfy_peci_transfer(const struct device *dev, { struct peci_msg msg_copy; - Z_OOPS(Z_SYSCALL_DRIVER_PECI(dev, transfer)); - Z_OOPS(z_user_from_copy(&msg_copy, msg, sizeof(*msg))); + K_OOPS(K_SYSCALL_DRIVER_PECI(dev, transfer)); + K_OOPS(k_usermode_from_copy(&msg_copy, msg, sizeof(*msg))); return z_impl_peci_transfer(dev, &msg_copy); } diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 4ff07c5fdde7f14..310b528d17681b1 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) @@ -36,3 +37,6 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_TI_CC32XX pinctrl_ti_cc32xx.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_MSPM0G3XXX pinctrl_mspm0g3xxx.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_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 c9d94d5ad6c595d..39449a1964f181e 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -65,5 +65,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.renesas_ra" +source "drivers/pinctrl/Kconfig.rzt2m" +source "drivers/pinctrl/Kconfig.zynqmp" endif # PINCTRL diff --git a/drivers/pinctrl/Kconfig.imx b/drivers/pinctrl/Kconfig.imx index b31a90e72911f4f..506f5b30016bcaa 100644 --- a/drivers/pinctrl/Kconfig.imx +++ b/drivers/pinctrl/Kconfig.imx @@ -7,6 +7,13 @@ config PINCTRL_IMX help Enable pin controller driver for NXP iMX series MCUs +config PINCTRL_IMX_SCU + bool "Pin controller driver for SCU-based i.MX SoCs" + depends on DT_HAS_NXP_IMX_IOMUXC_SCU_ENABLED + default y + help + Enable pin controller driver for SCU-based NXP i.MX SoCs. + # TODO: Find better place for this option config MCUX_XBARA bool "MCUX XBARA driver" diff --git a/drivers/pinctrl/Kconfig.rcar b/drivers/pinctrl/Kconfig.rcar index 5aabd54371dd327..cc3ff51b9d66fc9 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 000000000000000..6f3c301d07bbb3e --- /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.rzt2m b/drivers/pinctrl/Kconfig.rzt2m new file mode 100644 index 000000000000000..236afdcf55ec3bf --- /dev/null +++ b/drivers/pinctrl/Kconfig.rzt2m @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_RZT2M + bool "Renesas RZ/T2M pin controller driver" + default y + depends on DT_HAS_RENESAS_RZT2M_PINCTRL_ENABLED + help + Renesas RZ/T2M pinctrl driver diff --git a/drivers/pinctrl/Kconfig.zynqmp b/drivers/pinctrl/Kconfig.zynqmp new file mode 100644 index 000000000000000..10e9b1105848606 --- /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 17705e0a8635174..ad10b03fda05ef8 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 000000000000000..cbef35ff76bc91f --- /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_imx_scu.c b/drivers/pinctrl/pinctrl_imx_scu.c new file mode 100644 index 000000000000000..67448ed599921d2 --- /dev/null +++ b/drivers/pinctrl/pinctrl_imx_scu.c @@ -0,0 +1,38 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include
    + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, + uint8_t pin_cnt, uintptr_t reg) +{ + sc_ipc_t ipc_handle; + int ret, i; + + ret = sc_ipc_open(&ipc_handle, DT_REG_ADDR(DT_NODELABEL(scu_mu))); + if (ret != SC_ERR_NONE) { + return -ENODEV; + } + + for (i = 0; i < pin_cnt; i++) { + /* TODO: for now, pad configuration is not supported. As such, + * the state of the pad is the following: + * 1) Normal configuration (no OD) + * 2) ISO off + * 3) Pull select and drive strength initialized by another + * entity (e.g: SCFW, Linux etc...) or set to the default + * values as specified in the TRM. + */ + ret = sc_pad_set_mux(ipc_handle, pins[i].pad, pins[i].mux, 0, 0); + if (ret != SC_ERR_NONE) { + return -EINVAL; + } + } + + return 0; +} diff --git a/drivers/pinctrl/pinctrl_ite_it8xxx2.c b/drivers/pinctrl/pinctrl_ite_it8xxx2.c index 886a035483feac6..33ed9130b62e2e9 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_kinetis.c b/drivers/pinctrl/pinctrl_kinetis.c index 5fdb07a8cedf99e..45ac0ebe3cfd464 100644 --- a/drivers/pinctrl/pinctrl_kinetis.c +++ b/drivers/pinctrl/pinctrl_kinetis.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 NXP + * Copyright (c) 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,9 +7,13 @@ #define DT_DRV_COMPAT nxp_kinetis_pinmux +#include #include +#include #include +LOG_MODULE_REGISTER(pinctrl_kinetis, CONFIG_PINCTRL_LOG_LEVEL); + /* Port register addresses. */ static PORT_Type *ports[] = { (PORT_Type *)DT_REG_ADDR(DT_NODELABEL(porta)), @@ -28,7 +32,8 @@ static PORT_Type *ports[] = { #define PINCFG(mux) ((mux) & Z_PINCTRL_KINETIS_PCR_MASK) struct pinctrl_mcux_config { - clock_ip_name_t clock_ip_name; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; }; int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, @@ -51,24 +56,36 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, static int pinctrl_mcux_init(const struct device *dev) { const struct pinctrl_mcux_config *config = dev->config; + int err; + + if (!device_is_ready(config->clock_dev)) { + LOG_ERR("clock control device not ready"); + return -ENODEV; + } - CLOCK_EnableClock(config->clock_ip_name); + err = clock_control_on(config->clock_dev, config->clock_subsys); + if (err) { + LOG_ERR("failed to enable clock (err %d)", err); + return -EINVAL; + } return 0; } -#if DT_NODE_HAS_STATUS(DT_INST(0, nxp_kinetis_ke1xf_sim), okay) -#define INST_DT_CLOCK_IP_NAME(n) \ - DT_REG_ADDR(DT_INST_PHANDLE(n, clocks)) + DT_INST_CLOCKS_CELL(n, name) -#else -#define INST_DT_CLOCK_IP_NAME(n) \ +#if DT_NODE_HAS_STATUS(DT_INST(0, nxp_kinetis_sim), okay) +#define PINCTRL_MCUX_DT_INST_CLOCK_SUBSYS(n) \ CLK_GATE_DEFINE(DT_INST_CLOCKS_CELL(n, offset), \ DT_INST_CLOCKS_CELL(n, bits)) +#else +#define PINCTRL_MCUX_DT_INST_CLOCK_SUBSYS(n) \ + DT_INST_CLOCKS_CELL(n, name) #endif #define PINCTRL_MCUX_INIT(n) \ static const struct pinctrl_mcux_config pinctrl_mcux_##n##_config = {\ - .clock_ip_name = INST_DT_CLOCK_IP_NAME(n), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (clock_control_subsys_t) \ + PINCTRL_MCUX_DT_INST_CLOCK_SUBSYS(n), \ }; \ \ DEVICE_DT_INST_DEFINE(n, \ diff --git a/drivers/pinctrl/pinctrl_npcx.c b/drivers/pinctrl/pinctrl_npcx.c index 5759122018f4405..373a7158cfc8a6f 100644 --- a/drivers/pinctrl/pinctrl_npcx.c +++ b/drivers/pinctrl/pinctrl_npcx.c @@ -38,17 +38,10 @@ static const struct npcx_pwm_pinctrl_config pwm_pinctrl_cfg[] = { /* Pin-control local functions for peripheral devices */ static bool npcx_periph_pinmux_has_lock(int group) { -#if defined(CONFIG_SOC_SERIES_NPCX7) - if (group == 0x00 || (group >= 0x02 && group <= 0x04) || group == 0x06 || - group == 0x0b || group == 0x0f) { + if ((BIT(group) & NPCX_DEVALT_LK_GROUP_MASK) != 0) { return true; } -#elif defined(CONFIG_SOC_SERIES_NPCX9) - if (group == 0x00 || (group >= 0x02 && group <= 0x06) || group == 0x0b || - group == 0x0d || (group >= 0x0f && group <= 0x12)) { - return true; - } -#endif + return false; } diff --git a/drivers/pinctrl/pinctrl_nrf.c b/drivers/pinctrl/pinctrl_nrf.c index c2ac538c93b9da9..12ee1d5229415ba 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_renesas_ra.c b/drivers/pinctrl/pinctrl_renesas_ra.c new file mode 100644 index 000000000000000..89f8a41d519823f --- /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_rzt2m.c b/drivers/pinctrl/pinctrl_rzt2m.c new file mode 100644 index 000000000000000..0dff44619031c42 --- /dev/null +++ b/drivers/pinctrl/pinctrl_rzt2m.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_rzt2m_pinctrl + +#include +#include +#include + +#define PORT_NSR DT_INST_REG_ADDR_BY_NAME(0, port_nsr) +#define PTADR DT_INST_REG_ADDR_BY_NAME(0, ptadr) + +/* Port m mode control register */ +#define PMC(port) (PORT_NSR + 0x400 + port) +/* Port m function control register */ +#define PFC(port) (PORT_NSR + 0x600 + (0x4 * port)) +/* IO Buffer m function switching register */ +#define DRCTL(port, pin) (PORT_NSR + 0xa00 + (0x8 * port) + pin) +/* Port m region select register */ +#define RSELP(port) (PTADR + port) + +#define DRCTL_DRIVE_STRENGTH(val) (val & 0x3) +#define DRCTL_PULL_UP_DOWN(val) ((val & 0x3) << 2) +#define DRCTL_SCHMITT(val) ((val & 0x1) << 4) +#define DRCTL_SLEW_RATE(val) ((val & 0x1) << 5) +#define DRCTL_CONFIG(drive, pull, schmitt, slew) \ + (DRCTL_DRIVE_STRENGTH(drive) | DRCTL_PULL_UP_DOWN(pull) | DRCTL_SCHMITT(schmitt) | \ + DRCTL_SLEW_RATE(slew)) +#define PFC_FUNC_MASK(pin) (0xf << (pin * 4)) + +static void pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) +{ + uint8_t rselp = sys_read8(RSELP(pin->port)); + uint32_t pfc = sys_read32(PFC(pin->port)) & ~(PFC_FUNC_MASK(pin->pin)); + uint8_t pmc = sys_read8(PMC(pin->port)); + + /* Set proper bit in the RSELP register to use as non-safety domain. */ + sys_write8(rselp | BIT(pin->pin), RSELP(pin->port)); + sys_write8(DRCTL_CONFIG( + pin->drive_strength, (pin->pull_up == 1 ? 1U : (pin->pull_down == 1 ? 2U : 0)), + pin->schmitt_enable, pin->slew_rate), + DRCTL(pin->port, pin->pin)); + + /* Select function for the pin. */ + sys_write32(pfc | pin->func << (pin->pin * 4), PFC(pin->port)); + + /* Set proper bit in the PMC register to use the pin as a peripheral IO. */ + sys_write8(pmc | BIT(pin->pin), PMC(pin->port)); +} + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + ARG_UNUSED(reg); + + for (uint8_t i = 0U; i < pin_cnt; i++) { + pinctrl_configure_pin(pins++); + } + + return 0; +} diff --git a/drivers/pinctrl/pinctrl_sifive.c b/drivers/pinctrl/pinctrl_sifive.c index ff770b53a6aa87f..7dd8c6f944fd300 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 000000000000000..6d874801c512964 --- /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/pm_cpu_ops/Kconfig b/drivers/pm_cpu_ops/Kconfig index c38c6779fa1cad5..43d549f59bde558 100644 --- a/drivers/pm_cpu_ops/Kconfig +++ b/drivers/pm_cpu_ops/Kconfig @@ -32,7 +32,6 @@ config PM_CPU_OPS_PSCI config PSCI_SHELL bool "Support for PSCI interface shell commands" - default y depends on SHELL && PM_CPU_OPS_PSCI help Say Y here if you need to enable PSCI interface shell commands diff --git a/drivers/power_domain/CMakeLists.txt b/drivers/power_domain/CMakeLists.txt index 0637e64f7947618..27b07c945f1d0f3 100644 --- a/drivers/power_domain/CMakeLists.txt +++ b/drivers/power_domain/CMakeLists.txt @@ -4,4 +4,5 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_GPIO power_domain_gpio.c) +zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_GPIO_MONITOR power_domain_gpio_monitor.c) zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_INTEL_ADSP power_domain_intel_adsp.c) diff --git a/drivers/power_domain/Kconfig b/drivers/power_domain/Kconfig index 6c8563d4724ddd1..c1fe5d3bd9b0288 100644 --- a/drivers/power_domain/Kconfig +++ b/drivers/power_domain/Kconfig @@ -12,14 +12,31 @@ module = POWER_DOMAIN module-str = power_domain source "subsys/logging/Kconfig.template.log_config" +config POWER_DOMAIN_INIT_PRIORITY + int "Power domain init priority" + default 75 + help + Power domain initialization priority. + config POWER_DOMAIN_GPIO bool "GPIO controlled power domain" 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 @@ -28,4 +45,31 @@ 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 + depends on DT_HAS_POWER_DOMAIN_GPIO_MONITOR_ENABLED + 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 b4702ad13eb4483..82d9a17ef9e5b7f 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -125,17 +125,17 @@ static int pd_gpio_init(const struct device *dev) return pm_device_driver_init(dev, pd_gpio_pm_action); } -#define POWER_DOMAIN_DEVICE(id) \ - static const struct pd_gpio_config pd_gpio_##id##_cfg = { \ - .enable = GPIO_DT_SPEC_INST_GET(id, enable_gpios), \ - .startup_delay_us = DT_INST_PROP(id, startup_delay_us), \ - .off_on_delay_us = DT_INST_PROP(id, off_on_delay_us), \ - }; \ - static struct pd_gpio_data pd_gpio_##id##_data; \ - 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, 75, \ +#define POWER_DOMAIN_DEVICE(id) \ + static const struct pd_gpio_config pd_gpio_##id##_cfg = { \ + .enable = GPIO_DT_SPEC_INST_GET(id, enable_gpios), \ + .startup_delay_us = DT_INST_PROP(id, startup_delay_us), \ + .off_on_delay_us = DT_INST_PROP(id, off_on_delay_us), \ + }; \ + static struct pd_gpio_data pd_gpio_##id##_data; \ + 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_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 new file mode 100644 index 000000000000000..40c03bb8dd7bf20 --- /dev/null +++ b/drivers/power_domain/power_domain_gpio_monitor.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT power_domain_gpio_monitor + +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(power_domain_gpio_monitor, CONFIG_POWER_DOMAIN_LOG_LEVEL); + +struct pd_gpio_monitor_config { + struct gpio_dt_spec power_good_gpio; +}; + +struct pd_gpio_monitor_data { + struct gpio_callback callback; + const struct device *dev; + bool is_powered; +}; + +struct pd_visitor_context { + const struct device *domain; + enum pm_device_action action; +}; + +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)) { + return 0; + } + + dev->pm->usage = 0; + (void)pm_device_action_run(dev, visitor_context->action); + return 0; +} + +static void pd_gpio_monitor_callback(const struct device *port, + struct gpio_callback *cb, gpio_port_pins_t pins) +{ + struct pd_gpio_monitor_data *data = CONTAINER_OF(cb, struct pd_gpio_monitor_data, callback); + const struct pd_gpio_monitor_config *config = data->dev->config; + const struct device *dev = data->dev; + struct pd_visitor_context context = {.domain = dev}; + int rc; + + rc = gpio_pin_get_dt(&config->power_good_gpio); + if (rc < 0) { + LOG_WRN("Failed to read gpio logic level"); + return; + } + + data->is_powered = rc; + if (rc == 0) { + context.action = PM_DEVICE_ACTION_SUSPEND; + (void)device_supported_foreach(dev, pd_on_domain_visitor, &context); + context.action = PM_DEVICE_ACTION_TURN_OFF; + (void)device_supported_foreach(dev, pd_on_domain_visitor, &context); + return; + } + + pm_device_children_action_run(data->dev, PM_DEVICE_ACTION_TURN_ON, NULL); +} + +static int pd_gpio_monitor_pm_action(const struct device *dev, enum pm_device_action action) +{ + struct pd_gpio_monitor_data *data = dev->data; + + switch (action) { + case PM_DEVICE_ACTION_TURN_ON: + case PM_DEVICE_ACTION_TURN_OFF: + return -ENOTSUP; + case PM_DEVICE_ACTION_RESUME: + if (!data->is_powered) { + return -EAGAIN; + } + break; + default: + break; + } + + return 0; +} + +static int pd_gpio_monitor_init(const struct device *dev) +{ + const struct pd_gpio_monitor_config *config = dev->config; + struct pd_gpio_monitor_data *data = dev->data; + int rc; + + data->dev = dev; + + if (!gpio_is_ready_dt(&config->power_good_gpio)) { + LOG_ERR("GPIO port %s is not ready", config->power_good_gpio.port->name); + return -ENODEV; + } + + rc = gpio_pin_configure_dt(&config->power_good_gpio, GPIO_INPUT); + if (rc) { + LOG_ERR("Failed to configure GPIO"); + goto unconfigure_pin; + } + + rc = gpio_pin_interrupt_configure_dt(&config->power_good_gpio, GPIO_INT_EDGE_BOTH); + if (rc) { + gpio_pin_configure_dt(&config->power_good_gpio, GPIO_DISCONNECTED); + LOG_ERR("Failed to configure GPIO interrupt"); + goto unconfigure_interrupt; + } + + gpio_init_callback(&data->callback, pd_gpio_monitor_callback, + BIT(config->power_good_gpio.pin)); + rc = gpio_add_callback_dt(&config->power_good_gpio, &data->callback); + if (rc) { + LOG_ERR("Failed to add GPIO callback"); + goto remove_callback; + } + + pm_device_init_suspended(dev); + return pm_device_runtime_enable(dev); +remove_callback: + gpio_remove_callback(config->power_good_gpio.port, &data->callback); +unconfigure_interrupt: + gpio_pin_interrupt_configure_dt(&config->power_good_gpio, GPIO_INT_DISABLE); +unconfigure_pin: + gpio_pin_configure_dt(&config->power_good_gpio, GPIO_DISCONNECTED); + return rc; +} + +#define POWER_DOMAIN_DEVICE(inst) \ + static const struct pd_gpio_monitor_config pd_gpio_monitor_config_##inst = { \ + .power_good_gpio = GPIO_DT_SPEC_INST_GET(inst, gpios), \ + }; \ + static struct pd_gpio_monitor_data pd_gpio_monitor_data_##inst; \ + PM_DEVICE_DT_INST_DEFINE(inst, pd_gpio_monitor_pm_action); \ + 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_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 21df893b1277436..8a82f26650fc0e3 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); @@ -17,6 +21,7 @@ struct pg_bits { uint32_t CPA_bit; }; +#ifdef CONFIG_PM_DEVICE static int pd_intel_adsp_set_power_enable(struct pg_bits *bits, bool power_enable) { uint16_t SPA_bit_mask = BIT(bits->SPA_bit); @@ -27,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); } @@ -65,6 +81,8 @@ static int pd_intel_adsp_pm_action(const struct device *dev, enum pm_device_acti return ret; } +#endif /* CONFIG_PM_DEVICE */ + static int pd_intel_adsp_init(const struct device *dev) { pm_device_init_suspended(dev); @@ -73,14 +91,14 @@ static int pd_intel_adsp_init(const struct device *dev) #define DT_DRV_COMPAT intel_adsp_power_domain -#define POWER_DOMAIN_DEVICE(id) \ - static struct pg_bits pd_pg_reg##id = { \ - .SPA_bit = DT_INST_PROP(id, bit_position), \ - .CPA_bit = DT_INST_PROP(id, bit_position), \ - }; \ - 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); +#define POWER_DOMAIN_DEVICE(id) \ + static struct pg_bits pd_pg_reg##id = { \ + .SPA_bit = DT_INST_PROP(id, bit_position), \ + .CPA_bit = DT_INST_PROP(id, bit_position), \ + }; \ + 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_POWER_DOMAIN_INTEL_ADSP_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(POWER_DOMAIN_DEVICE) diff --git a/drivers/ps2/ps2_handlers.c b/drivers/ps2/ps2_handlers.c index 71d1181a2d29558..91835e85ea55572 100644 --- a/drivers/ps2/ps2_handlers.c +++ b/drivers/ps2/ps2_handlers.c @@ -5,13 +5,13 @@ */ #include -#include +#include static inline int z_vrfy_ps2_config(const struct device *dev, ps2_callback_t callback_isr) { - Z_OOPS(Z_SYSCALL_DRIVER_PS2(dev, config)); - Z_OOPS(Z_SYSCALL_VERIFY_MSG(callback_isr == NULL, + K_OOPS(K_SYSCALL_DRIVER_PS2(dev, config)); + K_OOPS(K_SYSCALL_VERIFY_MSG(callback_isr == NULL, "callback not be set from user mode")); return z_impl_ps2_config(dev, callback_isr); } @@ -19,29 +19,29 @@ static inline int z_vrfy_ps2_config(const struct device *dev, static inline int z_vrfy_ps2_write(const struct device *dev, uint8_t value) { - Z_OOPS(Z_SYSCALL_DRIVER_PS2(dev, write)); + K_OOPS(K_SYSCALL_DRIVER_PS2(dev, write)); return z_impl_ps2_write(dev, value); } #include static inline int z_vrfy_ps2_read(const struct device *dev, uint8_t *value) { - Z_OOPS(Z_SYSCALL_DRIVER_PS2(dev, read)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(value, sizeof(uint8_t))); + K_OOPS(K_SYSCALL_DRIVER_PS2(dev, read)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(value, sizeof(uint8_t))); return z_impl_ps2_read(dev, value); } #include static inline int z_vrfy_ps2_enable_callback(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_PS2(dev, enable_callback)); + K_OOPS(K_SYSCALL_DRIVER_PS2(dev, enable_callback)); return z_impl_ps2_enable_callback(dev); } #include static inline int z_vrfy_ps2_disable_callback(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_PS2(dev, disable_callback)); + K_OOPS(K_SYSCALL_DRIVER_PS2(dev, disable_callback)); return z_impl_ps2_disable_callback(dev); } #include diff --git a/drivers/ps2/ps2_mchp_xec.c b/drivers/ps2/ps2_mchp_xec.c index ccd2957982e0fe4..0a6677869127bae 100644 --- a/drivers/ps2/ps2_mchp_xec.c +++ b/drivers/ps2/ps2_mchp_xec.c @@ -16,10 +16,8 @@ #include #endif #include -#ifdef CONFIG_PM_DEVICE #include #include -#endif #include #include #include @@ -174,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; @@ -308,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 7987b588ceaa962..3dfde253e0901b8 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 9417d7f063326d0..74ab3e14eb85234 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 000000000000000..aa9c8d5e41b48a5 --- /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.c b/drivers/ptp_clock/ptp_clock.c index ba0d7e373e94b5e..0ac0e5c242f7836 100644 --- a/drivers/ptp_clock/ptp_clock.c +++ b/drivers/ptp_clock/ptp_clock.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include #ifdef CONFIG_USERSPACE @@ -14,15 +14,15 @@ int z_vrfy_ptp_clock_get(const struct device *dev, struct net_ptp_time ptp_time; int ret; - Z_OOPS(Z_SYSCALL_DRIVER_PTP_CLOCK(dev, get)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(tm, sizeof(struct net_ptp_time))); + K_OOPS(K_SYSCALL_DRIVER_PTP_CLOCK(dev, get)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(tm, sizeof(struct net_ptp_time))); ret = z_impl_ptp_clock_get((const struct device *)dev, &ptp_time); if (ret != 0) { return 0; } - if (z_user_to_copy((void *)tm, &ptp_time, sizeof(ptp_time)) != 0) { + if (k_usermode_to_copy((void *)tm, &ptp_time, sizeof(ptp_time)) != 0) { return 0; } 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 000000000000000..943ff6ca4ea05ae --- /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/Kconfig b/drivers/pwm/Kconfig index ff9856d9d57dfed..8942ebd89b08cd1 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -22,7 +22,6 @@ config PWM_INIT_PRIORITY config PWM_SHELL bool "PWM shell" - default y depends on SHELL help Enable the PWM related shell commands. diff --git a/drivers/pwm/pwm_handlers.c b/drivers/pwm/pwm_handlers.c index 9993b24cf7334ff..3ffaaa61e465abc 100644 --- a/drivers/pwm/pwm_handlers.c +++ b/drivers/pwm/pwm_handlers.c @@ -5,14 +5,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include static inline int z_vrfy_pwm_set_cycles(const struct device *dev, uint32_t channel, uint32_t period, uint32_t pulse, pwm_flags_t flags) { - Z_OOPS(Z_SYSCALL_DRIVER_PWM(dev, set_cycles)); + K_OOPS(K_SYSCALL_DRIVER_PWM(dev, set_cycles)); return z_impl_pwm_set_cycles((const struct device *)dev, channel, period, pulse, flags); } @@ -22,8 +22,8 @@ static inline int z_vrfy_pwm_get_cycles_per_sec(const struct device *dev, uint32_t channel, uint64_t *cycles) { - Z_OOPS(Z_SYSCALL_DRIVER_PWM(dev, get_cycles_per_sec)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(cycles, sizeof(uint64_t))); + K_OOPS(K_SYSCALL_DRIVER_PWM(dev, get_cycles_per_sec)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(cycles, sizeof(uint64_t))); return z_impl_pwm_get_cycles_per_sec((const struct device *)dev, channel, (uint64_t *)cycles); } @@ -34,7 +34,7 @@ static inline int z_vrfy_pwm_get_cycles_per_sec(const struct device *dev, static inline int z_vrfy_pwm_enable_capture(const struct device *dev, uint32_t channel) { - Z_OOPS(Z_SYSCALL_DRIVER_PWM(dev, enable_capture)); + K_OOPS(K_SYSCALL_DRIVER_PWM(dev, enable_capture)); return z_impl_pwm_enable_capture((const struct device *)dev, channel); } #include @@ -42,7 +42,7 @@ static inline int z_vrfy_pwm_enable_capture(const struct device *dev, static inline int z_vrfy_pwm_disable_capture(const struct device *dev, uint32_t channel) { - Z_OOPS(Z_SYSCALL_DRIVER_PWM(dev, disable_capture)); + K_OOPS(K_SYSCALL_DRIVER_PWM(dev, disable_capture)); return z_impl_pwm_disable_capture((const struct device *)dev, channel); } #include @@ -57,19 +57,19 @@ static inline int z_vrfy_pwm_capture_cycles(const struct device *dev, uint32_t pulse; int err; - Z_OOPS(Z_SYSCALL_DRIVER_PWM(dev, configure_capture)); - Z_OOPS(Z_SYSCALL_DRIVER_PWM(dev, enable_capture)); - Z_OOPS(Z_SYSCALL_DRIVER_PWM(dev, disable_capture)); + K_OOPS(K_SYSCALL_DRIVER_PWM(dev, configure_capture)); + K_OOPS(K_SYSCALL_DRIVER_PWM(dev, enable_capture)); + K_OOPS(K_SYSCALL_DRIVER_PWM(dev, disable_capture)); err = z_impl_pwm_capture_cycles((const struct device *)dev, channel, flags, &period, &pulse, timeout); if (period_cycles != NULL) { - Z_OOPS(z_user_to_copy(period_cycles, &period, + K_OOPS(k_usermode_to_copy(period_cycles, &period, sizeof(*period_cycles))); } if (pulse_cycles != NULL) { - Z_OOPS(z_user_to_copy(pulse_cycles, &pulse, + K_OOPS(k_usermode_to_copy(pulse_cycles, &pulse, sizeof(*pulse_cycles))); } diff --git a/drivers/pwm/pwm_led_esp32.c b/drivers/pwm/pwm_led_esp32.c index de89bf694a81b14..7e53877f69ebce5 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 27ed76df7ee2d24..9f57be2dd711651 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 91d16092e8fd1db..fcd3272cfdc6a1f 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 f367bb59899f39a..2b9a22a38f081a0 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_pca9685.c b/drivers/pwm/pwm_pca9685.c index 24596d7f3770cac..f08bdd4cf9b04ba 100644 --- a/drivers/pwm/pwm_pca9685.c +++ b/drivers/pwm/pwm_pca9685.c @@ -119,6 +119,7 @@ static int set_pre_scale(const struct device *dev, uint8_t value) struct pca9685_data *data = dev->data; uint8_t mode1; int ret; + uint8_t restart = RESTART; k_mutex_lock(&data->mutex, K_FOREVER); @@ -134,9 +135,7 @@ static int set_pre_scale(const struct device *dev, uint8_t value) } if ((mode1 & RESTART) == 0x00) { - LOG_ERR("RESTART bit should be set"); - ret = -EIO; - goto out; + restart = 0; } ret = set_reg(dev, ADDR_PRE_SCALE, value); @@ -152,7 +151,7 @@ static int set_pre_scale(const struct device *dev, uint8_t value) k_sleep(OSCILLATOR_STABILIZE); - ret = set_reg(dev, ADDR_MODE1, AUTO_INC | RESTART); + ret = set_reg(dev, ADDR_MODE1, AUTO_INC | restart); if (ret != 0) { goto out; } diff --git a/drivers/pwm/pwm_rpi_pico.c b/drivers/pwm/pwm_rpi_pico.c index 4b23cc558f15b76..b36a468fe37ccfd 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 ca989facd5d6d97..c8e44633ad5f9c9 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 27bf32076cf68a8..c7612fa2067abef 100644 --- a/drivers/regulator/CMakeLists.txt +++ b/drivers/regulator/CMakeLists.txt @@ -6,9 +6,11 @@ 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) +zephyr_library_sources_ifdef(CONFIG_REGULATOR_MAX20335 regulator_max20335.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM1100 regulator_npm1100.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM1300 regulator_npm1300.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM6001 regulator_npm6001.c) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 5ecaf1181ead336..754ba31783e7073 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -17,7 +17,6 @@ config REGULATOR_THREAD_SAFE_REFCNT config REGULATOR_SHELL bool "Regulator shell" - default y depends on SHELL help Enable regulator shell framework, for interacting with regulators via @@ -29,9 +28,11 @@ 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" +source "drivers/regulator/Kconfig.max20335" source "drivers/regulator/Kconfig.npm1100" source "drivers/regulator/Kconfig.npm1300" source "drivers/regulator/Kconfig.npm6001" diff --git a/drivers/regulator/Kconfig.axp192 b/drivers/regulator/Kconfig.axp192 index c2ec403359ef61e..8c8fad5cdb44ceb 100644 --- a/drivers/regulator/Kconfig.axp192 +++ b/drivers/regulator/Kconfig.axp192 @@ -15,7 +15,7 @@ if REGULATOR_AXP192 config REGULATOR_AXP192_INIT_PRIORITY int "AXP192 regulator driver init priority" - default 76 + default 86 help Init priority for the axp192 regulator driver. It must be greater than MFD_INIT_PRIORITY. diff --git a/drivers/regulator/Kconfig.da1469x b/drivers/regulator/Kconfig.da1469x new file mode 100644 index 000000000000000..d8205ed4925dff4 --- /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 new file mode 100644 index 000000000000000..a92743afdb53672 --- /dev/null +++ b/drivers/regulator/Kconfig.max20335 @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Grinn +# SPDX -License-Identifier: Apache-2.0 + +config REGULATOR_MAX20335 + bool "MAX20335 PMIC regulator driver" + default y + depends on DT_HAS_MAXIM_MAX20335_REGULATOR_ENABLED + select I2C + select MFD + 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 87 + help + 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/Kconfig.npm1300 b/drivers/regulator/Kconfig.npm1300 index a003f90f7a9f1df..997934cabb79885 100644 --- a/drivers/regulator/Kconfig.npm1300 +++ b/drivers/regulator/Kconfig.npm1300 @@ -14,14 +14,14 @@ if REGULATOR_NPM1300 config REGULATOR_NPM1300_COMMON_INIT_PRIORITY int "nPM1300 regulator driver init priority (common part)" - default 75 + default 85 help Init priority for the Nordic nPM1300 regulator driver (common part). It must be greater than I2C init priority. config REGULATOR_NPM1300_INIT_PRIORITY int "nPM1300 regulator driver init priority" - default 76 + default 86 help Init priority for the Nordic nPM1300 regulator driver. It must be greater than REGULATOR_NPM1300_COMMON_INIT_PRIORITY. diff --git a/drivers/regulator/Kconfig.npm6001 b/drivers/regulator/Kconfig.npm6001 index d4e361876aed9f3..a9c290475deac41 100644 --- a/drivers/regulator/Kconfig.npm6001 +++ b/drivers/regulator/Kconfig.npm6001 @@ -12,7 +12,7 @@ config REGULATOR_NPM6001 config REGULATOR_NPM6001_INIT_PRIORITY int "nPM6001 regulator driver init priority" - default 76 + default 86 depends on REGULATOR_NPM6001 help Init priority for the Nordic nPM6001 regulator driver. diff --git a/drivers/regulator/regulator_common.c b/drivers/regulator/regulator_common.c index adbacddac1205cc..f2d9f6275e67b29 100644 --- a/drivers/regulator/regulator_common.c +++ b/drivers/regulator/regulator_common.c @@ -1,10 +1,23 @@ /* * Copyright 2022 Nordic Semiconductor ASA + * Copyright 2023 Meta Platforms * SPDX-License-Identifier: Apache-2.0 */ +#include #include +static void regulator_delay(uint32_t delay_us) +{ + if (delay_us > 0U) { +#ifdef CONFIG_MULTITHREADING + k_sleep(K_USEC(delay_us)); +#else + k_busy_wait(delay_us); +#endif + } +} + void regulator_common_data_init(const struct device *dev) { struct regulator_common_data *data = dev->data; @@ -30,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) { @@ -37,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)) { @@ -67,6 +96,7 @@ int regulator_common_init(const struct device *dev, bool is_enabled) return ret; } + regulator_delay(config->startup_delay_us); data->refcnt++; } @@ -100,6 +130,8 @@ int regulator_enable(const struct device *dev) ret = api->enable(dev); if (ret < 0) { data->refcnt--; + } else { + regulator_delay(config->off_on_delay_us); } } diff --git a/drivers/regulator/regulator_da1469x.c b/drivers/regulator/regulator_da1469x.c new file mode 100644 index 000000000000000..36d8fe1d35ff7da --- /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 05b74bc56e100b4..129ef2f215e02d1 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 390f925cde61c1b..5e7151f4941bf16 100644 --- a/drivers/regulator/regulator_fixed.c +++ b/drivers/regulator/regulator_fixed.c @@ -9,7 +9,6 @@ #include -#include #include #include #include @@ -18,8 +17,6 @@ LOG_MODULE_REGISTER(regulator_fixed, CONFIG_REGULATOR_LOG_LEVEL); struct regulator_fixed_config { struct regulator_common_config common; - uint32_t startup_delay_us; - uint32_t off_on_delay_us; struct gpio_dt_spec enable; }; @@ -41,10 +38,6 @@ static int regulator_fixed_enable(const struct device *dev) return ret; } - if (cfg->off_on_delay_us > 0U) { - k_sleep(K_USEC(cfg->off_on_delay_us)); - } - return 0; } @@ -91,35 +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; - } - - k_busy_wait(cfg->startup_delay_us); - } 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) \ @@ -130,8 +111,6 @@ static int regulator_fixed_init(const struct device *dev) \ static const struct regulator_fixed_config config##inst = { \ .common = REGULATOR_DT_INST_COMMON_CONFIG_INIT(inst), \ - .startup_delay_us = DT_INST_PROP(inst, startup_delay_us), \ - .off_on_delay_us = DT_INST_PROP(inst, off_on_delay_us), \ .enable = GPIO_DT_SPEC_INST_GET_OR(inst, enable_gpios, {0}), \ }; \ \ diff --git a/drivers/regulator/regulator_gpio.c b/drivers/regulator/regulator_gpio.c index 93d6ebddff8018a..49d373897b38eb3 100644 --- a/drivers/regulator/regulator_gpio.c +++ b/drivers/regulator/regulator_gpio.c @@ -7,7 +7,6 @@ #include -#include #include #include #include @@ -24,7 +23,6 @@ struct regulator_gpio_config { uint8_t states_cnt; const struct gpio_dt_spec enable; - int32_t startup_delay_us; }; struct regulator_gpio_data { @@ -73,10 +71,6 @@ static int regulator_gpio_enable(const struct device *dev) return ret; } - if (cfg->startup_delay_us > 0U) { - k_sleep(K_USEC(cfg->startup_delay_us)); - } - return 0; } @@ -229,7 +223,6 @@ static int regulator_gpio_init(const struct device *dev) .enable = GPIO_DT_SPEC_INST_GET_OR(inst, enable_gpios, {0}), \ .states = ((const int[])DT_INST_PROP(inst, states)), \ .states_cnt = DT_INST_PROP_LEN(inst, states) / 2, \ - .startup_delay_us = DT_INST_PROP_OR(inst, startup_delay_us, 0), \ }; \ DEVICE_DT_INST_DEFINE(inst, regulator_gpio_init, NULL, &data##inst, &config##inst, \ POST_KERNEL, CONFIG_REGULATOR_GPIO_INIT_PRIORITY, \ diff --git a/drivers/regulator/regulator_max20335.c b/drivers/regulator/regulator_max20335.c new file mode 100644 index 000000000000000..328e5179156ea44 --- /dev/null +++ b/drivers/regulator/regulator_max20335.c @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT maxim_max20335_regulator + +#include +#include +#include +#include +#include + +#define MAX20335_BUCK1_CFG 0x0DU +#define MAX20335_BUCK1_VSET 0x0EU +#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 +#define MAX20335_BUCK_EN BIT(3) +#define MAX20335_BUCK_EN_MASK GENMASK(4, 3) + +#define MAX20335_LDO1_CFG 0x12U +#define MAX20335_LDO1_VSET 0x13U +#define MAX20335_LDO2_CFG 0x14U +#define MAX20335_LDO2_VSET 0x15U +#define MAX20335_LDO3_CFG 0x16U +#define MAX20335_LDO3_VSET 0x17U +#define MAX20335_LDO_MODE_MASK BIT(0) +#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, + MAX20335_PMIC_SOURCE_LDO1, + MAX20335_PMIC_SOURCE_LDO2, + MAX20335_PMIC_SOURCE_LDO3, +}; + +struct regulator_max20335_desc { + uint8_t vsel_reg; + uint8_t enable_mask; + uint8_t enable_val; + uint8_t cfg_reg; + const struct linear_range *uv_range; + 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; + const struct regulator_max20335_desc *desc; + uint8_t source; +}; + +struct regulator_max20335_data { + struct regulator_common_data common; +}; + +static const struct linear_range buck1_range = LINEAR_RANGE_INIT(700000, 25000U, 0x0U, 0x3FU); +static const struct linear_range buck2_range = LINEAR_RANGE_INIT(700000, 50000U, 0x0U, 0x3FU); +static const struct linear_range buck12_current_limit_range = + LINEAR_RANGE_INIT(50000, 25000U, 0x02U, 0x0FU); +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 __maybe_unused buck1_desc = { + .vsel_reg = MAX20335_BUCK1_VSET, + .enable_mask = MAX20335_BUCK_EN_MASK, + .enable_val = MAX20335_BUCK_EN, + .cfg_reg = MAX20335_BUCK1_CFG, + .uv_range = &buck1_range, + .ua_range = &buck12_current_limit_range, +}; + +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, + .cfg_reg = MAX20335_BUCK2_CFG, + .uv_range = &buck2_range, + .ua_range = &buck12_current_limit_range, +}; + +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, + .cfg_reg = MAX20335_LDO1_CFG, + .uv_range = &ldo1_range, +}; + +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, + .cfg_reg = MAX20335_LDO2_CFG, + .uv_range = &ldo23_range, +}; + +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, + .cfg_reg = MAX20335_LDO3_CFG, + .uv_range = &ldo23_range, +}; + +static int regulator_max20335_set_enable(const struct device *dev, bool enable) +{ + const struct regulator_max20335_config *config = dev->config; + + return i2c_reg_update_byte_dt(&config->bus, + config->desc->cfg_reg, + config->desc->enable_mask, + enable ? config->desc->enable_val : 0); +} + +static int regulator_max20335_enable(const struct device *dev) +{ + return regulator_max20335_set_enable(dev, true); +} + +static int regulator_max20335_disable(const struct device *dev) +{ + return regulator_max20335_set_enable(dev, false); +} + +static int regulator_max20335_set_mode(const struct device *dev, regulator_mode_t mode) +{ + const struct regulator_max20335_config *config = dev->config; + + if (mode > MAX20335_LOAD_SWITCH_MODE) { + return -ENOTSUP; + } + + switch (config->source) { + case MAX20335_PMIC_SOURCE_LDO1: + __fallthrough; + case MAX20335_PMIC_SOURCE_LDO2: + __fallthrough; + case MAX20335_PMIC_SOURCE_LDO3: + return i2c_reg_update_byte_dt(&config->bus, + config->desc->cfg_reg, + MAX20335_LDO_MODE_MASK, + mode); + default: + return -ENOTSUP; + } +} + +static unsigned int regulator_max20335_count_voltages(const struct device *dev) +{ + const struct regulator_max20335_config *config = dev->config; + + return linear_range_values_count(config->desc->uv_range); +} + +static int regulator_max20335_list_voltage(const struct device *dev, unsigned int idx, + int32_t *volt_uv) +{ + const struct regulator_max20335_config *config = dev->config; + + return linear_range_get_value(config->desc->uv_range, idx, volt_uv); +} + +static int regulator_max20335_set_buck_ldo_voltage(const struct device *dev, int32_t min_uv, + int32_t max_uv, const struct linear_range *range, + uint8_t vout_reg) +{ + const struct regulator_max20335_config *config = dev->config; + uint16_t idx; + int ret; + + ret = linear_range_get_win_index(range, min_uv, max_uv, &idx); + if (ret == -EINVAL) { + return ret; + } + + return i2c_reg_write_byte_dt(&config->bus, vout_reg, (uint8_t)idx); +} + +static int regulator_max20335_buck12_ldo123_get_voltage(const struct device *dev, + const struct linear_range *range, + uint8_t vout_reg, int32_t *volt_uv) +{ + const struct regulator_max20335_config *config = dev->config; + uint8_t idx; + int ret; + + ret = i2c_reg_read_byte_dt(&config->bus, vout_reg, &idx); + if (ret < 0) { + return ret; + } + + return linear_range_get_value(range, idx, volt_uv); +} + +static int regulator_max20335_get_voltage(const struct device *dev, int32_t *volt_uv) +{ + const struct regulator_max20335_config *config = dev->config; + + return regulator_max20335_buck12_ldo123_get_voltage(dev, + config->desc->uv_range, + config->desc->vsel_reg, + volt_uv); +} + +static int regulator_max20335_set_voltage(const struct device *dev, int32_t min_uv, int32_t max_uv) +{ + const struct regulator_max20335_config *config = dev->config; + + return regulator_max20335_set_buck_ldo_voltage(dev, + min_uv, + max_uv, + config->desc->uv_range, + config->desc->vsel_reg); +} + +static unsigned int regulator_max20335_count_current_limits(const struct device *dev) +{ + 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); +} + +static int regulator_max20335_list_current_limit(const struct device *dev, unsigned int idx, + int32_t *current_ua) +{ + 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); +} + +static int regulator_max20335_set_current_limit(const struct device *dev, + int32_t min_ua, + int32_t max_ua) +{ + const struct regulator_max20335_config *config = dev->config; + uint8_t val; + 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; + } + + ret = linear_range_get_win_index(config->desc->ua_range, min_ua, max_ua, &idx); + if (ret == -EINVAL) { + return ret; + } + + switch (config->source) { + case MAX20335_PMIC_SOURCE_BUCK1: + val = idx | (val & MAX20335_BUCK1_CSET_MASK); + break; + case MAX20335_PMIC_SOURCE_BUCK2: + val = (idx << MAX20335_BUCK2_CSET_SHIFT) | (val & MAX20335_BUCK2_CSET_MASK); + break; + default: + return -ENOTSUP; + } + + 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; + + if (!i2c_is_ready_dt(&config->bus)) { + return -ENODEV; + } + + regulator_common_data_init(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, + .set_mode = regulator_max20335_set_mode, + .count_voltages = regulator_max20335_count_voltages, + .list_voltage = regulator_max20335_list_voltage, + .set_voltage = regulator_max20335_set_voltage, + .get_voltage = regulator_max20335_get_voltage, + .count_current_limits = regulator_max20335_count_current_limits, + .list_current_limit = regulator_max20335_list_current_limit, + .set_current_limit = regulator_max20335_set_current_limit, +}; + +#define REGULATOR_MAX20335_DEFINE(node_id, id, child_name, _source) \ + static const struct regulator_max20335_config regulator_max20335_config_##id = { \ + .common = REGULATOR_DT_COMMON_CONFIG_INIT(node_id), \ + .bus = I2C_DT_SPEC_GET(DT_GPARENT(node_id)), \ + .desc = &child_name##_desc, \ + .source = _source, \ + }; \ + \ + static struct regulator_max20335_data regulator_max20335_data_##id; \ + DEVICE_DT_DEFINE(node_id, regulator_max20335_init, NULL, \ + ®ulator_max20335_data_##id, \ + ®ulator_max20335_config_##id, \ + POST_KERNEL, \ + CONFIG_REGULATOR_MAXIM_MAX20335_INIT_PRIORITY, \ + &api); + +#define REGULATOR_MAX20335_DEFINE_COND(inst, child, source) \ + COND_CODE_1(DT_NODE_EXISTS(DT_INST_CHILD(inst, child)), \ + (REGULATOR_MAX20335_DEFINE(DT_INST_CHILD(inst, child), \ + child##inst, child, source)), \ + ()) + +#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) diff --git a/drivers/regulator/regulator_npm1300.c b/drivers/regulator/regulator_npm1300.c index 84ea5b68263c359..8adb2d3cb817aba 100644 --- a/drivers/regulator/regulator_npm1300.c +++ b/drivers/regulator/regulator_npm1300.c @@ -48,6 +48,7 @@ enum npm1300_gpio_type { #define BUCK_OFFSET_SW_CTRL 0x0FU #define BUCK_OFFSET_VOUT_STAT 0x10U #define BUCK_OFFSET_CTRL0 0x15U +#define BUCK_OFFSET_STATUS 0x34U /* nPM1300 ldsw register offsets */ #define LDSW_OFFSET_EN_SET 0x00U @@ -61,6 +62,17 @@ enum npm1300_gpio_type { /* nPM1300 ship register offsets */ #define SHIP_OFFSET_SHIP 0x02U +#define BUCK1_ON_MASK 0x04U +#define BUCK2_ON_MASK 0x40U + +#define LDSW1_ON_MASK 0x03U +#define LDSW2_ON_MASK 0x0CU + +#define LDSW1_SOFTSTART_MASK 0x0CU +#define LDSW1_SOFTSTART_SHIFT 2U +#define LDSW2_SOFTSTART_MASK 0x30U +#define LDSW2_SOFTSTART_SHIFT 4U + struct regulator_npm1300_pconfig { const struct device *mfd; struct gpio_dt_spec dvs_state_pins[5]; @@ -74,6 +86,7 @@ struct regulator_npm1300_config { struct gpio_dt_spec enable_gpios; struct gpio_dt_spec retention_gpios; struct gpio_dt_spec pwm_gpios; + uint8_t soft_start; }; struct regulator_npm1300_data { @@ -426,7 +439,7 @@ static int regulator_npm1300_set_ldsw_pin_ctrl(const struct device *dev, uint8_t ctrl = (pin + 1U) | (inv << 3U); - return mfd_npm1300_reg_write(config->mfd, LDSW_BASE, LDSW_OFFSET_GPISEL + chan, type); + return mfd_npm1300_reg_write(config->mfd, LDSW_BASE, LDSW_OFFSET_GPISEL + chan, ctrl); } int regulator_npm1300_set_pin_ctrl(const struct device *dev, const struct gpio_dt_spec *spec, @@ -512,16 +525,75 @@ int regulator_npm1300_common_init(const struct device *dev) return 0; } +static int get_enabled_reg(const struct device *dev, uint8_t base, uint8_t offset, uint8_t mask, + bool *enabled) +{ + const struct regulator_npm1300_config *config = dev->config; + uint8_t data; + + int ret = mfd_npm1300_reg_read(config->mfd, base, offset, &data); + + if (ret != 0) { + return ret; + } + + *enabled = (data & mask) != 0U; + + return 0; +} + +static int get_enabled(const struct device *dev, bool *enabled) +{ + const struct regulator_npm1300_config *config = dev->config; + + switch (config->source) { + case NPM1300_SOURCE_BUCK1: + return get_enabled_reg(dev, BUCK_BASE, BUCK_OFFSET_STATUS, BUCK1_ON_MASK, enabled); + case NPM1300_SOURCE_BUCK2: + return get_enabled_reg(dev, BUCK_BASE, BUCK_OFFSET_STATUS, BUCK2_ON_MASK, enabled); + case NPM1300_SOURCE_LDO1: + return get_enabled_reg(dev, LDSW_BASE, LDSW_OFFSET_STATUS, LDSW1_ON_MASK, enabled); + case NPM1300_SOURCE_LDO2: + return get_enabled_reg(dev, LDSW_BASE, LDSW_OFFSET_STATUS, LDSW2_ON_MASK, enabled); + default: + return -ENODEV; + } +} + +static int soft_start_set(const struct device *dev, uint8_t soft_start) +{ + const struct regulator_npm1300_config *config = dev->config; + + switch (config->source) { + case NPM1300_SOURCE_LDO1: + return mfd_npm1300_reg_update(config->mfd, LDSW_BASE, LDSW_OFFSET_CONFIG, + soft_start << LDSW1_SOFTSTART_SHIFT, + LDSW1_SOFTSTART_MASK); + case NPM1300_SOURCE_LDO2: + return mfd_npm1300_reg_update(config->mfd, LDSW_BASE, LDSW_OFFSET_CONFIG, + soft_start << LDSW2_SOFTSTART_SHIFT, + LDSW2_SOFTSTART_MASK); + default: + return -ENOTSUP; + } +} + int regulator_npm1300_init(const struct device *dev) { const struct regulator_npm1300_config *config = dev->config; + bool enabled; int ret = 0; if (!device_is_ready(config->mfd)) { return -ENODEV; } - ret = regulator_common_init(dev, false); + ret = get_enabled(dev, &enabled); + if (ret < 0) { + return ret; + } + + ret = regulator_common_init(dev, enabled); if (ret < 0) { return ret; } @@ -534,6 +606,14 @@ int regulator_npm1300_init(const struct device *dev) } } + /* Configure soft start */ + if (config->soft_start != UINT8_MAX) { + ret = soft_start_set(dev, config->soft_start); + if (ret != 0) { + return ret; + } + } + /* Configure GPIO pin control */ ret = regulator_npm1300_set_pin_ctrl(dev, &config->enable_gpios, NPM1300_GPIO_TYPE_ENABLE); if (ret != 0) { @@ -570,6 +650,7 @@ static const struct regulator_driver_api api = {.enable = regulator_npm1300_enab .mfd = DEVICE_DT_GET(DT_GPARENT(node_id)), \ .source = _source, \ .retention_uv = DT_PROP_OR(node_id, retention_microvolt, 0), \ + .soft_start = DT_ENUM_IDX_OR(node_id, soft_start_microamp, UINT8_MAX), \ .enable_gpios = GPIO_DT_SPEC_GET_OR(node_id, enable_gpios, {0}), \ .retention_gpios = GPIO_DT_SPEC_GET_OR(node_id, retention_gpios, {0}), \ .pwm_gpios = GPIO_DT_SPEC_GET_OR(node_id, pwm_gpios, {0})}; \ diff --git a/drivers/regulator/regulator_pca9420.c b/drivers/regulator/regulator_pca9420.c index 71dd55525b8ff32..705d4f3a8e92b45 100644 --- a/drivers/regulator/regulator_pca9420.c +++ b/drivers/regulator/regulator_pca9420.c @@ -18,10 +18,14 @@ /** General purpose registers */ /** @brief Top level system ctrl 0 */ #define PCA9420_TOP_CNTL0 0x09U +/** @brief Top level system ctrl 2 */ +#define PCA9420_TOP_CNTL2 0x0BU /** @brief Top level system ctrl 3 */ #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 */ @@ -36,6 +40,10 @@ #define PCA9420_TOP_CNTL0_VIN_ILIM_SEL_MASK 0xE0U #define PCA9420_TOP_CNTL0_VIN_ILIM_SEL_DISABLED 0x7U +/** @brief ASYS UVLO threshold selection */ +#define PCA9420_TOP_CNTL2_ASYS_UVLO_SEL_POS 6U +#define PCA9420_TOP_CNTL2_ASYS_UVLO_SEL_MASK 0xC0U + /** @brief I2C Mode control mask */ #define PCA9420_TOP_CNTL3_MODE_I2C_POS 3U #define PCA9420_TOP_CNTL3_MODE_I2C_MASK 0x18U @@ -75,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 @@ -93,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; @@ -102,6 +124,7 @@ struct regulator_pca9420_common_config { struct i2c_dt_spec i2c; int32_t vin_ilim_ua; bool enable_modesel_pins; + uint8_t asys_uvlo_sel_mv; }; struct regulator_pca9420_common_data { @@ -152,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), @@ -164,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), @@ -176,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), @@ -188,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), @@ -272,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; @@ -306,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) @@ -427,10 +490,20 @@ static int regulator_pca9420_common_init(const struct device *dev) PCA9420_VIN_ILIM_UA_LSB; } - return i2c_reg_update_byte_dt( + ret = i2c_reg_update_byte_dt( &config->i2c, PCA9420_TOP_CNTL0, PCA9420_TOP_CNTL0_VIN_ILIM_SEL_MASK, reg_val << PCA9420_TOP_CNTL0_VIN_ILIM_SEL_POS); + + if (ret != 0) { + return ret; + } + + /* configure ASYS UVLO threshold */ + return i2c_reg_update_byte_dt(&config->i2c, PCA9420_TOP_CNTL2, + PCA9420_TOP_CNTL2_ASYS_UVLO_SEL_MASK, + config->asys_uvlo_sel_mv << + PCA9420_TOP_CNTL2_ASYS_UVLO_SEL_POS); } #define REGULATOR_PCA9420_DEFINE(node_id, id, name, _parent) \ @@ -465,6 +538,8 @@ static int regulator_pca9420_common_init(const struct device *dev) .vin_ilim_ua = DT_INST_PROP(inst, nxp_vin_ilim_microamp), \ .enable_modesel_pins = \ DT_INST_PROP(inst, nxp_enable_modesel_pins), \ + .asys_uvlo_sel_mv = \ + DT_INST_ENUM_IDX(inst, nxp_asys_uvlo_sel_millivolt), \ }; \ \ static struct regulator_pca9420_common_data data_##inst; \ diff --git a/drivers/regulator/regulator_shell.c b/drivers/regulator/regulator_shell.c index 4caaa9f88156858..5dddbb5b8d72636 100644 --- a/drivers/regulator/regulator_shell.c +++ b/drivers/regulator/regulator_shell.c @@ -221,6 +221,38 @@ static int cmd_vget(const struct shell *sh, size_t argc, char **argv) return 0; } +static int cmd_clist(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + unsigned int current_cnt; + int32_t last_current_ua; + + ARG_UNUSED(argc); + + dev = device_get_binding(argv[1]); + if (dev == NULL) { + shell_error(sh, "Regulator device %s not available", argv[1]); + return -ENODEV; + } + + current_cnt = regulator_count_current_limits(dev); + + for (unsigned int i = 0U; i < current_cnt; i++) { + int32_t current_ua; + + (void)regulator_list_current_limit(dev, i, ¤t_ua); + + /* do not print repeated current limits */ + if ((i == 0U) || (last_current_ua != current_ua)) { + microtoshell(sh, 'A', current_ua); + } + + last_current_ua = current_ua; + } + + return 0; +} + static int cmd_iset(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; @@ -332,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; @@ -449,6 +538,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE( "Get voltage\n" "Usage: vget ", cmd_vget, 2, 0), + SHELL_CMD_ARG(clist, &dsub_device_name, + "List all supported current limits\n" + "Usage: clist ", + cmd_clist, 2, 0), SHELL_CMD_ARG(iset, &dsub_device_name, "Set current limit\n" "Input requires units, e.g. 200ma, 20.5ma, 10ua, 1a...\n" @@ -467,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 c119347a7671715..4f9322c3a892b32 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 4a4231c4968ad92..0348efbab105828 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_handlers.c b/drivers/retained_mem/retained_mem_handlers.c index 265ae7b15fd9b52..d344e37b42c360d 100644 --- a/drivers/retained_mem/retained_mem_handlers.c +++ b/drivers/retained_mem/retained_mem_handlers.c @@ -5,11 +5,11 @@ */ #include -#include +#include static inline ssize_t z_vrfy_retained_mem_size(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_RETAINED_MEM)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_RETAINED_MEM)); return z_impl_retained_mem_size(dev); } #include @@ -17,8 +17,8 @@ static inline ssize_t z_vrfy_retained_mem_size(const struct device *dev) static inline int z_vrfy_retained_mem_read(const struct device *dev, off_t offset, uint8_t *buffer, size_t size) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_RETAINED_MEM)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(buffer, size)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_RETAINED_MEM)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(buffer, size)); return z_impl_retained_mem_read(dev, offset, buffer, size); } #include @@ -26,15 +26,15 @@ static inline int z_vrfy_retained_mem_read(const struct device *dev, off_t offse static inline int z_vrfy_retained_mem_write(const struct device *dev, off_t offset, const uint8_t *buffer, size_t size) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_RETAINED_MEM)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(buffer, size)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_RETAINED_MEM)); + K_OOPS(K_SYSCALL_MEMORY_READ(buffer, size)); return z_impl_retained_mem_write(dev, offset, buffer, size); } #include static inline int z_vrfy_retained_mem_clear(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_RETAINED_MEM)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_RETAINED_MEM)); return z_impl_retained_mem_clear(dev); } #include 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 000000000000000..a302e175a6eaf11 --- /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/CMakeLists.txt b/drivers/rtc/CMakeLists.txt index 94cda7627c469a7..65d822dbe6e088a 100644 --- a/drivers/rtc/CMakeLists.txt +++ b/drivers/rtc/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/rtc.h) zephyr_library() zephyr_library_sources_ifdef(CONFIG_RTC_AM1805 rtc_am1805.c) +zephyr_library_sources_ifdef(CONFIG_RTC_DS1307 rtc_ds1307.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE rtc_handlers.c) zephyr_library_sources_ifdef(CONFIG_RTC_EMUL rtc_emul.c) zephyr_library_sources_ifdef(CONFIG_RTC_PCF8523 rtc_pcf8523.c) @@ -14,3 +15,5 @@ zephyr_library_sources_ifdef(CONFIG_RTC_MOTOROLA_MC146818 rtc_mc146818.c) zephyr_library_sources_ifdef(CONFIG_RTC_STM32 rtc_ll_stm32.c) zephyr_library_sources_ifdef(CONFIG_RTC_SHELL rtc_shell.c) zephyr_library_sources_ifdef(CONFIG_RTC_FAKE rtc_fake.c) +zephyr_library_sources_ifdef(CONFIG_RTC_SMARTBOND rtc_smartbond.c) +zephyr_library_sources_ifdef(CONFIG_RTC_ATMEL_SAM rtc_sam.c) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 97cc21fef0e1ca5..10b228ceeabc7f2 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -42,11 +42,14 @@ config RTC_SHELL RTC Shell commands source "drivers/rtc/Kconfig.am1805" +source "drivers/rtc/Kconfig.ds1307" source "drivers/rtc/Kconfig.emul" source "drivers/rtc/Kconfig.fake" source "drivers/rtc/Kconfig.pcf8523" source "drivers/rtc/Kconfig.pcf8563" source "drivers/rtc/Kconfig.mc146818" +source "drivers/rtc/Kconfig.sam" source "drivers/rtc/Kconfig.stm32" +source "drivers/rtc/Kconfig.smartbond" endif # RTC diff --git a/drivers/rtc/Kconfig.ds1307 b/drivers/rtc/Kconfig.ds1307 new file mode 100644 index 000000000000000..b350846f58ec63d --- /dev/null +++ b/drivers/rtc/Kconfig.ds1307 @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 Arunmani Alagarsamy +# Author: Arunmani Alagarsamy + +config RTC_DS1307 + bool "MAXIM DS1307 RTC driver" + default y + depends on DT_HAS_MAXIM_DS1307_ENABLED + select I2C + help + Enable the MAXIM DS1307 RTC driver. diff --git a/drivers/rtc/Kconfig.sam b/drivers/rtc/Kconfig.sam new file mode 100644 index 000000000000000..5968f66bc4222f9 --- /dev/null +++ b/drivers/rtc/Kconfig.sam @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +config RTC_ATMEL_SAM + bool "Atmel SAM RTC driver" + default y + depends on DT_HAS_ATMEL_SAM_RTC_ENABLED + help + Atmel Real-Time Clock (RTC) driver used on SAM SoC series. diff --git a/drivers/rtc/Kconfig.smartbond b/drivers/rtc/Kconfig.smartbond new file mode 100644 index 000000000000000..d21d3a962fa7f71 --- /dev/null +++ b/drivers/rtc/Kconfig.smartbond @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config RTC_SMARTBOND + bool "Smartbond RTC driver" + depends on DT_HAS_RENESAS_SMARTBOND_RTC_ENABLED + default y + help + Build RTC driver for Smartbond SoCs. diff --git a/drivers/rtc/rtc_ds1307.c b/drivers/rtc/rtc_ds1307.c new file mode 100644 index 000000000000000..bfbe0abe2550f92 --- /dev/null +++ b/drivers/rtc/rtc_ds1307.c @@ -0,0 +1,160 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Arunmani Alagarsamy + * Author: Arunmani Alagarsamy + */ + +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT maxim_ds1307 + +LOG_MODULE_REGISTER(ds1307, CONFIG_RTC_LOG_LEVEL); + +/* DS1307 registers */ +#define DS1307_REG_SECONDS 0x00 +#define DS1307_REG_MINUTES 0x01 +#define DS1307_REG_HOURS 0x02 +#define DS1307_REG_DAY 0x03 +#define DS1307_REG_DATE 0x04 +#define DS1307_REG_MONTH 0x05 +#define DS1307_REG_YEAR 0x06 +#define DS1307_REG_CTRL 0x07 + +#define SECONDS_BITS GENMASK(6, 0) +#define MINUTES_BITS GENMASK(7, 0) +#define HOURS_BITS GENMASK(5, 0) +#define DATE_BITS GENMASK(5, 0) +#define MONTHS_BITS GENMASK(4, 0) +#define WEEKDAY_BITS GENMASK(2, 0) +#define YEAR_BITS GENMASK(7, 0) +#define VALIDATE_24HR BIT(6) + +struct ds1307_config { + struct i2c_dt_spec i2c_bus; +}; + +struct ds1307_data { + struct k_spinlock lock; +}; + +static int ds1307_set_time(const struct device *dev, const struct rtc_time *tm) +{ + int err; + uint8_t regs[7]; + + struct ds1307_data *data = dev->data; + const struct ds1307_config *config = dev->config; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + LOG_DBG("set time: year = %d, mon = %d, mday = %d, wday = %d, hour = %d, " + "min = %d, sec = %d", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, tm->tm_hour, tm->tm_min, + tm->tm_sec); + + regs[0] = bin2bcd(tm->tm_sec) & SECONDS_BITS; + regs[1] = bin2bcd(tm->tm_min); + regs[2] = bin2bcd(tm->tm_hour); + regs[3] = bin2bcd(tm->tm_wday); + regs[4] = bin2bcd(tm->tm_mday); + regs[5] = bin2bcd(tm->tm_mon); + regs[6] = bin2bcd((tm->tm_year % 100)); + + err = i2c_burst_write_dt(&config->i2c_bus, DS1307_REG_SECONDS, regs, sizeof(regs)); + + k_spin_unlock(&data->lock, key); + + return err; +} + +static int ds1307_get_time(const struct device *dev, struct rtc_time *timeptr) +{ + int err; + uint8_t regs[7]; + + struct ds1307_data *data = dev->data; + const struct ds1307_config *config = dev->config; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + err = i2c_burst_read_dt(&config->i2c_bus, DS1307_REG_SECONDS, regs, sizeof(regs)); + if (err != 0) { + goto unlock; + } + + timeptr->tm_sec = bcd2bin(regs[0] & SECONDS_BITS); + timeptr->tm_min = bcd2bin(regs[1] & MINUTES_BITS); + timeptr->tm_hour = bcd2bin(regs[2] & HOURS_BITS); /* 24hr mode */ + timeptr->tm_wday = bcd2bin(regs[3] & WEEKDAY_BITS); + timeptr->tm_mday = bcd2bin(regs[4] & DATE_BITS); + timeptr->tm_mon = bcd2bin(regs[5] & MONTHS_BITS); + timeptr->tm_year = bcd2bin(regs[6] & YEAR_BITS); + timeptr->tm_year = timeptr->tm_year + 100; + + /* Not used */ + timeptr->tm_nsec = 0; + timeptr->tm_isdst = -1; + timeptr->tm_yday = -1; + + /* Validate the chip in 24hr mode */ + if (regs[2] & VALIDATE_24HR) { + err = -ENODATA; + goto unlock; + } + + LOG_DBG("get time: year = %d, mon = %d, mday = %d, wday = %d, hour = %d, " + "min = %d, sec = %d", + timeptr->tm_year, timeptr->tm_mon, timeptr->tm_mday, timeptr->tm_wday, + timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec); + +unlock: + k_spin_unlock(&data->lock, key); + + return err; +} + +static const struct rtc_driver_api ds1307_driver_api = { + .set_time = ds1307_set_time, + .get_time = ds1307_get_time, +}; + +static int ds1307_init(const struct device *dev) +{ + int err; + const struct ds1307_config *config = dev->config; + + if (!i2c_is_ready_dt(&config->i2c_bus)) { + LOG_ERR("I2C bus not ready"); + return -ENODEV; + } + + /* Disable squarewave output */ + err = i2c_reg_write_byte_dt(&config->i2c_bus, DS1307_REG_CTRL, 0x00); + if (err < 0) { + LOG_ERR("Error: SQW:%d\n", err); + } + + /* Make clock halt = 0 */ + err = i2c_reg_write_byte_dt(&config->i2c_bus, DS1307_REG_SECONDS, 0x00); + if (err < 0) { + LOG_ERR("Error: Set clock halt bit:%d\n", err); + } + + return 0; +} + +#define DS1307_DEFINE(inst) \ + static struct ds1307_data ds1307_data_##inst; \ + static const struct ds1307_config ds1307_config_##inst = { \ + .i2c_bus = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, &ds1307_init, NULL, &ds1307_data_##inst, \ + &ds1307_config_##inst, POST_KERNEL, CONFIG_RTC_INIT_PRIORITY, \ + &ds1307_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DS1307_DEFINE) diff --git a/drivers/rtc/rtc_emul.c b/drivers/rtc/rtc_emul.c index bf95fa87813b33e..9ce6b5dbc25f396 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 86d66ebd5f850a8..f02cf48b2e8ec0e 100644 --- a/drivers/rtc/rtc_fake.c +++ b/drivers/rtc/rtc_fake.c @@ -11,9 +11,9 @@ #include #include -#ifdef CONFIG_ZTEST_NEW_API +#ifdef CONFIG_ZTEST #include -#endif /* CONFIG_ZTEST_NEW_API */ +#endif /* CONFIG_ZTEST */ DEFINE_FAKE_VALUE_FUNC(int, rtc_fake_set_time, const struct device *, const struct rtc_time *); DEFINE_FAKE_VALUE_FUNC(int, rtc_fake_get_time, const struct device *, struct rtc_time *); @@ -40,7 +40,7 @@ DEFINE_FAKE_VALUE_FUNC(int, rtc_fake_set_calibration, const struct device *, int DEFINE_FAKE_VALUE_FUNC(int, rtc_fake_get_calibration, const struct device *, int32_t *); #endif /* CONFIG_RTC_CALIBRATION */ -#ifdef CONFIG_ZTEST_NEW_API +#ifdef CONFIG_ZTEST static void fake_rtc_reset_rule_before(const struct ztest_unit_test *test, void *fixture) { ARG_UNUSED(test); @@ -68,9 +68,9 @@ 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_NEW_API */ +#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_handlers.c b/drivers/rtc/rtc_handlers.c index a0e9cb34a8cd38a..33bb9076971105b 100644 --- a/drivers/rtc/rtc_handlers.c +++ b/drivers/rtc/rtc_handlers.c @@ -5,20 +5,20 @@ */ #include -#include +#include static inline int z_vrfy_rtc_set_time(const struct device *dev, const struct rtc_time *timeptr) { - Z_OOPS(Z_SYSCALL_DRIVER_RTC(dev, set_time)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(timeptr, sizeof(struct rtc_time))); + K_OOPS(K_SYSCALL_DRIVER_RTC(dev, set_time)); + K_OOPS(K_SYSCALL_MEMORY_READ(timeptr, sizeof(struct rtc_time))); return z_impl_rtc_set_time(dev, timeptr); } #include static inline int z_vrfy_rtc_get_time(const struct device *dev, struct rtc_time *timeptr) { - Z_OOPS(Z_SYSCALL_DRIVER_RTC(dev, get_time)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(timeptr, sizeof(struct rtc_time))); + K_OOPS(K_SYSCALL_DRIVER_RTC(dev, get_time)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(timeptr, sizeof(struct rtc_time))); return z_impl_rtc_get_time(dev, timeptr); } #include @@ -27,8 +27,8 @@ static inline int z_vrfy_rtc_get_time(const struct device *dev, struct rtc_time static inline int z_vrfy_rtc_alarm_get_supported_fields(const struct device *dev, uint16_t id, uint16_t *mask) { - Z_OOPS(Z_SYSCALL_DRIVER_RTC(dev, alarm_get_supported_fields)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(mask, sizeof(uint16_t))); + K_OOPS(K_SYSCALL_DRIVER_RTC(dev, alarm_get_supported_fields)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(mask, sizeof(uint16_t))); return z_impl_rtc_alarm_get_supported_fields(dev, id, mask); } #include @@ -36,8 +36,8 @@ static inline int z_vrfy_rtc_alarm_get_supported_fields(const struct device *dev static inline int z_vrfy_rtc_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask, const struct rtc_time *timeptr) { - Z_OOPS(Z_SYSCALL_DRIVER_RTC(dev, alarm_set_time)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(timeptr, sizeof(struct rtc_time))); + K_OOPS(K_SYSCALL_DRIVER_RTC(dev, alarm_set_time)); + K_OOPS(K_SYSCALL_MEMORY_READ(timeptr, sizeof(struct rtc_time))); return z_impl_rtc_alarm_set_time(dev, id, mask, timeptr); } #include @@ -45,16 +45,16 @@ static inline int z_vrfy_rtc_alarm_set_time(const struct device *dev, uint16_t i static inline int z_vrfy_rtc_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask, struct rtc_time *timeptr) { - Z_OOPS(Z_SYSCALL_DRIVER_RTC(dev, alarm_get_time)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(mask, sizeof(uint16_t))); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(timeptr, sizeof(struct rtc_time))); + K_OOPS(K_SYSCALL_DRIVER_RTC(dev, alarm_get_time)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(mask, sizeof(uint16_t))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(timeptr, sizeof(struct rtc_time))); return z_impl_rtc_alarm_get_time(dev, id, mask, timeptr); } #include static inline int z_vrfy_rtc_alarm_is_pending(const struct device *dev, uint16_t id) { - Z_OOPS(Z_SYSCALL_DRIVER_RTC(dev, alarm_is_pending)); + K_OOPS(K_SYSCALL_DRIVER_RTC(dev, alarm_is_pending)); return z_impl_rtc_alarm_is_pending(dev, id); } #include @@ -63,7 +63,7 @@ static inline int z_vrfy_rtc_alarm_is_pending(const struct device *dev, uint16_t #ifdef CONFIG_RTC_CALIBRATION static inline int z_vrfy_rtc_set_calibration(const struct device *dev, int32_t calibration) { - Z_OOPS(Z_SYSCALL_DRIVER_RTC(dev, set_calibration)); + K_OOPS(K_SYSCALL_DRIVER_RTC(dev, set_calibration)); return z_impl_rtc_set_calibration(dev, calibration); } @@ -71,8 +71,8 @@ static inline int z_vrfy_rtc_set_calibration(const struct device *dev, int32_t c static inline int z_vrfy_rtc_get_calibration(const struct device *dev, int32_t *calibration) { - Z_OOPS(Z_SYSCALL_DRIVER_RTC(dev, get_calibration)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(calibration, sizeof(int32_t))); + K_OOPS(K_SYSCALL_DRIVER_RTC(dev, get_calibration)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(calibration, sizeof(int32_t))); return z_impl_rtc_get_calibration(dev, calibration); } #include diff --git a/drivers/rtc/rtc_ll_stm32.c b/drivers/rtc/rtc_ll_stm32.c index 8714439ef47aeb1..8e1ee9419b53089 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 6ecdfafa6346cea..15d36c623b09494 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_pcf8523.c b/drivers/rtc/rtc_pcf8523.c index 1e1a7a1ddfa2c83..b6be011d61b73a0 100644 --- a/drivers/rtc/rtc_pcf8523.c +++ b/drivers/rtc/rtc_pcf8523.c @@ -254,8 +254,12 @@ static int pcf8523_int1_enable_unlocked(const struct device *dev, bool enable) return 0; } -static void pcf8523_int1_thread(const struct device *dev) +static void pcf8523_int1_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; struct pcf8523_data *data = dev->data; rtc_alarm_callback alarm_callback = NULL; void *alarm_user_data = NULL; @@ -791,7 +795,7 @@ static int pcf8523_init(const struct device *dev) tid = k_thread_create(&data->int1_thread, data->int1_stack, K_THREAD_STACK_SIZEOF(data->int1_stack), - (k_thread_entry_t)pcf8523_int1_thread, (void *)dev, NULL, + pcf8523_int1_thread, (void *)dev, NULL, NULL, CONFIG_RTC_PCF8523_THREAD_PRIO, 0, K_NO_WAIT); k_thread_name_set(tid, "pcf8523"); diff --git a/drivers/rtc/rtc_pcf8563.c b/drivers/rtc/rtc_pcf8563.c index 4b16707dee8ec2b..515adaf5584451a 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 new file mode 100644 index 000000000000000..e50edd94e3c095a --- /dev/null +++ b/drivers/rtc/rtc_sam.c @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2023 Bjarki Arge Andreasen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT atmel_sam_rtc + +#include +#include +#include +#include +#include + +#include +#include + +#define RTC_SAM_REG_GET_FIELD(value, field) \ + ((RTC_##field##_Msk & value) >> RTC_##field##_Pos) + +#define RTC_SAM_WPMR_DISABLE 0x52544300 +#define RTC_SAM_WPMR_ENABLE 0x52544301 + +#define RTC_SAM_CALIBRATE_PPB_MAX (1950000) +#define RTC_SAM_CALIBRATE_PPB_MIN (-1950000) +#define RTC_SAM_CALIBRATE_PPB_QUANTA (1500) +#define RTC_SAM_CALIBRATE_PPB_LOW_SCALE (30500) + +typedef void (*rtc_sam_irq_init_fn_ptr)(void); + +struct rtc_sam_config { + Rtc *regs; + uint16_t irq_num; + rtc_sam_irq_init_fn_ptr irq_init_fn_ptr; +}; + +struct rtc_sam_data { +#ifdef CONFIG_RTC_ALARM + rtc_alarm_callback alarm_callback; + void *alarm_user_data; +#endif /* CONFIG_RTC_ALARM */ +#ifdef CONFIG_RTC_UPDATE + rtc_update_callback update_callback; + void *update_user_data; +#endif /* CONFIG_RTC_UPDATE */ + struct k_spinlock lock; + struct k_sem cr_sec_evt_sem; + struct k_sem cr_upd_ack_sem; +}; + +static void rtc_sam_disable_wp(void) +{ + REG_RTC_WPMR = RTC_SAM_WPMR_DISABLE; +} + +static void rtc_sam_enable_wp(void) +{ + REG_RTC_WPMR = RTC_SAM_WPMR_ENABLE; +} + +static bool rtc_sam_validate_tm(const struct rtc_time *timeptr, uint32_t mask) +{ + if ((mask & RTC_ALARM_TIME_MASK_SECOND) && + (timeptr->tm_sec < 0 || timeptr->tm_sec > 59)) { + return false; + } + + if ((mask & RTC_ALARM_TIME_MASK_MINUTE) && + (timeptr->tm_min < 0 || timeptr->tm_min > 59)) { + return false; + } + + if ((mask & RTC_ALARM_TIME_MASK_HOUR) && + (timeptr->tm_hour < 0 || timeptr->tm_hour > 23)) { + return false; + } + + if ((mask & RTC_ALARM_TIME_MASK_MONTH) && + (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)) { + return false; + } + + if ((mask & RTC_ALARM_TIME_MASK_MONTHDAY) && + (timeptr->tm_mday < 1 || timeptr->tm_mday > 31)) { + return false; + } + + if ((mask & RTC_ALARM_TIME_MASK_YEAR) && + (timeptr->tm_year < 0 || timeptr->tm_year > 199)) { + return false; + } + + return true; +} + +static uint32_t rtc_sam_timr_from_tm(const struct rtc_time *timeptr) +{ + uint32_t timr; + + timr = RTC_TIMR_SEC(bin2bcd(timeptr->tm_sec)); + timr |= RTC_TIMR_MIN(bin2bcd(timeptr->tm_min)); + timr |= RTC_TIMR_HOUR(bin2bcd(timeptr->tm_hour)); + + return timr; +} + +static uint32_t rtc_sam_calr_from_tm(const struct rtc_time *timeptr) +{ + uint32_t calr; + uint8_t centuries; + uint8_t years; + + calr = RTC_CALR_DATE(bin2bcd(timeptr->tm_mday)); + calr |= RTC_CALR_MONTH(bin2bcd(timeptr->tm_mon + 1)); + centuries = (uint8_t)((timeptr->tm_year / 100) + 19); + years = (uint8_t)((timeptr->tm_year % 100)); + calr |= RTC_CALR_CENT(bin2bcd(centuries)); + calr |= RTC_CALR_YEAR(bin2bcd(years)); + calr |= RTC_CALR_DAY(bin2bcd(timeptr->tm_wday + 1)); + return calr; +} + +static int rtc_sam_set_time(const struct device *dev, const struct rtc_time *timeptr) +{ + struct rtc_sam_data *data = dev->data; + const struct rtc_sam_config *config = dev->config; + Rtc *regs = config->regs; + + if (rtc_sam_validate_tm(timeptr, UINT32_MAX) == false) { + return -EINVAL; + } + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + k_sem_reset(&data->cr_sec_evt_sem); + k_sem_take(&data->cr_sec_evt_sem, K_MSEC(1100)); + k_sem_reset(&data->cr_upd_ack_sem); + + /* Enable update acknowledge interrupt */ + regs->RTC_IER = RTC_IER_ACKEN; + + rtc_sam_disable_wp(); + + /* Request update */ + regs->RTC_CR = (RTC_CR_UPDTIM | RTC_CR_UPDCAL); + + /* Await update acknowledge */ + if (k_sem_take(&data->cr_upd_ack_sem, K_MSEC(1100)) < 0) { + regs->RTC_CR = 0; + + rtc_sam_enable_wp(); + + /* Disable update acknowledge interrupt */ + regs->RTC_IDR = RTC_IDR_ACKDIS; + + k_spin_unlock(&data->lock, key); + return -EAGAIN; + } + + regs->RTC_TIMR = rtc_sam_timr_from_tm(timeptr); + regs->RTC_CALR = rtc_sam_calr_from_tm(timeptr); + regs->RTC_CR = 0; + rtc_sam_enable_wp(); + regs->RTC_IDR = RTC_IDR_ACKDIS; + k_spin_unlock(&data->lock, key); + return 0; +} + +static int rtc_sam_get_time(const struct device *dev, struct rtc_time *timeptr) +{ + const struct rtc_sam_config *config = dev->config; + Rtc *regs = config->regs; + + uint32_t timr0; + uint32_t calr0; + uint32_t timr1; + uint32_t calr1; + + /* Validate time and date */ + if (regs->RTC_VER & (RTC_VER_NVTIM | RTC_VER_NVCAL)) { + return -ENODATA; + } + + /* Read until synchronized (registers updated async) */ + while (1) { + timr0 = regs->RTC_TIMR; + calr0 = regs->RTC_CALR; + timr1 = regs->RTC_TIMR; + calr1 = regs->RTC_CALR; + + if ((timr0 == timr1) && (calr0 == calr1)) { + break; + } + } + + timeptr->tm_sec = bcd2bin(RTC_SAM_REG_GET_FIELD(timr0, TIMR_SEC)); + timeptr->tm_min = bcd2bin(RTC_SAM_REG_GET_FIELD(timr0, TIMR_MIN)); + timeptr->tm_hour = bcd2bin(RTC_SAM_REG_GET_FIELD(timr0, TIMR_HOUR)); + timeptr->tm_mday = bcd2bin(RTC_SAM_REG_GET_FIELD(calr0, CALR_DATE)); + timeptr->tm_mon = bcd2bin(RTC_SAM_REG_GET_FIELD(calr0, CALR_MONTH)) - 1; + + timeptr->tm_year = bcd2bin(RTC_SAM_REG_GET_FIELD(calr0, CALR_YEAR)); + timeptr->tm_year += ((int)bcd2bin(RTC_SAM_REG_GET_FIELD(calr0, CALR_CENT))) * 100; + timeptr->tm_year -= 1900; + + timeptr->tm_wday = bcd2bin(RTC_SAM_REG_GET_FIELD(calr0, CALR_DAY)) - 1; + timeptr->tm_yday = -1; + timeptr->tm_isdst = -1; + timeptr->tm_nsec = 0; + return 0; +} + +static void rtc_sam_isr(const struct device *dev) +{ + struct rtc_sam_data *data = dev->data; + const struct rtc_sam_config *config = dev->config; + Rtc *regs = config->regs; + + uint32_t sr = regs->RTC_SR; + + if (sr & RTC_SR_ACKUPD) { + regs->RTC_SCCR = RTC_SCCR_ACKCLR; + k_sem_give(&data->cr_upd_ack_sem); + } + +#ifdef CONFIG_RTC_ALARM + if (sr & RTC_SR_ALARM) { + regs->RTC_SCCR = RTC_SCCR_ALRCLR; + if (data->alarm_callback != NULL) { + data->alarm_callback(dev, 0, data->alarm_user_data); + } + } +#endif /* CONFIG_RTC_ALARM */ + +#ifdef CONFIG_RTC_UPDATE + if (sr & RTC_SR_SEC) { + regs->RTC_SCCR = RTC_SCCR_SECCLR; + if (data->update_callback != NULL) { + data->update_callback(dev, data->update_user_data); + } + + k_sem_give(&data->cr_sec_evt_sem); + } +#endif /* CONFIG_RTC_UPDATE */ +} + +#ifdef CONFIG_RTC_ALARM +static uint16_t rtc_sam_alarm_get_supported_mask(void) +{ + return (RTC_ALARM_TIME_MASK_SECOND + | RTC_ALARM_TIME_MASK_MINUTE + | RTC_ALARM_TIME_MASK_HOUR + | RTC_ALARM_TIME_MASK_MONTHDAY + | RTC_ALARM_TIME_MASK_MONTH); +} + +static uint32_t rtc_atmel_timalr_from_tm(const struct rtc_time *timeptr, uint32_t mask) +{ + uint32_t timalr = 0; + + if (mask & RTC_ALARM_TIME_MASK_SECOND) { + timalr |= RTC_TIMALR_SECEN; + timalr |= RTC_TIMALR_SEC(bin2bcd(timeptr->tm_sec)); + } + + if (mask & RTC_ALARM_TIME_MASK_MINUTE) { + timalr |= RTC_TIMALR_MINEN; + timalr |= RTC_TIMALR_MIN(bin2bcd(timeptr->tm_min)); + } + + if (mask & RTC_ALARM_TIME_MASK_HOUR) { + timalr |= RTC_TIMALR_HOUREN; + timalr |= RTC_TIMALR_HOUR(bin2bcd(timeptr->tm_hour)); + } + + return timalr; +} + +static uint32_t rtc_atmel_calalr_from_tm(const struct rtc_time *timeptr, uint32_t mask) +{ + uint32_t calalr = RTC_CALALR_MONTH(1) | RTC_CALALR_DATE(1); + + if (mask & RTC_ALARM_TIME_MASK_MONTH) { + calalr |= RTC_CALALR_MTHEN; + calalr |= RTC_CALALR_MONTH(bin2bcd(timeptr->tm_mon + 1)); + } + + if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) { + calalr |= RTC_CALALR_DATEEN; + calalr |= RTC_CALALR_DATE(bin2bcd(timeptr->tm_mday)); + } + + return calalr; +} + +static uint32_t rtc_sam_alarm_mask_from_timalr(uint32_t timalr) +{ + uint32_t mask = 0; + + if (timalr & RTC_TIMALR_SECEN) { + mask |= RTC_ALARM_TIME_MASK_SECOND; + } + + if (timalr & RTC_TIMALR_MINEN) { + mask |= RTC_ALARM_TIME_MASK_MINUTE; + } + + if (timalr & RTC_TIMALR_HOUREN) { + mask |= RTC_ALARM_TIME_MASK_HOUR; + } + + return mask; +} + +static uint32_t rtc_sam_alarm_mask_from_calalr(uint32_t calalr) +{ + uint32_t mask = 0; + + if (calalr & RTC_CALALR_MTHEN) { + mask |= RTC_ALARM_TIME_MASK_MONTH; + } + + if (calalr & RTC_CALALR_DATEEN) { + mask |= RTC_ALARM_TIME_MASK_MONTHDAY; + } + + return mask; +} + +static void rtc_sam_tm_from_timalr_calalr(struct rtc_time *timeptr, uint32_t mask, + uint32_t timalr, uint32_t calalr) +{ + memset(timeptr, 0x00, sizeof(*timeptr)); + + if (mask & RTC_ALARM_TIME_MASK_SECOND) { + timeptr->tm_sec = bcd2bin(RTC_SAM_REG_GET_FIELD(timalr, TIMALR_SEC)); + } + + if (mask & RTC_ALARM_TIME_MASK_MINUTE) { + timeptr->tm_min = bcd2bin(RTC_SAM_REG_GET_FIELD(timalr, TIMALR_MIN)); + } + + if (mask & RTC_ALARM_TIME_MASK_HOUR) { + timeptr->tm_hour = bcd2bin(RTC_SAM_REG_GET_FIELD(timalr, TIMALR_HOUR)); + } + + if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) { + timeptr->tm_mday = bcd2bin(RTC_SAM_REG_GET_FIELD(calalr, CALALR_DATE)); + } + + if (mask & RTC_ALARM_TIME_MASK_MONTH) { + timeptr->tm_mon = bcd2bin(RTC_SAM_REG_GET_FIELD(calalr, CALALR_MONTH)) - 1; + } +} + +static int rtc_sam_alarm_get_supported_fields(const struct device *dev, uint16_t id, + uint16_t *mask) +{ + ARG_UNUSED(dev); + ARG_UNUSED(id); + + *mask = rtc_sam_alarm_get_supported_mask(); + return 0; +} + +static int rtc_sam_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask, + const struct rtc_time *timeptr) +{ + struct rtc_sam_data *data = dev->data; + const struct rtc_sam_config *config = dev->config; + Rtc *regs = config->regs; + + uint32_t timalr; + uint32_t calalr; + uint32_t mask_supported; + + mask_supported = rtc_sam_alarm_get_supported_mask(); + + if ((id != 0)) { + return -EINVAL; + } + + if ((mask > 0) && (timeptr == NULL)) { + return -EINVAL; + } + + if (mask & ~mask_supported) { + return -EINVAL; + } + + if (rtc_sam_validate_tm(timeptr, mask) == false) { + return -EINVAL; + } + + timalr = rtc_atmel_timalr_from_tm(timeptr, mask); + calalr = rtc_atmel_calalr_from_tm(timeptr, mask); + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + irq_disable(config->irq_num); + rtc_sam_disable_wp(); + + /* Set RTC alarm time */ + regs->RTC_TIMALR = timalr; + regs->RTC_CALALR = calalr; + + rtc_sam_enable_wp(); + + /* Clear alarm pending status */ + regs->RTC_SCCR = RTC_SCCR_ALRCLR; + + irq_enable(config->irq_num); + k_spin_unlock(&data->lock, key); + return 0; +} + +static int rtc_sam_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask, + struct rtc_time *timeptr) +{ + struct rtc_sam_data *data = dev->data; + const struct rtc_sam_config *config = dev->config; + Rtc *regs = config->regs; + + uint32_t timalr; + uint32_t calalr; + + if ((id != 0) || (mask == NULL) || (timeptr == NULL)) { + return -EINVAL; + } + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + timalr = regs->RTC_TIMALR; + calalr = regs->RTC_CALALR; + + k_spin_unlock(&data->lock, key); + + *mask = rtc_sam_alarm_mask_from_timalr(timalr); + *mask |= rtc_sam_alarm_mask_from_calalr(calalr); + + rtc_sam_tm_from_timalr_calalr(timeptr, *mask, timalr, calalr); + return 0; +} + +static int rtc_sam_alarm_is_pending(const struct device *dev, uint16_t id) +{ + struct rtc_sam_data *data = dev->data; + const struct rtc_sam_config *config = dev->config; + Rtc *regs = config->regs; + + if (id != 0) { + return -EINVAL; + } + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if ((regs->RTC_SR & RTC_SR_ALARM) == 0) { + k_spin_unlock(&data->lock, key); + + return 0; + } + + regs->RTC_SCCR = RTC_SCCR_ALRCLR; + k_spin_unlock(&data->lock, key); + return 1; +} + +static int rtc_sam_alarm_set_callback(const struct device *dev, uint16_t id, + rtc_alarm_callback callback, void *user_data) +{ + struct rtc_sam_data *data = dev->data; + const struct rtc_sam_config *config = dev->config; + Rtc *regs = config->regs; + + if (id != 0) { + return -EINVAL; + } + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + irq_disable(config->irq_num); + data->alarm_callback = callback; + data->alarm_user_data = user_data; + + if (data->alarm_callback) { + regs->RTC_IER = RTC_IER_ALREN; + } else { + regs->RTC_IDR = RTC_IDR_ALRDIS; + } + + irq_enable(config->irq_num); + k_spin_unlock(&data->lock, key); + return 0; +} +#endif /* CONFIG_RTC_ALARM */ + +#ifdef CONFIG_RTC_UPDATE +static int rtc_sam_update_set_callback(const struct device *dev, rtc_update_callback callback, + void *user_data) +{ + struct rtc_sam_data *data = dev->data; + const struct rtc_sam_config *config = dev->config; + Rtc *regs = config->regs; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + irq_disable(config->irq_num); + + data->update_callback = callback; + data->update_user_data = user_data; + + if (data->update_callback) { + regs->RTC_IER = RTC_IER_SECEN; + } else { + regs->RTC_IDR = RTC_IDR_SECDIS; + } + + irq_enable(config->irq_num); + + k_spin_unlock(&data->lock, key); + + return 0; +} +#endif /* CONFIG_RTC_UPDATE */ + +#ifdef CONFIG_RTC_CALIBRATION +static int rtc_sam_set_calibration(const struct device *dev, int32_t calibration) +{ + struct rtc_sam_data *data = dev->data; + const struct rtc_sam_config *config = dev->config; + Rtc *regs = config->regs; + bool negative_calibration; + bool high_calibration; + uint32_t slow_clock_calibration; + uint32_t mr; + + if ((calibration < RTC_SAM_CALIBRATE_PPB_MIN) || + (calibration > RTC_SAM_CALIBRATE_PPB_MAX)) { + return -EINVAL; + } + + /* The value written to the register is absolute */ + if (calibration < 0) { + negative_calibration = true; + calibration = -calibration; + } else { + negative_calibration = false; + } + + /* + * Formula adapted from + * Atmel-11157-32-bit-Cortex-M4-Microcontroller-SAM4E16-SAM4E8_Datasheet.pdf + * section 15.6.2 + * + * Formula if RTC_MR_HIGHPPM is 0 + * + * RTC_MR_CORRECTION = (3906 / (20 * ppm)) - 1 + * + * Formula if RTC_MR_HIGHPPM is 1 + * + * RTC_MR_CORRECTION = (3906 / ppm) - 1 + * + * Since we are working with ppb, we adapt the formula by increasing the + * terms of the fraction by 1000, turning the ppm into ppb + * + * Adapted formula if RTC_MR_HIGHPPM is 0 + * + * RTC_MR_CORRECTION = (3906000 / (20 * ppb)) - 1 + * + * Adapted formula if RTC_MR_HIGHPPM is 1 + * + * RTC_MR_CORRECTION = (3906000 / ppb) - 1 + */ + if (calibration < RTC_SAM_CALIBRATE_PPB_QUANTA) { + high_calibration = false; + slow_clock_calibration = 0; + } else if (calibration < RTC_SAM_CALIBRATE_PPB_LOW_SCALE) { + high_calibration = false; + slow_clock_calibration = (uint32_t)((3906000 / (20 * calibration)) - 1); + } else { + high_calibration = true; + slow_clock_calibration = (uint32_t)((3906000 / calibration) - 1); + } + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + rtc_sam_disable_wp(); + + mr = regs->RTC_MR; + + if (negative_calibration == true) { + mr |= RTC_MR_NEGPPM; + } else { + mr &= ~RTC_MR_NEGPPM; + } + + mr &= ~RTC_MR_CORRECTION_Msk; + mr |= RTC_MR_CORRECTION(slow_clock_calibration); + + if (high_calibration == true) { + mr |= RTC_MR_HIGHPPM; + } else { + mr &= ~RTC_MR_HIGHPPM; + } + + regs->RTC_MR = mr; + + rtc_sam_enable_wp(); + + k_spin_unlock(&data->lock, key); + + return 0; +} + +static int rtc_sam_get_calibration(const struct device *dev, int32_t *calibration) +{ + const struct rtc_sam_config *config = dev->config; + Rtc *regs = config->regs; + + uint32_t mr; + int32_t correction; + + if (calibration == NULL) { + return -EINVAL; + } + + mr = regs->RTC_MR; + + correction = (int32_t)RTC_SAM_REG_GET_FIELD(mr, MR_CORRECTION); + + /* Formula documented in rtc_sam_set_calibration() */ + if (correction == 0) { + *calibration = 0; + } else if (mr & RTC_MR_HIGHPPM) { + *calibration = 3906000 / (correction + 1); + } else { + *calibration = 3906000 / ((correction + 1) * 20); + } + + if (mr & RTC_MR_NEGPPM) { + *calibration = -*calibration; + } + + return 0; +} +#endif /* CONFIG_RTC_CALIBRATION */ + +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 + .alarm_get_supported_fields = rtc_sam_alarm_get_supported_fields, + .alarm_set_time = rtc_sam_alarm_set_time, + .alarm_get_time = rtc_sam_alarm_get_time, + .alarm_is_pending = rtc_sam_alarm_is_pending, + .alarm_set_callback = rtc_sam_alarm_set_callback, +#endif /* CONFIG_RTC_ALARM */ +#ifdef CONFIG_RTC_UPDATE + .update_set_callback = rtc_sam_update_set_callback, +#endif /* CONFIG_RTC_UPDATE */ +#ifdef CONFIG_RTC_CALIBRATION + .set_calibration = rtc_sam_set_calibration, + .get_calibration = rtc_sam_get_calibration, +#endif /* CONFIG_RTC_CALIBRATION */ +}; + +static int rtc_sam_init(const struct device *dev) +{ + struct rtc_sam_data *data = dev->data; + const struct rtc_sam_config *config = dev->config; + Rtc *regs = config->regs; + + rtc_sam_disable_wp(); + regs->RTC_MR &= ~(RTC_MR_HRMOD | RTC_MR_PERSIAN); + regs->RTC_CR = 0; + rtc_sam_enable_wp(); + regs->RTC_IDR = (RTC_IDR_ACKDIS + | RTC_IDR_ALRDIS + | RTC_IDR_SECDIS + | RTC_IDR_TIMDIS + | RTC_IDR_CALDIS + | RTC_IDR_TDERRDIS); + + k_sem_init(&data->cr_sec_evt_sem, 0, 1); + k_sem_init(&data->cr_upd_ack_sem, 0, 1); + config->irq_init_fn_ptr(); + irq_enable(config->irq_num); + return 0; +} + +#define RTC_SAM_DEVICE(id) \ + static void rtc_sam_irq_init_##id(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), \ + rtc_sam_isr, DEVICE_DT_INST_GET(id), 0); \ + } \ + \ + static const struct rtc_sam_config rtc_sam_config_##id = { \ + .regs = (Rtc *)DT_INST_REG_ADDR(id), \ + .irq_num = DT_INST_IRQN(id), \ + .irq_init_fn_ptr = rtc_sam_irq_init_##id, \ + }; \ + \ + static struct rtc_sam_data rtc_sam_data_##id; \ + \ + DEVICE_DT_INST_DEFINE(id, rtc_sam_init, NULL, \ + &rtc_sam_data_##id, \ + &rtc_sam_config_##id, POST_KERNEL, \ + CONFIG_RTC_INIT_PRIORITY, \ + &rtc_sam_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(RTC_SAM_DEVICE); diff --git a/drivers/rtc/rtc_shell.c b/drivers/rtc/rtc_shell.c index 8dcaf46f875aabd..bc9980d20aff5e4 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 new file mode 100644 index 000000000000000..bfac974e874c041 --- /dev/null +++ b/drivers/rtc/rtc_smartbond.c @@ -0,0 +1,641 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(rtc_smartbond, CONFIG_RTC_LOG_LEVEL); + +#define DT_DRV_COMPAT renesas_smartbond_rtc + +#define SMARTBOND_IRQN DT_INST_IRQN(0) +#define SMARTBOND_IRQ_PRIO DT_INST_IRQ(0, priority) + +#define RTC_ALARMS_COUNT DT_PROP(DT_NODELABEL(rtc), alarms_count) + +#define TM_YEAR_REF 1900 +#define RTC_DIV_DENOM_1000 0 +#define RTC_DIV_DENOM_1024 1 + +#define RTC_SMARTBOND_SUPPORTED_ALARM_FIELDS \ + (RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR | \ + RTC_ALARM_TIME_MASK_MONTH | RTC_ALARM_TIME_MASK_MONTHDAY) + +#define RTC_TIME_REG_SET_FIELD(_field, _var, _val) \ + ((_var) = \ + ((_var) & ~(RTC_RTC_TIME_REG_RTC_TIME_ ## _field ## _T_Msk | \ + RTC_RTC_TIME_REG_RTC_TIME_ ## _field ## _U_Msk)) | \ + (((_val) << RTC_RTC_TIME_REG_RTC_TIME_ ## _field ## _U_Pos) & \ + (RTC_RTC_TIME_REG_RTC_TIME_ ## _field ## _T_Msk | \ + RTC_RTC_TIME_REG_RTC_TIME_ ## _field ## _U_Msk))) + +#define RTC_CALENDAR_REG_SET_FIELD(_field, _var, _val) \ + ((_var) = \ + ((_var) & ~(RTC_RTC_CALENDAR_REG_RTC_CAL_ ## _field ## _T_Msk | \ + RTC_RTC_CALENDAR_REG_RTC_CAL_ ## _field ## _U_Msk)) | \ + (((_val) << RTC_RTC_CALENDAR_REG_RTC_CAL_ ## _field ## _U_Pos) & \ + (RTC_RTC_CALENDAR_REG_RTC_CAL_ ## _field ## _T_Msk | \ + RTC_RTC_CALENDAR_REG_RTC_CAL_ ## _field ## _U_Msk))) + +#define RTC_CALENDAR_ALARM_REG_SET_FIELD(_field, _var, _val) \ + ((_var) = \ + ((_var) & ~(RTC_RTC_CALENDAR_ALARM_REG_RTC_CAL_ ## _field ## _T_Msk | \ + RTC_RTC_CALENDAR_ALARM_REG_RTC_CAL_ ## _field ## _U_Msk)) | \ + (((_val) << RTC_RTC_CALENDAR_ALARM_REG_RTC_CAL_ ## _field ## _U_Pos) & \ + (RTC_RTC_CALENDAR_ALARM_REG_RTC_CAL_ ## _field ## _T_Msk | \ + RTC_RTC_CALENDAR_ALARM_REG_RTC_CAL_ ## _field ## _U_Msk))) + +#define RTC_TIME_ALARM_REG_SET_FIELD(_field, _var, _val) \ + ((_var) = \ + ((_var) & ~(RTC_RTC_TIME_ALARM_REG_RTC_TIME_ ## _field ## _T_Msk | \ + RTC_RTC_TIME_ALARM_REG_RTC_TIME_ ## _field ## _U_Msk)) | \ + (((_val) << RTC_RTC_TIME_ALARM_REG_RTC_TIME_ ## _field ## _U_Pos) & \ + (RTC_RTC_TIME_ALARM_REG_RTC_TIME_ ## _field ## _T_Msk | \ + RTC_RTC_TIME_ALARM_REG_RTC_TIME_ ## _field ## _U_Msk))) + +#define RTC_TIME_REG_GET_FIELD(_field, _var) \ + (((_var) & (RTC_RTC_TIME_REG_RTC_TIME_ ## _field ## _T_Msk | \ + RTC_RTC_TIME_REG_RTC_TIME_ ## _field ## _U_Msk)) >> \ + RTC_RTC_TIME_REG_RTC_TIME_ ## _field ## _U_Pos) + +#define RTC_CALENDAR_REG_GET_FIELD(_field, _var) \ + (((_var) & (RTC_RTC_CALENDAR_REG_RTC_CAL_ ## _field ## _T_Msk | \ + RTC_RTC_CALENDAR_REG_RTC_CAL_ ## _field ## _U_Msk)) >> \ + RTC_RTC_CALENDAR_REG_RTC_CAL_ ## _field ## _U_Pos) + +#define RTC_CALENDAR_ALARM_REG_GET_FIELD(_field, _var) \ + (((_var) & (RTC_RTC_CALENDAR_ALARM_REG_RTC_CAL_ ## _field ## _T_Msk | \ + RTC_RTC_CALENDAR_ALARM_REG_RTC_CAL_ ## _field ## _U_Msk)) >> \ + RTC_RTC_CALENDAR_ALARM_REG_RTC_CAL_ ## _field ## _U_Pos) + +#define RTC_TIME_ALARM_REG_GET_FIELD(_field, _var) \ + (((_var) & (RTC_RTC_TIME_ALARM_REG_RTC_TIME_ ## _field ## _T_Msk | \ + RTC_RTC_TIME_ALARM_REG_RTC_TIME_ ## _field ## _U_Msk)) >> \ + RTC_RTC_TIME_ALARM_REG_RTC_TIME_ ## _field ## _U_Pos) + +#define CLK_RTCDIV_REG_SET_FIELD(_field, _var, _val) \ + ((_var) = \ + ((_var) & ~CRG_TOP_CLK_RTCDIV_REG_RTC_DIV_ ## _field ## _Msk) | \ + (((_val) << CRG_TOP_CLK_RTCDIV_REG_RTC_DIV_ ## _field ## _Pos) & \ + CRG_TOP_CLK_RTCDIV_REG_RTC_DIV_ ## _field ## _Msk)) + +struct rtc_smartbond_data { + struct k_mutex lock; + bool is_rtc_configured; +#if defined(CONFIG_RTC_ALARM) + volatile bool is_alarm_pending; + rtc_alarm_callback alarm_cb; + void *alarm_user_data; +#endif +#if defined(CONFIG_RTC_UPDATE) + rtc_update_callback update_cb; + void *update_user_data; +#endif +}; + +#if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_UPDATE) +static void smartbond_rtc_isr(const struct device *dev) +{ + struct rtc_smartbond_data *data = dev->data; + /* Exercise which events asserted the RTC IRQ line. Register is cleared upon read. */ + uint32_t rtc_event_flags_reg = RTC->RTC_EVENT_FLAGS_REG; + /* RTC_EVENT_FLASH_REG will be updated regardless of the interrupt mask. */ + uint32_t rtc_interrupt_mask_reg = RTC->RTC_INTERRUPT_MASK_REG; + +#if defined(CONFIG_RTC_ALARM) + if ((rtc_event_flags_reg & RTC_RTC_EVENT_FLAGS_REG_RTC_EVENT_ALRM_Msk) && + !(rtc_interrupt_mask_reg & RTC_RTC_INTERRUPT_MASK_REG_RTC_ALRM_INT_MSK_Msk)) { + if (data->alarm_cb) { + data->alarm_cb(dev, 0, data->alarm_user_data); + data->is_alarm_pending = false; + } else { + data->is_alarm_pending = true; + } + } +#endif + +#if defined(CONFIG_RTC_UPDATE) + if ((rtc_event_flags_reg & RTC_RTC_EVENT_FLAGS_REG_RTC_EVENT_SEC_Msk) && + !(rtc_interrupt_mask_reg & RTC_RTC_INTERRUPT_MASK_REG_RTC_SEC_INT_MSK_Msk)) { + if (data->update_cb) { + data->update_cb(dev, data->update_user_data); + } + } +#endif +} +#endif + +static inline void rtc_smartbond_set_status(bool status) +{ + if (status) { + CRG_TOP->CLK_RTCDIV_REG |= CRG_TOP_CLK_RTCDIV_REG_RTC_DIV_ENABLE_Msk; + RTC->RTC_CONTROL_REG = 0; + } else { + RTC->RTC_CONTROL_REG = (RTC_RTC_CONTROL_REG_RTC_CAL_DISABLE_Msk | + RTC_RTC_CONTROL_REG_RTC_TIME_DISABLE_Msk); + CRG_TOP->CLK_RTCDIV_REG &= ~CRG_TOP_CLK_RTCDIV_REG_RTC_DIV_ENABLE_Msk; + } +} + +static uint32_t rtc_time_to_bcd(const struct rtc_time *timeptr) +{ + uint32_t rtc_time_reg = 0; + + RTC_TIME_REG_SET_FIELD(S, rtc_time_reg, bin2bcd(timeptr->tm_sec)); /*[0, 59]*/ + RTC_TIME_REG_SET_FIELD(M, rtc_time_reg, bin2bcd(timeptr->tm_min)); /*[0, 59]*/ + RTC_TIME_REG_SET_FIELD(HR, rtc_time_reg, bin2bcd(timeptr->tm_hour)); /*[0, 23]*/ + + return rtc_time_reg; +} + +static uint32_t rtc_calendar_to_bcd(const struct rtc_time *timeptr) +{ + uint32_t rtc_calendar_reg = 0; + + RTC_CALENDAR_REG_SET_FIELD(D, rtc_calendar_reg, bin2bcd(timeptr->tm_mday)); /*[1, 31]*/ + RTC_CALENDAR_REG_SET_FIELD(Y, rtc_calendar_reg, + bin2bcd((timeptr->tm_year + TM_YEAR_REF) % 100)); /*[year - 1900]*/ + RTC_CALENDAR_REG_SET_FIELD(C, rtc_calendar_reg, + bin2bcd((timeptr->tm_year + TM_YEAR_REF) / 100)); + RTC_CALENDAR_REG_SET_FIELD(M, rtc_calendar_reg, bin2bcd(timeptr->tm_mon + 1)); /*[0, 11]*/ + + if (timeptr->tm_wday != -1) { + rtc_calendar_reg |= ((timeptr->tm_wday + 1) & + RTC_RTC_CALENDAR_REG_RTC_DAY_Msk); /*[0, 6]*/ + } + + return rtc_calendar_reg; +} + +static void bcd_to_rtc_time(struct rtc_time *timeptr) +{ + uint32_t rtc_time_reg = RTC->RTC_TIME_REG; + + timeptr->tm_sec = bcd2bin(RTC_TIME_REG_GET_FIELD(S, rtc_time_reg)); + timeptr->tm_min = bcd2bin(RTC_TIME_REG_GET_FIELD(M, rtc_time_reg)); + timeptr->tm_hour = bcd2bin(RTC_TIME_REG_GET_FIELD(HR, rtc_time_reg)); + + timeptr->tm_nsec = 0; /*Unknown*/ +} + +static void bcd_to_rtc_calendar(struct rtc_time *timeptr) +{ + uint32_t rtc_calendar_reg = RTC->RTC_CALENDAR_REG; + + timeptr->tm_mday = bcd2bin(RTC_CALENDAR_REG_GET_FIELD(D, rtc_calendar_reg)); + timeptr->tm_mon = bcd2bin(RTC_CALENDAR_REG_GET_FIELD(M, rtc_calendar_reg)) - 1; + timeptr->tm_year = bcd2bin(RTC_CALENDAR_REG_GET_FIELD(Y, rtc_calendar_reg)) + + (bcd2bin(RTC_CALENDAR_REG_GET_FIELD(C, rtc_calendar_reg)) * 100) - TM_YEAR_REF; + timeptr->tm_wday = (rtc_calendar_reg & RTC_RTC_CALENDAR_REG_RTC_DAY_Msk) - 1; + + timeptr->tm_yday = timeptr->tm_isdst = -1; /*Unknown*/ +} + +static int rtc_smartbond_set_time(const struct device *dev, const struct rtc_time *timeptr) +{ + struct rtc_smartbond_data *data = dev->data; + int ret = 0; + uint32_t rtc_time_reg, rtc_calendar_reg, rtc_status_reg; + + if (timeptr == NULL) { + LOG_ERR("No pointer is provided to set time"); + return -EINVAL; + } + + if (timeptr->tm_year + TM_YEAR_REF < TM_YEAR_REF) { + LOG_ERR("RTC time exceeds HW capabilities"); + return -EINVAL; + } + + if ((timeptr->tm_yday != -1) || (timeptr->tm_isdst != -1) || (timeptr->tm_nsec != 0)) { + LOG_WRN("Unsupported RTC sub-values"); + } + + k_mutex_lock(&data->lock, K_FOREVER); + rtc_smartbond_set_status(false); + + /* Store current counter values as it might happen that the requested time is not valid */ + rtc_time_reg = RTC->RTC_TIME_REG; + rtc_calendar_reg = RTC->RTC_CALENDAR_REG; + + RTC->RTC_TIME_REG = rtc_time_to_bcd(timeptr); + RTC->RTC_CALENDAR_REG = rtc_calendar_to_bcd(timeptr); + + /* Check if the new values were valid, otherwise reset back to the previous ones. */ + rtc_status_reg = RTC->RTC_STATUS_REG; + if (!(rtc_status_reg & RTC_RTC_STATUS_REG_RTC_VALID_CAL_Msk) || + !(rtc_status_reg & RTC_RTC_STATUS_REG_RTC_VALID_TIME_Msk)) { + RTC->RTC_TIME_REG = rtc_time_reg; + RTC->RTC_CALENDAR_REG = rtc_calendar_reg; + ret = -EINVAL; + } + + /* Mark the very first valid RTC configuration; used to check if RTC contains valid data. */ + if (!data->is_rtc_configured && (ret == 0)) { + data->is_rtc_configured = true; + } + + /* It might happen that the very first time RTC is not configured correctly; do not care. */ + rtc_smartbond_set_status(true); + k_mutex_unlock(&data->lock); + + return ret; +} + +static int rtc_smartbond_get_time(const struct device *dev, struct rtc_time *timeptr) +{ + struct rtc_smartbond_data *data = dev->data; + + if (timeptr == NULL) { + LOG_ERR("No pointer is provided to store the requested time"); + return -EINVAL; + } + + if (!data->is_rtc_configured) { + LOG_ERR("RTC is not initialized yet"); + return -ENODATA; + } + + k_mutex_lock(&data->lock, K_FOREVER); + /* Stop RTC counters to obtain coherent data. */ + rtc_smartbond_set_status(false); + + bcd_to_rtc_time(timeptr); + bcd_to_rtc_calendar(timeptr); + + rtc_smartbond_set_status(true); + k_mutex_unlock(&data->lock); + + return 0; +} + +#if defined(CONFIG_RTC_ALARM) +BUILD_ASSERT(RTC_ALARMS_COUNT, "At least one alarm event should be supported"); + +/* Define a valid calendar value as a zero sub-field is not valid for the alarm calendar value */ +static uint32_t alarm_calendar_to_bcd(const struct rtc_time *timeptr, uint16_t mask) +{ + uint32_t rtc_calendar_alarm_reg = 0x0108; + + if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) { + RTC_CALENDAR_ALARM_REG_SET_FIELD(D, rtc_calendar_alarm_reg, + bin2bcd(timeptr->tm_mday)); + } + + if (mask & RTC_ALARM_TIME_MASK_MONTH) { + RTC_CALENDAR_ALARM_REG_SET_FIELD(M, rtc_calendar_alarm_reg, + bin2bcd(timeptr->tm_mon + 1)); + } + + return rtc_calendar_alarm_reg; +} + +/* No need to parse the alarm mask as a zero sub-field is valid for the alarm time counter. */ +static inline uint32_t alarm_time_to_bcd(const struct rtc_time *timeptr) +{ + uint32_t rtc_time_alarm_reg = 0; + + RTC_TIME_ALARM_REG_SET_FIELD(S, rtc_time_alarm_reg, bin2bcd(timeptr->tm_sec)); /*[0, 59]*/ + RTC_TIME_ALARM_REG_SET_FIELD(M, rtc_time_alarm_reg, bin2bcd(timeptr->tm_min)); /*[0, 59]*/ + RTC_TIME_ALARM_REG_SET_FIELD(HR, rtc_time_alarm_reg, bin2bcd(timeptr->tm_hour)); /*[0, 23]*/ + + return rtc_time_alarm_reg; +} + +static void bcd_to_alarm_calendar(struct rtc_time *timeptr) +{ + uint32_t rtc_calendar_alarm_reg = RTC->RTC_CALENDAR_ALARM_REG; + + timeptr->tm_mday = bcd2bin(RTC_CALENDAR_ALARM_REG_GET_FIELD(D, rtc_calendar_alarm_reg)); + timeptr->tm_mon = bcd2bin(RTC_CALENDAR_ALARM_REG_GET_FIELD(M, rtc_calendar_alarm_reg)) - 1; + + timeptr->tm_yday = timeptr->tm_wday = timeptr->tm_isdst = timeptr->tm_year = -1; +} + +static void bcd_to_alarm_time(struct rtc_time *timeptr) +{ + uint32_t rtc_time_alarm_reg = RTC->RTC_TIME_ALARM_REG; + + timeptr->tm_sec = bcd2bin(RTC_TIME_ALARM_REG_GET_FIELD(S, rtc_time_alarm_reg)); + timeptr->tm_min = bcd2bin(RTC_TIME_ALARM_REG_GET_FIELD(M, rtc_time_alarm_reg)); + timeptr->tm_hour = bcd2bin(RTC_TIME_ALARM_REG_GET_FIELD(HR, rtc_time_alarm_reg)); + + timeptr->tm_nsec = 0; +} + +static uint32_t tm_to_rtc_alarm_mask(uint16_t mask) +{ + uint32_t rtc_alarm_enable_reg = 0; + + if (mask & RTC_ALARM_TIME_MASK_SECOND) { + rtc_alarm_enable_reg |= RTC_RTC_ALARM_ENABLE_REG_RTC_ALARM_SEC_EN_Msk; + } + if (mask & RTC_ALARM_TIME_MASK_MINUTE) { + rtc_alarm_enable_reg |= RTC_RTC_ALARM_ENABLE_REG_RTC_ALARM_MIN_EN_Msk; + } + if (mask & RTC_ALARM_TIME_MASK_HOUR) { + rtc_alarm_enable_reg |= RTC_RTC_ALARM_ENABLE_REG_RTC_ALARM_HOUR_EN_Msk; + } + if (mask & RTC_ALARM_TIME_MASK_MONTH) { + rtc_alarm_enable_reg |= RTC_RTC_ALARM_ENABLE_REG_RTC_ALARM_MNTH_EN_Msk; + } + if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) { + rtc_alarm_enable_reg |= RTC_RTC_ALARM_ENABLE_REG_RTC_ALARM_DATE_EN_Msk; + } + + return rtc_alarm_enable_reg; +} + +static uint16_t rtc_to_tm_alarm_mask(uint32_t rtc_alarm_enable_reg) +{ + uint16_t mask = 0; + + if (rtc_alarm_enable_reg & RTC_RTC_ALARM_ENABLE_REG_RTC_ALARM_SEC_EN_Msk) { + mask |= RTC_ALARM_TIME_MASK_SECOND; + } + if (rtc_alarm_enable_reg & RTC_RTC_ALARM_ENABLE_REG_RTC_ALARM_MIN_EN_Msk) { + mask |= RTC_ALARM_TIME_MASK_MINUTE; + } + if (rtc_alarm_enable_reg & RTC_RTC_ALARM_ENABLE_REG_RTC_ALARM_HOUR_EN_Msk) { + mask |= RTC_ALARM_TIME_MASK_HOUR; + } + if (rtc_alarm_enable_reg & RTC_RTC_ALARM_ENABLE_REG_RTC_ALARM_MNTH_EN_Msk) { + mask |= RTC_ALARM_TIME_MASK_MONTH; + } + if (rtc_alarm_enable_reg & RTC_RTC_ALARM_ENABLE_REG_RTC_ALARM_DATE_EN_Msk) { + mask |= RTC_ALARM_TIME_MASK_MONTHDAY; + } + + return mask; +} + +static int rtc_smartbond_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask, + const struct rtc_time *timeptr) +{ + int ret = 0; + struct rtc_smartbond_data *data = dev->data; + uint32_t rtc_time_alarm_reg; + uint32_t rtc_calendar_alarm_reg; + uint32_t rtc_alarm_enable_reg; + uint32_t rtc_status_reg; + + if (id >= RTC_ALARMS_COUNT) { + LOG_ERR("Alarm id is out of range"); + return -EINVAL; + } + + if (mask & ~RTC_SMARTBOND_SUPPORTED_ALARM_FIELDS) { + LOG_ERR("Invalid alarm mask"); + return -EINVAL; + } + + if ((timeptr == NULL) && (mask != 0)) { + LOG_ERR("No pointer is provided to set alarm"); + return -EINVAL; + } + + if (!data->is_rtc_configured) { + LOG_WRN("RTC is not initialized yet"); + } + + k_mutex_lock(&data->lock, K_FOREVER); + + rtc_alarm_enable_reg = RTC->RTC_ALARM_ENABLE_REG; + + /* Disable alarm to obtain coherency and/or when the alarm mask is empty */ + RTC->RTC_ALARM_ENABLE_REG = 0; + RTC->RTC_INTERRUPT_DISABLE_REG = RTC_RTC_INTERRUPT_DISABLE_REG_RTC_ALRM_INT_DIS_Msk; + + if (mask) { + /* Store current counter values as it might happen requested alrm is not valid */ + rtc_time_alarm_reg = RTC->RTC_TIME_ALARM_REG; + rtc_calendar_alarm_reg = RTC->RTC_CALENDAR_ALARM_REG; + + RTC->RTC_TIME_ALARM_REG = alarm_time_to_bcd(timeptr); + RTC->RTC_CALENDAR_ALARM_REG = alarm_calendar_to_bcd(timeptr, mask); + + rtc_status_reg = RTC->RTC_STATUS_REG; + if (!(rtc_status_reg & RTC_RTC_STATUS_REG_RTC_VALID_CAL_ALM_Msk) || + !(rtc_status_reg & RTC_RTC_STATUS_REG_RTC_VALID_TIME_ALM_Msk)) { + RTC->RTC_TIME_ALARM_REG = rtc_time_alarm_reg; + RTC->RTC_CALENDAR_ALARM_REG = rtc_calendar_alarm_reg; + RTC->RTC_ALARM_ENABLE_REG = rtc_alarm_enable_reg; + ret = -EINVAL; + } else { + RTC->RTC_ALARM_ENABLE_REG = tm_to_rtc_alarm_mask(mask); + } + + RTC->RTC_INTERRUPT_ENABLE_REG = RTC_RTC_INTERRUPT_ENABLE_REG_RTC_ALRM_INT_EN_Msk; + } + + k_mutex_unlock(&data->lock); + + return ret; +} + +static int rtc_smartbond_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask, + struct rtc_time *timeptr) +{ + struct rtc_smartbond_data *data = dev->data; + + if (id >= RTC_ALARMS_COUNT) { + LOG_ERR("Alarm id is out of range"); + return -EINVAL; + } + + if ((timeptr == NULL) || (mask == NULL)) { + LOG_ERR("No pointer is provided to store the requested alarm time/mask"); + return -EINVAL; + } + + if (!data->is_rtc_configured) { + LOG_WRN("RTC is not initialized yet"); + } + + k_mutex_lock(&data->lock, K_FOREVER); + + bcd_to_alarm_calendar(timeptr); + bcd_to_alarm_time(timeptr); + *mask = rtc_to_tm_alarm_mask(RTC->RTC_ALARM_ENABLE_REG); + + k_mutex_unlock(&data->lock); + + return 0; +} + +static int rtc_smartbond_alarm_is_pending(const struct device *dev, uint16_t id) +{ + unsigned int key; + int status; + struct rtc_smartbond_data *data = dev->data; + + if (id >= RTC_ALARMS_COUNT) { + LOG_ERR("Alarm id is out of range"); + return -EINVAL; + } + + /* Globally disable interrupts as the status flag can be updated within ISR */ + key = DA1469X_IRQ_DISABLE(); + status = data->is_alarm_pending; + /* After reading, the alarm status should be cleared. */ + data->is_alarm_pending = 0; + DA1469X_IRQ_ENABLE(key); + + return status; +} + +static int rtc_smartbond_alarm_set_callback(const struct device *dev, uint16_t id, + rtc_alarm_callback callback, void *user_data) +{ + struct rtc_smartbond_data *data = dev->data; + + if (id >= RTC_ALARMS_COUNT) { + LOG_ERR("Alarm id is out of range"); + return -EINVAL; + } + + k_mutex_lock(&data->lock, K_FOREVER); + + data->alarm_cb = callback; + data->alarm_user_data = user_data; + + k_mutex_unlock(&data->lock); + + return 0; +} + +static int rtc_smartbond_alarm_get_supported_fields(const struct device *dev, uint16_t id, + uint16_t *mask) +{ + if (id >= RTC_ALARMS_COUNT) { + LOG_ERR("Alarm id is out of range"); + return -EINVAL; + } + + if (mask == NULL) { + LOG_ERR("Pointer to store the mask value is missed"); + return -EINVAL; + } + + *mask = (uint16_t)RTC_SMARTBOND_SUPPORTED_ALARM_FIELDS; + + return 0; +} +#endif + +#if defined(CONFIG_RTC_UPDATE) +static int rtc_smartbond_update_set_callback(const struct device *dev, rtc_update_callback callback, + void *user_data) +{ + struct rtc_smartbond_data *data = dev->data; + + k_mutex_lock(&data->lock, K_FOREVER); + + data->update_cb = callback; + data->update_user_data = user_data; + + if (data->update_cb) { + /* Enable asserting the RTC interrupt line when the second counter rolls over. */ + RTC->RTC_INTERRUPT_ENABLE_REG = RTC_RTC_INTERRUPT_ENABLE_REG_RTC_SEC_INT_EN_Msk; + } else { + RTC->RTC_INTERRUPT_DISABLE_REG = RTC_RTC_INTERRUPT_DISABLE_REG_RTC_SEC_INT_DIS_Msk; + } + + k_mutex_unlock(&data->lock); + + return 0; +} +#endif + +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) + .alarm_get_time = rtc_smartbond_alarm_get_time, + .alarm_set_time = rtc_smartbond_alarm_set_time, + .alarm_is_pending = rtc_smartbond_alarm_is_pending, + .alarm_set_callback = rtc_smartbond_alarm_set_callback, + .alarm_get_supported_fields = rtc_smartbond_alarm_get_supported_fields, +#endif +#if defined(CONFIG_RTC_UPDATE) + .update_set_callback = rtc_smartbond_update_set_callback, +#endif +}; + +static void rtc_smartbond_100HZ_clock_cfg(void) +{ + const struct device * const dev = DEVICE_DT_GET(DT_NODELABEL(osc)); + uint32_t lp_clk_rate; + uint32_t clk_rtcdiv_reg; + + if (!device_is_ready(dev)) { + __ASSERT_MSG_INFO("Clock device is not ready"); + } + + if (clock_control_get_rate(dev, (clock_control_subsys_t)SMARTBOND_CLK_LP_CLK, + &lp_clk_rate) < 0) { + __ASSERT_MSG_INFO("Cannot extract LP clock rate"); + } + + clk_rtcdiv_reg = CRG_TOP->CLK_RTCDIV_REG; + CLK_RTCDIV_REG_SET_FIELD(DENOM, clk_rtcdiv_reg, RTC_DIV_DENOM_1000); + CLK_RTCDIV_REG_SET_FIELD(INT, clk_rtcdiv_reg, lp_clk_rate / 100); + CLK_RTCDIV_REG_SET_FIELD(FRAC, clk_rtcdiv_reg, (lp_clk_rate % 100) * 10); + CRG_TOP->CLK_RTCDIV_REG = clk_rtcdiv_reg; +} + +static int rtc_smartbond_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* Wakeup device from RTC events (alarm/roll over) */ +#if CONFIG_PM + bool is_xtal32m_enabled = DT_NODE_HAS_STATUS(DT_NODELABEL(xtal32m), okay); + int pdc_idx = da1469x_pdc_add(MCU_PDC_TRIGGER_RTC_ALARM, MCU_PDC_MASTER_M33, + is_xtal32m_enabled ? MCU_PDC_EN_XTAL : 0); + + __ASSERT(pdc_idx >= 0, "Failed to add RTC PDC entry"); + da1469x_pdc_set(pdc_idx); + da1469x_pdc_ack(pdc_idx); +#endif + + rtc_smartbond_100HZ_clock_cfg(); + + /* Timer and calendar counters will not reset after SW reset */ + RTC->RTC_KEEP_RTC_REG |= RTC_RTC_KEEP_RTC_REG_RTC_KEEP_Msk; + +#if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_UPDATE) + IRQ_CONNECT(SMARTBOND_IRQN, SMARTBOND_IRQ_PRIO, smartbond_rtc_isr, + DEVICE_DT_INST_GET(0), 0); + irq_enable(SMARTBOND_IRQN); +#endif + + return 0; +} + +#define SMARTBOND_RTC_INIT(inst) \ + BUILD_ASSERT((inst) == 0, "multiple instances are not supported"); \ + \ + static struct rtc_smartbond_data rtc_smartbond_data_ ## inst; \ + \ + DEVICE_DT_INST_DEFINE(0, rtc_smartbond_init, NULL, \ + &rtc_smartbond_data_ ## inst, NULL, \ + POST_KERNEL, \ + CONFIG_RTC_INIT_PRIORITY, \ + &rtc_smartbond_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(SMARTBOND_RTC_INIT) diff --git a/drivers/sdhc/CMakeLists.txt b/drivers/sdhc/CMakeLists.txt index a43e3f54806f9ea..2675589bfc9023f 100644 --- a/drivers/sdhc/CMakeLists.txt +++ b/drivers/sdhc/CMakeLists.txt @@ -8,4 +8,6 @@ zephyr_library_sources_ifdef(CONFIG_SPI_SDHC sdhc_spi.c) 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 69a942238e4aaf8..13b63cfcc9c2380 100644 --- a/drivers/sdhc/Kconfig +++ b/drivers/sdhc/Kconfig @@ -8,11 +8,13 @@ menuconfig SDHC if SDHC +source "drivers/sdhc/Kconfig.ifx_cat1" source "drivers/sdhc/Kconfig.imx" 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.ifx_cat1 b/drivers/sdhc/Kconfig.ifx_cat1 new file mode 100644 index 000000000000000..13dde4cf18fbd07 --- /dev/null +++ b/drivers/sdhc/Kconfig.ifx_cat1 @@ -0,0 +1,22 @@ +# Infineon CAT1 SDHC configuration options + +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +config SDHC_INFINEON_CAT1 + bool "Infineon CAT1 SDHC driver" + default y + depends on DT_HAS_INFINEON_CAT1_SDHC_SDIO_ENABLED + select USE_INFINEON_SDIO + select SDHC_SUPPORTS_NATIVE_MODE + help + This option enables the SDHC driver for Infineon CAT1 family. + +if SDHC_INFINEON_CAT1 + +config SDHC_INIT_PRIORITY + default 70 + +endif diff --git a/drivers/sdhc/Kconfig.sdhc_cdns b/drivers/sdhc/Kconfig.sdhc_cdns new file mode 100644 index 000000000000000..3558763fbf44459 --- /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/ifx_cat1_sdio.c b/drivers/sdhc/ifx_cat1_sdio.c new file mode 100644 index 000000000000000..d298e1d7b6b9da5 --- /dev/null +++ b/drivers/sdhc/ifx_cat1_sdio.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/** + * @brief SDIO driver for Infineon CAT1 MCU family. + * + * This driver support only SDIO protocol of the SD interface for general + * I/O functions. + * + * Refer to the SD Specifications Part 1 SDIO Specifications Version 4.10 for more + * information on the SDIO protocol and specifications. + * + * Features + * - Supports 4-bit interface + * - Supports Ultra High Speed (UHS-I) mode + * - Supports Default Speed (DS), High Speed (HS), SDR12, SDR25 and SDR50 speed modes + * - Supports SDIO card interrupts in both 1-bit SD and 4-bit SD modes + * - Supports Standard capacity (SDSC), High capacity (SDHC) and + * Extended capacity (SDXC) memory + * + * Note (limitations): + * - current version of ifx_cat1_sdio supports only following set of commands: + * > GO_IDLE_STATE (CMD0) + * > SEND_RELATIVE_ADDR (CMD3) + * > IO_SEND_OP_COND (CMD5) + * > SELECT_CARD (CMD7) + * > VOLTAGE_SWITCH (CMD11) + * > GO_INACTIVE_STATE (CMD15) + * > IO_RW_DIRECT (CMD52) + * > IO_RW_EXTENDED (CMD53) + */ + +#define DT_DRV_COMPAT infineon_cat1_sdhc_sdio + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_REGISTER(ifx_cat1_sdio, CONFIG_SDHC_LOG_LEVEL); + +#include + +#define IFX_CAT1_SDIO_F_MIN (SDMMC_CLOCK_400KHZ) +#define IFX_CAT1_SDIO_F_MAX (SD_CLOCK_50MHZ) + +struct ifx_cat1_sdio_config { + const struct pinctrl_dev_config *pincfg; + SDHC_Type *reg_addr; + uint8_t irq_priority; +}; + +struct ifx_cat1_sdio_data { + cyhal_sdio_t sdio_obj; + cyhal_resource_inst_t hw_resource; + cyhal_sdio_configurator_t cyhal_sdio_config; + enum sdhc_clock_speed clock_speed; + enum sdhc_bus_width bus_width; + + void *sdio_cb_user_data; + sdhc_interrupt_cb_t sdio_cb; +}; + +static uint32_t sdio_rca; +static const cy_stc_sd_host_init_config_t host_config = {false, CY_SD_HOST_DMA_ADMA2, false}; +static cy_en_sd_host_card_capacity_t sd_host_card_capacity = CY_SD_HOST_SDSC; +static cy_en_sd_host_card_type_t sd_host_card_type = CY_SD_HOST_NOT_EMMC; +static cy_stc_sd_host_sd_card_config_t sd_host_sd_card_config = { + .lowVoltageSignaling = false, + .busWidth = CY_SD_HOST_BUS_WIDTH_4_BIT, + .cardType = &sd_host_card_type, + .rca = &sdio_rca, + .cardCapacity = &sd_host_card_capacity, +}; + +/* List of available SDHC instances */ +static SDHC_Type *const IFX_CAT1_SDHC_BASE_ADDRESSES[CY_IP_MXSDHC_INSTANCES] = { +#ifdef SDHC0 + SDHC0, +#endif /* ifdef SDHC0 */ + +#ifdef SDHC1 + SDHC1, +#endif /* ifdef SDHC1 */ +}; + +static int32_t _get_hw_block_num(SDHC_Type *reg_addr) +{ + uint32_t i; + + for (i = 0u; i < CY_IP_MXSDHC_INSTANCES; i++) { + if (IFX_CAT1_SDHC_BASE_ADDRESSES[i] == reg_addr) { + return i; + } + } + + return -EINVAL; +} + +static int ifx_cat1_sdio_reset(const struct device *dev) +{ + struct ifx_cat1_sdio_data *dev_data = dev->data; + + cyhal_sdhc_software_reset((cyhal_sdhc_t *)&dev_data->sdio_obj); + + return 0; +} + +static int ifx_cat1_sdio_set_io(const struct device *dev, struct sdhc_io *ios) +{ + cy_rslt_t ret; + struct ifx_cat1_sdio_data *dev_data = dev->data; + cyhal_sdio_cfg_t config = {.frequencyhal_hz = ios->clock}; + + /* NOTE: Set bus width, set card power, set host signal voltage, + * set I/O timing does not support in current version of driver + */ + + /* Set host clock */ + if ((dev_data->clock_speed != ios->clock) && (ios->clock != 0)) { + + if ((ios->clock > IFX_CAT1_SDIO_F_MAX) || (ios->clock < IFX_CAT1_SDIO_F_MIN)) { + return -EINVAL; + } + + ret = cyhal_sdio_configure(&dev_data->sdio_obj, &config); + if (ret != CY_RSLT_SUCCESS) { + return -ENOTSUP; + } + + dev_data->clock_speed = ios->clock; + } + + return 0; +} + +static int ifx_cat1_sdio_card_busy(const struct device *dev) +{ + struct ifx_cat1_sdio_data *dev_data = dev->data; + + return cyhal_sdio_is_busy(&dev_data->sdio_obj) ? 1 : 0; +} + +static int ifx_cat1_sdio_request(const struct device *dev, struct sdhc_command *cmd, + struct sdhc_data *data) +{ + struct ifx_cat1_sdio_data *dev_data = dev->data; + int ret; + + switch (cmd->opcode) { + case CYHAL_SDIO_CMD_GO_IDLE_STATE: + case CYHAL_SDIO_CMD_SEND_RELATIVE_ADDR: + case CYHAL_SDIO_CMD_IO_SEND_OP_COND: + case CYHAL_SDIO_CMD_SELECT_CARD: + case CYHAL_SDIO_CMD_VOLTAGE_SWITCH: + case CYHAL_SDIO_CMD_GO_INACTIVE_STATE: + case CYHAL_SDIO_CMD_IO_RW_DIRECT: + ret = cyhal_sdio_send_cmd(&dev_data->sdio_obj, CYHAL_SDIO_XFER_TYPE_READ, + cmd->opcode, cmd->arg, cmd->response); + if (ret != CY_RSLT_SUCCESS) { + LOG_ERR("cyhal_sdio_send_cmd failed ret = %d \r\n", ret); + } + break; + + case CYHAL_SDIO_CMD_IO_RW_EXTENDED: + cyhal_sdio_transfer_type_t direction; + + direction = (cmd->arg & BIT(SDIO_CMD_ARG_RW_SHIFT)) ? CYHAL_SDIO_XFER_TYPE_WRITE + : CYHAL_SDIO_XFER_TYPE_READ; + + ret = cyhal_sdio_bulk_transfer(&dev_data->sdio_obj, direction, cmd->arg, data->data, + data->blocks * data->block_size, cmd->response); + + if (ret != CY_RSLT_SUCCESS) { + LOG_ERR("cyhal_sdio_bulk_transfer failed ret = %d \r\n", ret); + } + break; + + default: + ret = -ENOTSUP; + } + + return ret; +} + +static int ifx_cat1_sdio_get_card_present(const struct device *dev) +{ + return 1; +} + +static int ifx_cat1_sdio_get_host_props(const struct device *dev, struct sdhc_host_props *props) +{ + memset(props, 0, sizeof(*props)); + props->f_max = IFX_CAT1_SDIO_F_MAX; + props->f_min = IFX_CAT1_SDIO_F_MIN; + props->host_caps.bus_4_bit_support = true; + props->host_caps.high_spd_support = true; + props->host_caps.sdr50_support = true; + props->host_caps.sdio_async_interrupt_support = true; + props->host_caps.vol_330_support = true; + + return 0; +} + +static int ifx_cat1_sdio_enable_interrupt(const struct device *dev, sdhc_interrupt_cb_t callback, + int sources, void *user_data) +{ + struct ifx_cat1_sdio_data *data = dev->data; + const struct ifx_cat1_sdio_config *cfg = dev->config; + + if (sources != SDHC_INT_SDIO) { + return -ENOTSUP; + } + + if (callback == NULL) { + return -EINVAL; + } + + /* Record SDIO callback parameters */ + data->sdio_cb = callback; + data->sdio_cb_user_data = user_data; + + /* Enable CARD INTERRUPT event */ + cyhal_sdio_enable_event(&data->sdio_obj, CYHAL_SDIO_CARD_INTERRUPT, + cfg->irq_priority, true); + + return 0; +} + +static int ifx_cat1_sdio_disable_interrupt(const struct device *dev, int sources) +{ + struct ifx_cat1_sdio_data *data = dev->data; + const struct ifx_cat1_sdio_config *cfg = dev->config; + + if (sources != SDHC_INT_SDIO) { + return -ENOTSUP; + } + + data->sdio_cb = NULL; + data->sdio_cb_user_data = NULL; + + /* Disable CARD INTERRUPT event */ + cyhal_sdio_enable_event(&data->sdio_obj, CYHAL_SDIO_CARD_INTERRUPT, + cfg->irq_priority, false); + + return 0; +} + +static void ifx_cat1_sdio_event_callback(void *callback_arg, cyhal_sdio_event_t event) +{ + const struct device *dev = callback_arg; + struct ifx_cat1_sdio_data *data = dev->data; + + if ((event == CYHAL_SDIO_CARD_INTERRUPT) && (data->sdio_cb != NULL)) { + data->sdio_cb(dev, SDHC_INT_SDIO, data->sdio_cb_user_data); + } +} + +static int ifx_cat1_sdio_init(const struct device *dev) +{ + cy_rslt_t ret; + struct ifx_cat1_sdio_data *data = dev->data; + const struct ifx_cat1_sdio_config *config = dev->config; + + /* Configure dt provided device signals when available */ + ret = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (ret) { + return ret; + } + + /* Dedicate SDIO HW resource */ + data->hw_resource.type = CYHAL_RSC_SDIODEV; + data->hw_resource.block_num = _get_hw_block_num(config->reg_addr); + + /* Initialize the SDIO peripheral */ + data->cyhal_sdio_config.resource = &data->hw_resource; + data->cyhal_sdio_config.host_config = &host_config, + data->cyhal_sdio_config.card_config = &sd_host_sd_card_config, + + ret = cyhal_sdio_init_cfg(&data->sdio_obj, &data->cyhal_sdio_config); + if (ret != CY_RSLT_SUCCESS) { + LOG_ERR("cyhal_sdio_init_cfg failed ret = %d \r\n", ret); + return ret; + } + + /* Register callback for SDIO events */ + cyhal_sdio_register_callback(&data->sdio_obj, ifx_cat1_sdio_event_callback, (void *)dev); + + return 0; +} + +static const struct sdhc_driver_api ifx_cat1_sdio_api = { + .reset = ifx_cat1_sdio_reset, + .request = ifx_cat1_sdio_request, + .set_io = ifx_cat1_sdio_set_io, + .get_card_present = ifx_cat1_sdio_get_card_present, + .card_busy = ifx_cat1_sdio_card_busy, + .get_host_props = ifx_cat1_sdio_get_host_props, + .enable_interrupt = ifx_cat1_sdio_enable_interrupt, + .disable_interrupt = ifx_cat1_sdio_disable_interrupt, +}; + +#define IFX_CAT1_SDHC_INIT(n) \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + \ + static const struct ifx_cat1_sdio_config ifx_cat1_sdio_##n##_config = { \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .reg_addr = (SDHC_Type *)DT_INST_REG_ADDR(n), \ + .irq_priority = DT_INST_IRQ(n, priority)}; \ + \ + static struct ifx_cat1_sdio_data ifx_cat1_sdio_##n##_data; \ + \ + DEVICE_DT_INST_DEFINE(n, &ifx_cat1_sdio_init, NULL, &ifx_cat1_sdio_##n##_data, \ + &ifx_cat1_sdio_##n##_config, POST_KERNEL, CONFIG_SDHC_INIT_PRIORITY, \ + &ifx_cat1_sdio_api); + +DT_INST_FOREACH_STATUS_OKAY(IFX_CAT1_SDHC_INIT) diff --git a/drivers/sdhc/imx_usdhc.c b/drivers/sdhc/imx_usdhc.c index 49914137eece7d5..84f8f2aee3b0b27 100644 --- a/drivers/sdhc/imx_usdhc.c +++ b/drivers/sdhc/imx_usdhc.c @@ -75,6 +75,7 @@ struct usdhc_config { }; struct usdhc_data { + const struct device *dev; struct sdhc_host_props props; bool card_present; struct k_sem transfer_sem; @@ -82,6 +83,9 @@ struct usdhc_data { usdhc_handle_t transfer_handle; struct sdhc_io host_io; struct k_mutex access_mutex; + sdhc_interrupt_cb_t sdhc_cb; + struct gpio_callback cd_callback; + void *sdhc_cb_user_data; uint8_t usdhc_rx_dummy[128] __aligned(32); #ifdef CONFIG_IMX_USDHC_DMA_SUPPORT uint32_t *usdhc_dma_descriptor; /* ADMA descriptor table (noncachable) */ @@ -107,6 +111,55 @@ static void transfer_complete_cb(USDHC_Type *usdhc, usdhc_handle_t *handle, k_sem_give(&data->transfer_sem); } + +static void sdio_interrupt_cb(USDHC_Type *usdhc, void *user_data) +{ + const struct device *dev = user_data; + struct usdhc_data *data = dev->data; + + if (data->sdhc_cb) { + data->sdhc_cb(dev, SDHC_INT_SDIO, data->sdhc_cb_user_data); + } +} + +static void card_inserted_cb(USDHC_Type *usdhc, void *user_data) +{ + const struct device *dev = user_data; + struct usdhc_data *data = dev->data; + + if (data->sdhc_cb) { + data->sdhc_cb(dev, SDHC_INT_INSERTED, data->sdhc_cb_user_data); + } +} + +static void card_removed_cb(USDHC_Type *usdhc, void *user_data) +{ + const struct device *dev = user_data; + struct usdhc_data *data = dev->data; + + if (data->sdhc_cb) { + data->sdhc_cb(dev, SDHC_INT_REMOVED, data->sdhc_cb_user_data); + } +} + +static void card_detect_gpio_cb(const struct device *port, + struct gpio_callback *cb, + gpio_port_pins_t pins) +{ + struct usdhc_data *data = CONTAINER_OF(cb, struct usdhc_data, cd_callback); + const struct device *dev = data->dev; + const struct usdhc_config *cfg = dev->config; + + if (data->sdhc_cb) { + if (gpio_pin_get_dt(&cfg->detect_gpio)) { + data->sdhc_cb(dev, SDHC_INT_INSERTED, data->sdhc_cb_user_data); + } else { + data->sdhc_cb(dev, SDHC_INT_REMOVED, data->sdhc_cb_user_data); + } + } +} + + static int imx_usdhc_dat3_pull(const struct usdhc_config *cfg, bool pullup) { int ret = 0U; @@ -333,16 +386,10 @@ static int imx_usdhc_set_io(const struct device *dev, struct sdhc_io *ios) /* Set card power */ if ((host_io->power_mode != ios->power_mode) && (cfg->pwr_gpio.port)) { - if (host_io->power_mode == SDHC_POWER_ON) { - /* Send 74 clock cycles if SD card is just powering on */ - USDHC_SetCardActive(cfg->base, 0xFFFF); - } - if (cfg->pwr_gpio.port) { - if (ios->power_mode == SDHC_POWER_OFF) { - gpio_pin_set_dt(&cfg->pwr_gpio, 0); - } else if (ios->power_mode == SDHC_POWER_ON) { - gpio_pin_set_dt(&cfg->pwr_gpio, 1); - } + if (ios->power_mode == SDHC_POWER_OFF) { + gpio_pin_set_dt(&cfg->pwr_gpio, 0); + } else if (ios->power_mode == SDHC_POWER_ON) { + gpio_pin_set_dt(&cfg->pwr_gpio, 1); } host_io->power_mode = ios->power_mode; } @@ -353,6 +400,11 @@ static int imx_usdhc_set_io(const struct device *dev, struct sdhc_io *ios) case SDHC_TIMING_LEGACY: case SDHC_TIMING_HS: break; + case SDHC_TIMING_DDR50: + 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); @@ -371,8 +423,6 @@ static int imx_usdhc_set_io(const struct device *dev, struct sdhc_io *ios) return -ENOTSUP; #endif case SDHC_TIMING_SDR104: - case SDHC_TIMING_DDR50: - case SDHC_TIMING_DDR52: case SDHC_TIMING_HS200: pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_FAST); break; @@ -591,6 +641,10 @@ static int imx_usdhc_request(const struct device *dev, struct sdhc_command *cmd, int ret = 0; int retries = (int)cmd->retries; + if (cmd->opcode == SD_GO_IDLE_STATE) { + USDHC_SetCardActive(cfg->base, 0xFFFF); + } + host_cmd.index = cmd->opcode; host_cmd.argument = cmd->arg; /* Mask out part of response type field used for SPI commands */ @@ -645,6 +699,14 @@ static int imx_usdhc_request(const struct device *dev, struct sdhc_command *cmd, case SD_APP_SEND_NUM_WRITTEN_BLK: host_data.rxData = data->data; break; + case SDIO_RW_EXTENDED: + /* Use R/W bit to determine data direction */ + if (host_cmd.argument & BIT(SDIO_CMD_ARG_RW_SHIFT)) { + host_data.txData = data->data; + } else { + host_data.rxData = data->data; + } + break; default: return -ENOTSUP; @@ -757,8 +819,7 @@ static int imx_usdhc_get_card_present(const struct device *dev) } else if (cfg->detect_gpio.port) { data->card_present = gpio_pin_get_dt(&cfg->detect_gpio) > 0; } else { - LOG_WRN("No card presence method configured, assuming card is present"); - data->card_present = true; + data->card_present = USDHC_DetectCardInsert(cfg->base); } return ((int)data->card_present); } @@ -775,6 +836,132 @@ static int imx_usdhc_get_host_props(const struct device *dev, return 0; } +/* + * Enable SDHC card interrupt + */ +static int imx_usdhc_enable_interrupt(const struct device *dev, + sdhc_interrupt_cb_t callback, + int sources, void *user_data) +{ + const struct usdhc_config *cfg = dev->config; + struct usdhc_data *data = dev->data; + int ret; + + /* Record SDIO callback parameters */ + data->sdhc_cb = callback; + data->sdhc_cb_user_data = user_data; + + /* Disable interrupts, then enable what the user requested */ + USDHC_DisableInterruptStatus(cfg->base, kUSDHC_CardInterruptFlag); + USDHC_DisableInterruptSignal(cfg->base, kUSDHC_CardInterruptFlag); + if (cfg->detect_gpio.port) { + ret = gpio_pin_interrupt_configure_dt(&cfg->detect_gpio, + GPIO_INT_DISABLE); + if (ret) { + return ret; + } + } else { + USDHC_DisableInterruptSignal(cfg->base, kUSDHC_CardInsertionFlag); + USDHC_DisableInterruptStatus(cfg->base, kUSDHC_CardInsertionFlag); + USDHC_DisableInterruptSignal(cfg->base, kUSDHC_CardRemovalFlag); + USDHC_DisableInterruptStatus(cfg->base, kUSDHC_CardRemovalFlag); + } + + if (sources & SDHC_INT_SDIO) { + /* Enable SDIO card interrupt */ + USDHC_EnableInterruptStatus(cfg->base, kUSDHC_CardInterruptFlag); + USDHC_EnableInterruptSignal(cfg->base, kUSDHC_CardInterruptFlag); + } + if (sources & SDHC_INT_INSERTED) { + if (cfg->detect_gpio.port) { + /* Use GPIO interrupt */ + ret = gpio_pin_interrupt_configure_dt(&cfg->detect_gpio, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret) { + return ret; + } + } else { + /* Enable card insertion interrupt */ + USDHC_EnableInterruptStatus(cfg->base, + kUSDHC_CardInsertionFlag); + USDHC_EnableInterruptSignal(cfg->base, + kUSDHC_CardInsertionFlag); + } + } + if (sources & SDHC_INT_REMOVED) { + if (cfg->detect_gpio.port) { + /* Use GPIO interrupt */ + ret = gpio_pin_interrupt_configure_dt(&cfg->detect_gpio, + GPIO_INT_EDGE_TO_INACTIVE); + if (ret) { + return ret; + } + } else { + /* Enable card removal interrupt */ + USDHC_EnableInterruptStatus(cfg->base, + kUSDHC_CardRemovalFlag); + USDHC_EnableInterruptSignal(cfg->base, + kUSDHC_CardRemovalFlag); + } + } + + return 0; +} + +static int imx_usdhc_disable_interrupt(const struct device *dev, int sources) +{ + const struct usdhc_config *cfg = dev->config; + struct usdhc_data *data = dev->data; + int ret; + + + if (sources & SDHC_INT_SDIO) { + /* Disable SDIO card interrupt */ + USDHC_DisableInterruptStatus(cfg->base, kUSDHC_CardInterruptFlag); + USDHC_DisableInterruptSignal(cfg->base, kUSDHC_CardInterruptFlag); + } + if (sources & SDHC_INT_INSERTED) { + if (cfg->detect_gpio.port) { + ret = gpio_pin_interrupt_configure_dt(&cfg->detect_gpio, + GPIO_INT_DISABLE); + if (ret) { + return ret; + } + } else { + /* Disable card insertion interrupt */ + USDHC_DisableInterruptStatus(cfg->base, + kUSDHC_CardInsertionFlag); + USDHC_DisableInterruptSignal(cfg->base, + kUSDHC_CardInsertionFlag); + } + } + if (sources & SDHC_INT_REMOVED) { + if (cfg->detect_gpio.port) { + ret = gpio_pin_interrupt_configure_dt(&cfg->detect_gpio, + GPIO_INT_DISABLE); + if (ret) { + return ret; + } + } else { + /* Disable card removal interrupt */ + USDHC_DisableInterruptStatus(cfg->base, + kUSDHC_CardRemovalFlag); + USDHC_DisableInterruptSignal(cfg->base, + kUSDHC_CardRemovalFlag); + } + } + + /* If all interrupt flags are disabled, remove callback */ + if ((USDHC_GetEnabledInterruptStatusFlags(cfg->base) & + (kUSDHC_CardInterruptFlag | kUSDHC_CardInsertionFlag | + kUSDHC_CardRemovalFlag)) == 0) { + data->sdhc_cb = NULL; + data->sdhc_cb_user_data = NULL; + } + + return 0; +} + static int imx_usdhc_isr(const struct device *dev) { const struct usdhc_config *cfg = dev->config; @@ -795,6 +982,9 @@ static int imx_usdhc_init(const struct device *dev) int ret; const usdhc_transfer_callback_t callbacks = { .TransferComplete = transfer_complete_cb, + .SdioInterrupt = sdio_interrupt_cb, + .CardInserted = card_inserted_cb, + .CardRemoved = card_removed_cb, }; if (!device_is_ready(cfg->clock_dev)) { @@ -833,9 +1023,24 @@ static int imx_usdhc_init(const struct device *dev) if (ret) { return ret; } + gpio_init_callback(&data->cd_callback, card_detect_gpio_cb, + BIT(cfg->detect_gpio.pin)); + ret = gpio_add_callback_dt(&cfg->detect_gpio, &data->cd_callback); + if (ret) { + return ret; + } } + 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); } @@ -847,6 +1052,8 @@ static const struct sdhc_driver_api usdhc_api = { .execute_tuning = imx_usdhc_execute_tuning, .card_busy = imx_usdhc_card_busy, .get_host_props = imx_usdhc_get_host_props, + .enable_interrupt = imx_usdhc_enable_interrupt, + .disable_interrupt = imx_usdhc_disable_interrupt, }; #ifdef CONFIG_NOCACHE_MEMORY diff --git a/drivers/sdhc/intel_emmc_host.c b/drivers/sdhc/intel_emmc_host.c index ec5c7934be14a56..6286965f1564e46 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 000000000000000..f5a880e5fb4e6ec --- /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 000000000000000..773b92b0e0502ce --- /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 000000000000000..5ffaa75c79c9374 --- /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 4224704414307c1..7462e711dcd4079 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 782115ca130f067..a2c3a0f34cbf36c 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -7,15 +7,19 @@ add_subdirectory_ifdef(CONFIG_ADT7310 adt7310) add_subdirectory_ifdef(CONFIG_ADT7420 adt7420) 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) add_subdirectory_ifdef(CONFIG_AMG88XX amg88xx) add_subdirectory_ifdef(CONFIG_AMS_AS5600 ams_as5600) 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) @@ -26,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) @@ -34,6 +39,7 @@ add_subdirectory_ifdef(CONFIG_DPS310 dps310) add_subdirectory_ifdef(CONFIG_DS18B20 ds18b20) add_subdirectory_ifdef(CONFIG_ENS210 ens210) add_subdirectory_ifdef(CONFIG_ESP32_TEMP esp32_temp) +add_subdirectory_ifdef(CONFIG_EXPLORIR_M explorir_m) add_subdirectory_ifdef(CONFIG_F75303 f75303) add_subdirectory_ifdef(CONFIG_FDC2X1X fdc2x1x) add_subdirectory_ifdef(CONFIG_FXAS21002 fxas21002) @@ -44,6 +50,7 @@ add_subdirectory_ifdef(CONFIG_HAS_STMEMSC stmemsc) add_subdirectory_ifdef(CONFIG_HM330X hm330x) add_subdirectory_ifdef(CONFIG_HMC5883L hmc5883l) add_subdirectory_ifdef(CONFIG_HP206C hp206c) +add_subdirectory_ifdef(CONFIG_HS300X hs300x) add_subdirectory_ifdef(CONFIG_HTS221 hts221) add_subdirectory_ifdef(CONFIG_I3G4250D i3g4250d) add_subdirectory_ifdef(CONFIG_ICM42605 icm42605) @@ -64,11 +71,13 @@ add_subdirectory_ifdef(CONFIG_ISM330DHCX ism330dhcx) add_subdirectory_ifdef(CONFIG_ITDS wsen_itds) add_subdirectory_ifdef(CONFIG_LIS2DH lis2dh) 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_LPS2XDF lps2xdf) add_subdirectory_ifdef(CONFIG_LPS22HB lps22hb) add_subdirectory_ifdef(CONFIG_LPS22HH lps22hh) add_subdirectory_ifdef(CONFIG_LPS25HB lps25hb) @@ -80,6 +89,7 @@ add_subdirectory_ifdef(CONFIG_LSM6DSO16IS lsm6dso16is) add_subdirectory_ifdef(CONFIG_LSM6DSV16X lsm6dsv16x) add_subdirectory_ifdef(CONFIG_LSM9DS0_GYRO lsm9ds0_gyro) add_subdirectory_ifdef(CONFIG_LSM9DS0_MFD lsm9ds0_mfd) +add_subdirectory_ifdef(CONFIG_LTR_F216A ltrf216a) add_subdirectory_ifdef(CONFIG_MAX17055 max17055) add_subdirectory_ifdef(CONFIG_MAX17262 max17262) add_subdirectory_ifdef(CONFIG_MAX30101 max30101) @@ -88,6 +98,7 @@ add_subdirectory_ifdef(CONFIG_MAX31865 max31865) add_subdirectory_ifdef(CONFIG_MAX31875 max31875) add_subdirectory_ifdef(CONFIG_MAX44009 max44009) add_subdirectory_ifdef(CONFIG_MAX6675 max6675) +add_subdirectory_ifdef(CONFIG_MC3419 mc3419) add_subdirectory_ifdef(CONFIG_MCP9600 mcp9600) add_subdirectory_ifdef(CONFIG_MCP970X mcp970x) add_subdirectory_ifdef(CONFIG_MCP9808 mcp9808) @@ -105,6 +116,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) @@ -142,6 +154,7 @@ add_subdirectory_ifdef(CONFIG_TMP108 tmp108) add_subdirectory_ifdef(CONFIG_TMP112 tmp112) add_subdirectory_ifdef(CONFIG_TMP116 tmp116) 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_VEML7700 veml7700) @@ -161,5 +174,6 @@ zephyr_library_property(ALLOW_EMPTY TRUE) zephyr_library_sources_ifdef(CONFIG_USERSPACE sensor_handlers.c) zephyr_library_sources_ifdef(CONFIG_SENSOR_SHELL sensor_shell.c) +zephyr_library_sources_ifdef(CONFIG_SENSOR_SHELL_STREAM sensor_shell_stream.c) zephyr_library_sources_ifdef(CONFIG_SENSOR_SHELL_BATTERY shell_battery.c) zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API sensor_decoders_init.c default_rtio_sensor.c) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index f406b6d1ffe34e5..4a446e597832b5b 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -32,10 +32,26 @@ config SENSOR_SHELL depends on SHELL select CBPRINTF_FP_SUPPORT select SENSOR_ASYNC_API - default y if !SHELL_MINIMAL help This shell provides access to basic sensor data. +config SENSOR_SHELL_STREAM + bool "Sensor shell 'stream' command" + depends on SENSOR_SHELL + help + Add the 'stream' subcommand to the sensor shell. When run on drivers that + support streaming (usually hardware FIFO backed), the shell will continue + to print new values as they come until the stream is closed. + +config SENSOR_SHELL_THREAD_STACK_SIZE + int "Stack size for the sensor shell data processing thread" + depends on SENSOR_SHELL_STREAM + default 1024 + help + The sensor shell uses a dedicated thread to process data coming from the + sensors in either one-shot or streaming mode. Use this config to control + the size of that thread's stack. + config SENSOR_SHELL_BATTERY bool "Sensor shell 'battery' command" depends on SHELL @@ -52,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" @@ -63,15 +87,19 @@ source "drivers/sensor/adt7310/Kconfig" source "drivers/sensor/adt7420/Kconfig" 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" source "drivers/sensor/amg88xx/Kconfig" source "drivers/sensor/ams_as5600/Kconfig" 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" @@ -82,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" @@ -90,6 +119,7 @@ source "drivers/sensor/dps310/Kconfig" source "drivers/sensor/ds18b20/Kconfig" source "drivers/sensor/ens210/Kconfig" source "drivers/sensor/esp32_temp/Kconfig" +source "drivers/sensor/explorir_m/Kconfig" source "drivers/sensor/f75303/Kconfig" source "drivers/sensor/fdc2x1x/Kconfig" source "drivers/sensor/fxas21002/Kconfig" @@ -99,6 +129,7 @@ source "drivers/sensor/grow_r502a/Kconfig" source "drivers/sensor/hm330x/Kconfig" source "drivers/sensor/hmc5883l/Kconfig" source "drivers/sensor/hp206c/Kconfig" +source "drivers/sensor/hs300x/Kconfig" source "drivers/sensor/hts221/Kconfig" source "drivers/sensor/i3g4250d/Kconfig" source "drivers/sensor/icm42605/Kconfig" @@ -120,11 +151,13 @@ source "drivers/sensor/ite_tach_it8xxx2/Kconfig" source "drivers/sensor/ite_vcmp_it8xxx2/Kconfig" source "drivers/sensor/lis2dh/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/lps2xdf/Kconfig" source "drivers/sensor/lps22hb/Kconfig" source "drivers/sensor/lps22hh/Kconfig" source "drivers/sensor/lps25hb/Kconfig" @@ -136,6 +169,7 @@ source "drivers/sensor/lsm6dso16is/Kconfig" source "drivers/sensor/lsm6dsv16x/Kconfig" source "drivers/sensor/lsm9ds0_gyro/Kconfig" source "drivers/sensor/lsm9ds0_mfd/Kconfig" +source "drivers/sensor/ltrf216a/Kconfig" source "drivers/sensor/max17055/Kconfig" source "drivers/sensor/max17262/Kconfig" source "drivers/sensor/max30101/Kconfig" @@ -144,6 +178,7 @@ source "drivers/sensor/max31865/Kconfig" source "drivers/sensor/max31875/Kconfig" source "drivers/sensor/max44009/Kconfig" source "drivers/sensor/max6675/Kconfig" +source "drivers/sensor/mc3419/Kconfig" source "drivers/sensor/mchp_tach_xec/Kconfig" source "drivers/sensor/mcp9600/Kconfig" source "drivers/sensor/mcp970x/Kconfig" @@ -166,6 +201,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" @@ -198,6 +234,7 @@ source "drivers/sensor/tmp108/Kconfig" source "drivers/sensor/tmp112/Kconfig" source "drivers/sensor/tmp116/Kconfig" source "drivers/sensor/tsl2540/Kconfig" +source "drivers/sensor/tsl2561/Kconfig" source "drivers/sensor/vcnl4040/Kconfig" source "drivers/sensor/veml7700/Kconfig" source "drivers/sensor/vl53l0x/Kconfig" diff --git a/drivers/sensor/Kconfig.trigger_template b/drivers/sensor/Kconfig.trigger_template new file mode 100644 index 000000000000000..7cb98e10e9e6756 --- /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/a01nyub/Kconfig b/drivers/sensor/a01nyub/Kconfig index ff40a6f0682e715..5f137e0358a17e0 100644 --- a/drivers/sensor/a01nyub/Kconfig +++ b/drivers/sensor/a01nyub/Kconfig @@ -6,5 +6,6 @@ config A01NYUB default y depends on DT_HAS_DFROBOT_A01NYUB_ENABLED depends on UART_INTERRUPT_DRIVEN + select UART_USE_RUNTIME_CONFIGURE help Enable driver for the DFRobot A01NYUB distance sensor. diff --git a/drivers/sensor/adltc2990/CMakeLists.txt b/drivers/sensor/adltc2990/CMakeLists.txt index 45ca5eb803bee2d..d71bf940a697cb0 100644 --- a/drivers/sensor/adltc2990/CMakeLists.txt +++ b/drivers/sensor/adltc2990/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_library() zephyr_library_sources(adltc2990.c) +zephyr_library_sources_ifdef(CONFIG_EMUL_ADLTC2990 adltc2990_emul.c) +zephyr_include_directories_ifdef(CONFIG_EMUL_ADLTC2990 .) diff --git a/drivers/sensor/adltc2990/Kconfig b/drivers/sensor/adltc2990/Kconfig index 260ae6af66b8004..75ac62b25f5d744 100644 --- a/drivers/sensor/adltc2990/Kconfig +++ b/drivers/sensor/adltc2990/Kconfig @@ -11,3 +11,11 @@ config ADLTC2990 help Enable the driver for Analog Devices LTC2990 Quad I2C Voltage, Current and Temperature Monitor. + +config EMUL_ADLTC2990 + bool "Emulator for ADLTC2990" + default y + depends on ADLTC2990 + depends on EMUL + help + Enable ADLTC2990 emulator. diff --git a/drivers/sensor/adltc2990/adltc2990.c b/drivers/sensor/adltc2990/adltc2990.c index 2e410505136a1b3..ea56065ede6e09b 100644 --- a/drivers/sensor/adltc2990/adltc2990.c +++ b/drivers/sensor/adltc2990/adltc2990.c @@ -1,6 +1,5 @@ /* * SPDX-FileCopyrightText: Copyright (c) 2023 Carl Zeiss Meditec AG - * * SPDX-License-Identifier: Apache-2.0 */ @@ -94,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, @@ -135,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_get_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; @@ -180,31 +187,42 @@ static int32_t adltc2990_get_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; + uint8_t negative_bit_index = 14U, sensor_val_divisor = 100U; if (type == VOLTAGE_SINGLEENDED) { conversion_factor = ADLTC2990_VOLTAGE_SINGLEENDED_CONVERSION_FACTOR; - negative_bit_index = 14; } else if (type == VOLTAGE_DIFFERENTIAL) { conversion_factor = ADLTC2990_VOLTAGE_DIFFERENTIAL_CONVERSION_FACTOR; - negative_bit_index = 14; } else if (type == TEMPERATURE) { conversion_factor = ADLTC2990_TEMPERATURE_CONVERSION_FACTOR; - negative_bit_index = 12; + if (cfg->temp_format == ADLTC2990_TEMPERATURE_FORMAT_CELSIUS) { + negative_bit_index = 12U; + } + sensor_val_divisor = 1U; } else { LOG_ERR("unknown type"); return -EINVAL; } - int16_t value = (msb_value<<8)+lsb_value; + int16_t value = (msb_value << 8) + lsb_value; - int32_t voltage_value = (value << (31-negative_bit_index))>>(31-negative_bit_index); + int32_t voltage_value = (value << (31 - negative_bit_index)) >> (31 - negative_bit_index); - return (voltage_value * conversion_factor) / 100; + *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_get_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_get_property_value(dev, VOLTAGE_DIFFERENTIAL, V1) * - ADLTC2990_MICROOHM_CONVERSION_FACTOR) / - cfg->pins_v1_v2.pins_current_resistor; + 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_get_property_value(dev, VOLTAGE_DIFFERENTIAL, V3) * - ADLTC2990_MICROOHM_CONVERSION_FACTOR) / - cfg->pins_v3_v4.pins_current_resistor; + 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_get_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_get_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.v2_r1_r2[1]; - voltage_divider_ratio = DIV_ROUND_CLOSEST(v1_r1 + v1_r2, v1_r2); - data->pins_v1_v2_values[0] = - adltc2990_get_property_value(dev, VOLTAGE_SINGLEENDED, V1) * - 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 = DIV_ROUND_CLOSEST(v2_r1 + v2_r2, v2_r2); - data->pins_v1_v2_values[1] = - adltc2990_get_property_value(dev, VOLTAGE_SINGLEENDED, V2) * - voltage_divider_ratio; + 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; + 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; + 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_get_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 = DIV_ROUND_CLOSEST(v3_r1 + v3_r2, v3_r2); - data->pins_v3_v4_values[0] = - adltc2990_get_property_value(dev, VOLTAGE_SINGLEENDED, V3) * - 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 = DIV_ROUND_CLOSEST((v4_r1 + v4_r2), v4_r2); - data->pins_v3_v4_values[1] = - adltc2990_get_property_value(dev, VOLTAGE_SINGLEENDED, V4) * - voltage_divider_ratio; + 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; + 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; + + 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_get_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[1] = - adltc2990_get_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; } @@ -368,8 +428,8 @@ static int adltc2990_channel_get(const struct device *dev, enum sensor_channel c switch (chan) { case SENSOR_CHAN_DIE_TEMP: { - val->val1 = data->internal_temperature / 10000; - val->val2 = data->internal_temperature % 10000; + val->val1 = (data->internal_temperature) / 1000000; + val->val2 = (data->internal_temperature) % 1000000; LOG_DBG("Internal Temperature Value is:%d.%d", val->val1, val->val2); break; } @@ -388,6 +448,7 @@ static int adltc2990_channel_get(const struct device *dev, enum sensor_channel c LOG_DBG("Getting V3-V4"); num_values_v3_v4 = ADLTC2990_VOLTAGE_DIFF_VALUES; } + /* Add VCC to the last index */ val[num_values_v1_v2 + num_values_v3_v4].val1 = data->supply_voltage / 1000000; val[num_values_v1_v2 + num_values_v3_v4].val2 = data->supply_voltage % 1000000; break; @@ -450,17 +511,17 @@ static const struct sensor_driver_api adltc2990_driver_api = { .temp_format = DT_INST_PROP(inst, temperature_format), \ .acq_format = DT_INST_PROP(inst, acquistion_format), \ .measurement_mode = DT_INST_PROP(inst, measurement_mode), \ - .pins_v1_v2.pins_current_resistor = \ + .pins_v1_v2.pins_current_resistor = \ DT_INST_PROP_OR(inst, pins_v1_v2_current_resistor, 1), \ - .pins_v1_v2.voltage_divider_resistors.v1_r1_r2 = \ + .pins_v1_v2.voltage_divider_resistors.v1_r1_r2 = \ DT_INST_PROP_OR(inst, pin_v1_voltage_divider_resistors, NULL), \ - .pins_v1_v2.voltage_divider_resistors.v2_r1_r2 = \ + .pins_v1_v2.voltage_divider_resistors.v2_r1_r2 = \ DT_INST_PROP_OR(inst, pin_v2_voltage_divider_resistors, NULL), \ - .pins_v3_v4.pins_current_resistor = \ + .pins_v3_v4.pins_current_resistor = \ DT_INST_PROP_OR(inst, pins_v3_v4_current_resistor, 1), \ - .pins_v3_v4.voltage_divider_resistors.v3_r1_r2 = \ + .pins_v3_v4.voltage_divider_resistors.v3_r1_r2 = \ DT_INST_PROP_OR(inst, pin_v3_voltage_divider_resistors, NULL), \ - .pins_v3_v4.voltage_divider_resistors.v4_r1_r2 = \ + .pins_v3_v4.voltage_divider_resistors.v4_r1_r2 = \ DT_INST_PROP_OR(inst, pin_v4_voltage_divider_resistors, NULL)}; \ \ SENSOR_DEVICE_DT_INST_DEFINE(inst, adltc2990_init, NULL, &adltc2990_data_##inst, \ diff --git a/drivers/sensor/adltc2990/adltc2990.h b/drivers/sensor/adltc2990/adltc2990.h index f1c20d33b23884f..af2d19955315594 100644 --- a/drivers/sensor/adltc2990/adltc2990.h +++ b/drivers/sensor/adltc2990/adltc2990.h @@ -1,6 +1,5 @@ /* * SPDX-FileCopyrightText: Copyright (c) 2023 Carl Zeiss Meditec AG - * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +9,7 @@ #include #include #include +#include #include enum adltc2990_monitor_pins { @@ -19,14 +19,14 @@ enum adltc2990_monitor_pins { V4, INTERNAL_TEMPERATURE, SUPPLY_VOLTAGE -} adltc2990_monitor_pins; +}; enum adltc2990_monitoring_type { NOTHING, VOLTAGE_DIFFERENTIAL, VOLTAGE_SINGLEENDED, TEMPERATURE -} adltc2990_monitoring_type; +}; union voltage_divider_resistors { struct { diff --git a/drivers/sensor/adltc2990/adltc2990_emul.c b/drivers/sensor/adltc2990/adltc2990_emul.c new file mode 100644 index 000000000000000..80078f21dc58b15 --- /dev/null +++ b/drivers/sensor/adltc2990/adltc2990_emul.c @@ -0,0 +1,136 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2023 Carl Zeiss Meditec AG + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_adltc2990 + +#include +#include +#include +#include +#include +#include +#include + +#include "adltc2990.h" +#include "adltc2990_reg.h" +#include "adltc2990_emul.h" + +LOG_MODULE_DECLARE(adltc2990, CONFIG_SENSOR_LOG_LEVEL); + +#define ADLTC2990_NUM_REGS ADLTC2990_REG_VCC_LSB + +struct adltc2990_emul_data { + uint8_t reg[ADLTC2990_NUM_REGS]; +}; + +struct adltc2990_emul_cfg { +}; + +void adltc2990_emul_set_reg(const struct emul *target, uint8_t reg_addr, const uint8_t *val) +{ + struct adltc2990_emul_data *data = target->data; + + __ASSERT_NO_MSG(reg_addr <= ADLTC2990_NUM_REGS); + memcpy(data->reg + reg_addr, val, 1); +} + +void adltc2990_emul_get_reg(const struct emul *target, uint8_t reg_addr, uint8_t *val) +{ + struct adltc2990_emul_data *data = target->data; + + __ASSERT_NO_MSG(reg_addr <= ADLTC2990_NUM_REGS); + memcpy(val, data->reg + reg_addr, 1); +} + +void adltc2990_emul_reset(const struct emul *target) +{ + struct adltc2990_emul_data *data = target->data; + + memset(data->reg, 0, ADLTC2990_NUM_REGS); +} + +static int adltc2990_emul_handle_write(const struct emul *target, uint8_t regn, uint8_t value) +{ + struct adltc2990_emul_data *data = target->data; + + switch (regn) { + case ADLTC2990_REG_CONTROL: + data->reg[ADLTC2990_REG_CONTROL] = value; + break; + + case ADLTC2990_REG_TRIGGER: + data->reg[ADLTC2990_REG_TRIGGER] = value; + break; + + default: + break; + } + return 0; +} + +static int adltc2990_emul_transfer_i2c(const struct emul *target, struct i2c_msg *msgs, + int num_msgs, int addr) +{ + struct adltc2990_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) { + for (int i = 0; i < msgs->len; ++i) { + msgs->buf[i] = data->reg[regn + i]; + } + } else { + int rc = adltc2990_emul_handle_write(target, regn, msgs->buf[1]); + + if (rc != 0) { + return rc; + } + } + return 0; +}; + +static int adltc2990_emul_init(const struct emul *target, const struct device *parent) +{ + ARG_UNUSED(parent); + adltc2990_emul_reset(target); + + return 0; +} + +static const struct i2c_emul_api adltc2990_emul_api_i2c = { + .transfer = adltc2990_emul_transfer_i2c, +}; + +#define ADLTC2990_EMUL(n) \ + const struct adltc2990_emul_cfg adltc2990_emul_cfg_##n; \ + struct adltc2990_emul_data adltc2990_emul_data_##n; \ + EMUL_DT_INST_DEFINE(n, adltc2990_emul_init, &adltc2990_emul_data_##n, \ + &adltc2990_emul_cfg_##n, &adltc2990_emul_api_i2c, NULL) + +DT_INST_FOREACH_STATUS_OKAY(ADLTC2990_EMUL) diff --git a/drivers/sensor/adltc2990/adltc2990_emul.h b/drivers/sensor/adltc2990/adltc2990_emul.h new file mode 100644 index 000000000000000..1085d7dea7021ba --- /dev/null +++ b/drivers/sensor/adltc2990/adltc2990_emul.h @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2023 Carl Zeiss Meditec AG + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_ADLTC2990_ADLTC2990_EMUL_H +#define ZEPHYR_DRIVERS_SENSOR_ADLTC2990_ADLTC2990_EMUL_H + +#include +#include + +void adltc2990_emul_set_reg(const struct emul *target, uint8_t reg_addr, const uint8_t *val); + +void adltc2990_emul_get_reg(const struct emul *target, uint8_t reg_addr, uint8_t *val); + +void adltc2990_emul_reset(const struct emul *target); + +#endif /* ZEPHYR_DRIVERS_SENSOR_ADLTC2990_ADLTC2990_EMUL_H */ diff --git a/drivers/sensor/adltc2990/adltc2990_reg.h b/drivers/sensor/adltc2990/adltc2990_reg.h index 3b23b8b066fdd9d..7f5a82bebacebe6 100644 --- a/drivers/sensor/adltc2990/adltc2990_reg.h +++ b/drivers/sensor/adltc2990/adltc2990_reg.h @@ -1,6 +1,5 @@ /* * SPDX-FileCopyrightText: Copyright (c) 2023 Carl Zeiss Meditec AG - * * SPDX-License-Identifier: Apache-2.0 */ @@ -44,11 +43,13 @@ #define ADLTC2990_MEASURE_PINS_V3_V4_ONLY 2U #define ADLTC2990_MEASURE_ALL_PINS_PER_MODE_2_0 3U -#define ADLTC2990_VOLTAGE_SINGLEENDED_CONVERSION_FACTOR 30518 -#define ADLTC2990_VOLTAGE_DIFFERENTIAL_CONVERSION_FACTOR 1942 -#define ADLTC2990_TEMPERATURE_CONVERSION_FACTOR 62500 +#define ADLTC2990_VOLTAGE_SINGLEENDED_CONVERSION_FACTOR 30518U +#define ADLTC2990_VOLTAGE_DIFFERENTIAL_CONVERSION_FACTOR 1942U +#define ADLTC2990_TEMPERATURE_CONVERSION_FACTOR 62500U #define ADLTC2990_MODE_2_0_MAX_VALUE 7U #define ADLTC2990_MODE_4_3_MAX_VALUE 3U +#define ADLTC2990_TEMPERATURE_FORMAT_CELSIUS 0U + #endif /* ZEPHYR_DRIVERS_SENSOR_ADLTC2990_REG_H */ diff --git a/drivers/sensor/adt7310/adt7310_trigger.c b/drivers/sensor/adt7310/adt7310_trigger.c index 25d264f57681977..be989a69910bde7 100644 --- a/drivers/sensor/adt7310/adt7310_trigger.c +++ b/drivers/sensor/adt7310/adt7310_trigger.c @@ -30,8 +30,13 @@ static void adt7310_gpio_callback(const struct device *dev, struct gpio_callback } #if defined(CONFIG_ADT7310_TRIGGER_OWN_THREAD) -static void adt7310_thread(struct adt7310_data *drv_data) +static void adt7310_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct adt7310_data *drv_data = p1; + while (true) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); if (drv_data->th_handler != NULL) { @@ -125,7 +130,7 @@ int adt7310_init_interrupt(const struct device *dev) k_sem_init(&drv_data->gpio_sem, 0, 1); k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_ADT7310_THREAD_STACK_SIZE, - (k_thread_entry_t)adt7310_thread, drv_data, + adt7310_thread, drv_data, NULL, NULL, K_PRIO_COOP(CONFIG_ADT7310_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_ADT7310_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/adt7420/adt7420_trigger.c b/drivers/sensor/adt7420/adt7420_trigger.c index 00065eab58697e8..1a26903adc75299 100644 --- a/drivers/sensor/adt7420/adt7420_trigger.c +++ b/drivers/sensor/adt7420/adt7420_trigger.c @@ -76,8 +76,13 @@ static void adt7420_gpio_callback(const struct device *dev, } #if defined(CONFIG_ADT7420_TRIGGER_OWN_THREAD) -static void adt7420_thread(struct adt7420_data *drv_data) +static void adt7420_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct adt7420_data *drv_data = p1; + while (true) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); process_int(drv_data->dev); @@ -162,7 +167,7 @@ int adt7420_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_ADT7420_THREAD_STACK_SIZE, - (k_thread_entry_t)adt7420_thread, drv_data, + adt7420_thread, drv_data, NULL, NULL, K_PRIO_COOP(CONFIG_ADT7420_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_ADT7420_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/adxl362/adxl362_trigger.c b/drivers/sensor/adxl362/adxl362_trigger.c index ba30c0a182637fc..341e6dad04d4e2a 100644 --- a/drivers/sensor/adxl362/adxl362_trigger.c +++ b/drivers/sensor/adxl362/adxl362_trigger.c @@ -62,8 +62,13 @@ static void adxl362_gpio_callback(const struct device *dev, } #if defined(CONFIG_ADXL362_TRIGGER_OWN_THREAD) -static void adxl362_thread(struct adxl362_data *drv_data) +static void adxl362_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct adxl362_data *drv_data = p1; + while (true) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); adxl362_thread_cb(drv_data->dev); @@ -171,7 +176,7 @@ int adxl362_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_ADXL362_THREAD_STACK_SIZE, - (k_thread_entry_t)adxl362_thread, drv_data, + adxl362_thread, drv_data, NULL, NULL, K_PRIO_COOP(CONFIG_ADXL362_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_ADXL362_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/adxl367/CMakeLists.txt b/drivers/sensor/adxl367/CMakeLists.txt new file mode 100644 index 000000000000000..1496eb11266d769 --- /dev/null +++ b/drivers/sensor/adxl367/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) 2023 Analog Devices Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +zephyr_library() + +zephyr_library_sources(adxl367.c) +zephyr_library_sources(adxl367_spi.c) +zephyr_library_sources(adxl367_i2c.c) +zephyr_library_sources_ifdef(CONFIG_ADXL367_TRIGGER adxl367_trigger.c) diff --git a/drivers/sensor/adxl367/Kconfig b/drivers/sensor/adxl367/Kconfig new file mode 100644 index 000000000000000..e0b4660b0f39e58 --- /dev/null +++ b/drivers/sensor/adxl367/Kconfig @@ -0,0 +1,133 @@ +# Micropower, 3-Axis, +/-200g Digital Accelerometer + +# Copyright (c) 2023 Analog Devices Inc. +# SPDX-License-Identifier: Apache-2.0 + +menuconfig ADXL367 + bool "ADXL367 Three Axis High-g I2C/SPI accelerometer" + default y + depends on DT_HAS_ADI_ADXL367_ENABLED + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ADI_ADXL367),i2c) + select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ADI_ADXL367),spi) + help + Enable driver for ADXL367 Three-Axis Digital Accelerometers. + +if ADXL367 + +choice ADXL367_OP_MODE + prompt "Operating mode" + default ADXL367_MEASUREMENT_MODE + +config ADXL367_MEASUREMENT_MODE + bool "Measurement Mode" + help + In this mode, acceleration data is provided continuously at the + output data rate (ODR). + +endchoice + +config ADXL367_ACTIVITY_THRESHOLD + int "Activity threshold in raw value" + range 0 8191 + default 100 + help + Threshold for activity detection. + +config ADXL367_INACTIVITY_THRESHOLD + int "In-activity threshold in raw value" + range 0 8191 + default 100 + help + Threshold for in-activity detection. + +config ADXL367_ACTIVITY_TIME + int "Activity time" + range 0 255 + default 100 + help + The activity timer implements a robust activity detection that + minimizes false positive motion triggers. When the timer is used, + only sustained motion can trigger activity detection. Value is the + number of samples. For example, at 100Hz ODR, 100 value translates + to 1 second. + +config ADXL367_INACTIVITY_TIME + int "In-activity time" + range 0 65535 + default 100 + help + The time that all enabled axes must be lower than the inactivity + threshold for an inactivity event to be detected. Value is the + number of samples. For example, at 100Hz ODR, 100 value translates + to 1 second. + +config ADXL367_ACTIVITY_DETECTION_MODE + bool "Use activity detection" + default y + help + Enable Activity detection. + +config ADXL367_INACTIVITY_DETECTION_MODE + bool "Use inactivity detection" + default y + help + Enable Inactivity detection. + + +config ADXL367_REFERENCED_ACTIVITY_DETECTION_MODE + bool "Use referenced activity detection" + default y + help + Activity detection can be configured as referenced or absolute. + When using absolute activity detection, acceleration samples are + compared directly to a user set threshold to determine whether + motion is present. + +config ADXL367_REFERENCED_INACTIVITY_DETECTION_MODE + bool "Use referenced inactivity detection" + default y + help + Inactivity detection can be configured as referenced or absolute. + When using absolute inactivity detection, acceleration samples are + compared directly to a user set threshold to determine whether + motion is present. + +choice ADXL367_TRIGGER_MODE + prompt "Trigger mode" + default ADXL367_TRIGGER_NONE + help + Specify the type of triggering used by the driver. + +config ADXL367_TRIGGER_NONE + bool "No trigger" + +config ADXL367_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + depends on GPIO + select ADXL367_TRIGGER + +config ADXL367_TRIGGER_OWN_THREAD + bool "Use own thread" + depends on GPIO + select ADXL367_TRIGGER + +endchoice + +config ADXL367_TRIGGER + bool + +config ADXL367_THREAD_PRIORITY + int "Thread priority" + depends on ADXL367_TRIGGER_OWN_THREAD && ADXL367_TRIGGER + default 10 + help + Priority of thread used by the driver to handle interrupts. + +config ADXL367_THREAD_STACK_SIZE + int "Thread stack size" + depends on ADXL367_TRIGGER_OWN_THREAD && ADXL367_TRIGGER + default 1024 + help + Stack size of thread used by the driver to handle interrupts. + +endif # ADXL367 diff --git a/drivers/sensor/adxl367/adxl367.c b/drivers/sensor/adxl367/adxl367.c new file mode 100644 index 000000000000000..1d5c31ad0210161 --- /dev/null +++ b/drivers/sensor/adxl367/adxl367.c @@ -0,0 +1,1101 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_adxl367 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "adxl367.h" + +LOG_MODULE_REGISTER(ADXL367, CONFIG_SENSOR_LOG_LEVEL); + +static const uint8_t adxl367_scale_mul[3] = {1, 2, 4}; +static uint8_t samples_per_set; + +/** + * @brief Configures activity detection. + * + * @param dev - The device structure. + * @param th - Structure holding the activity threshold information: + * Enable/Disable Activity detection + * Enable/Disable Referenced Activity detection + * Set Threshold value + * @return 0 in case of success, negative error code otherwise. + */ +static int adxl367_setup_activity_detection(const struct device *dev, + const struct adxl367_activity_threshold *th) +{ + struct adxl367_data *data = dev->data; + int ret; + + + ret = data->hw_tf->write_reg_mask(dev, ADXL367_ACT_INACT_CTL, + ADXL367_ACT_INACT_CTL_ACT_EN_MSK | + ADXL367_ACT_INACT_CTL_ACT_REF_MSK, + FIELD_PREP(ADXL367_ACT_INACT_CTL_ACT_EN_MSK, th->enable) | + FIELD_PREP(ADXL367_ACT_INACT_CTL_ACT_REF_MSK, + th->referenced)); + if (ret != 0) { + return ret; + } + + ret = data->hw_tf->write_reg_mask(dev, ADXL367_THRESH_ACT_H, ADXL367_THRESH_H_MSK, + FIELD_PREP(ADXL367_THRESH_H_MSK, th->value >> 6)); + if (ret != 0) { + return ret; + } + + return data->hw_tf->write_reg_mask(dev, ADXL367_THRESH_ACT_L, ADXL367_THRESH_L_MSK, + FIELD_PREP(ADXL367_THRESH_L_MSK, th->value & 0x3F)); +} + +/** + * @brief Configures activity detection. + * + * @param dev - The device structure. + * @param th - Structure holding the inactivity threshold information: + * Enable/Disable inactivity detection + * Enable/Disable Referenced inactivity detection + * Set Threshold value + * + * @return 0 in case of success, negative error code otherwise. + */ +static int adxl367_setup_inactivity_detection(const struct device *dev, + const struct adxl367_activity_threshold *th) +{ + struct adxl367_data *data = dev->data; + int ret; + + ret = data->hw_tf->write_reg_mask(dev, ADXL367_ACT_INACT_CTL, + ADXL367_ACT_INACT_CTL_INACT_EN_MSK | + ADXL367_ACT_INACT_CTL_INACT_REF_MSK, + FIELD_PREP(ADXL367_ACT_INACT_CTL_INACT_EN_MSK, + th->enable) | + FIELD_PREP(ADXL367_ACT_INACT_CTL_INACT_REF_MSK, + th->referenced)); + if (ret != 0) { + return ret; + } + + ret = data->hw_tf->write_reg_mask(dev, ADXL367_THRESH_INACT_H, ADXL367_THRESH_H_MSK, + FIELD_PREP(ADXL367_THRESH_H_MSK, th->value >> 6)); + if (ret != 0) { + return ret; + } + + return data->hw_tf->write_reg_mask(dev, ADXL367_THRESH_INACT_L, ADXL367_THRESH_L_MSK, + FIELD_PREP(ADXL367_THRESH_L_MSK, th->value & 0x3F)); +} + +/** + * @brief Set the mode of operation. + * + * @param dev - The device structure. + * @param op_mode - Mode of operation. + * Accepted values: ADXL367_STANDBY + * ADXL367_MEASURE + * + * @return 0 in case of success, negative error code otherwise. + */ +static int adxl367_set_op_mode(const struct device *dev, + enum adxl367_op_mode op_mode) +{ + struct adxl367_data *data = dev->data; + int ret; + + ret = data->hw_tf->write_reg_mask(dev, ADXL367_POWER_CTL, + ADXL367_POWER_CTL_MEASURE_MSK, + FIELD_PREP(ADXL367_POWER_CTL_MEASURE_MSK, op_mode)); + if (ret != 0) { + return ret; + } + + if (op_mode == ADXL367_MEASURE) + /* Wait 100 ms to allow the acceleration outputs to settle */ + k_sleep(K_MSEC(100)); + + return 0; +} + +/** + * @brief Autosleep. When set to 1, autosleep is enabled, and the device enters + * wake-up mode automatically upon detection of inactivity. + * + * @param dev - The device structure. + * @param enable - Accepted values: true + * false + * + * @return 0 in case of success, negative error code otherwise. + */ +static int adxl367_set_autosleep(const struct device *dev, bool enable) +{ + struct adxl367_data *data = dev->data; + + return data->hw_tf->write_reg_mask(dev, ADXL367_POWER_CTL, + ADXL367_POWER_CTL_AUTOSLEEP_MSK, + FIELD_PREP(ADXL367_POWER_CTL_AUTOSLEEP_MSK, enable)); +} + +/** + * @brief Noise Mode. When set to 1, low noise mode is enabled + * + * @param dev - The device structure. + * @param enable - Accepted values: true + * false + * + * @return 0 in case of success, negative error code otherwise. + */ +static int adxl367_set_low_noise(const struct device *dev, bool enable) +{ + struct adxl367_data *data = dev->data; + + return data->hw_tf->write_reg_mask(dev, ADXL367_POWER_CTL, + ADXL367_POWER_CTL_NOISE_MSK, + FIELD_PREP(ADXL367_POWER_CTL_NOISE_MSK, enable)); +} + +/** + * @brief Link/Loop Activity Processing. + * + * @param dev - The device structure. + * @param mode - Mode of operation. + * Accepted values: ADXL367_DEFAULT + * ADXL367_LINKED + * ADXL367_LOOPED + * + * @return 0 in case of success, negative error code otherwise. + */ +static int adxl367_set_act_proc_mode(const struct device *dev, + enum adxl367_act_proc_mode mode) +{ + struct adxl367_data *data = dev->data; + + return data->hw_tf->write_reg_mask(dev, ADXL367_ACT_INACT_CTL, + ADXL367_ACT_INACT_CTL_LINKLOOP_MSK, + FIELD_PREP(ADXL367_ACT_INACT_CTL_LINKLOOP_MSK, mode)); +} + + +/** + * @brief Selects the Output Data Rate of the device. + * @param dev - The device structure. + * @param odr - Output Data Rate option. + * Accepted values: ADXL367_ODR_12P5HZ, + * ADXL367_ODR_25HZ, + * ADXL367_ODR_50HZ, + * ADXL367_ODR_100HZ, + * ADXL367_ODR_200HZ, + * ADXL367_ODR_400HZ + * @return 0 in case of success, negative error code otherwise. + */ +int adxl367_set_output_rate(const struct device *dev, enum adxl367_odr odr) +{ + struct adxl367_data *data = dev->data; + + return data->hw_tf->write_reg_mask(dev, + ADXL367_FILTER_CTL, + ADXL367_FILTER_CTL_ODR_MSK, + FIELD_PREP(ADXL367_FILTER_CTL_ODR_MSK, odr)); +} + +/** + * @brief Selects the measurement range. + * + * @param dev - The device structure. + * @param range - Range option. + * Accepted values: ADXL367_2G_RANGE, +/- 2g + * ADXL367_4G_RANGE, +/- 4g + * ADXL367_8G_RANGE +/- 8g + * + * @return 0 in case of success, negative error code otherwise. + */ +int adxl367_set_range(const struct device *dev, enum adxl367_range range) +{ + struct adxl367_data *data = dev->data; + + return data->hw_tf->write_reg_mask(dev, + ADXL367_FILTER_CTL, + ADXL367_FILTER_CTL_RANGE_MSK, + FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MSK, range)); +} + +/** + * @brief Set the activity timer + * + * @param dev - The device structure. + * @param time - The value set in this register. + * + * @return 0 in case of success, negative error code otherwise. + */ +static int adxl367_set_activity_time(const struct device *dev, uint8_t time) +{ + struct adxl367_data *data = dev->data; + + return data->hw_tf->write_reg(dev, ADXL367_TIME_ACT, time); +} + +/** + * Set the inactivity timer + * @param dev - The device structure. + * @param time - is the 16-bit value set by the TIME_INACT_L register + * (eight LSBs) and the TIME_INACT_H register (eight MSBs). + * @return 0 in case of success, negative error code otherwise. + */ +static int adxl367_set_inactivity_time(const struct device *dev, + uint16_t time) +{ + int ret; + struct adxl367_data *data = dev->data; + + ret = data->hw_tf->write_reg(dev, ADXL367_TIME_INACT_H, time >> 8); + if (ret != 0) { + return ret; + } + + return data->hw_tf->write_reg(dev, ADXL367_TIME_INACT_L, time & 0xFF); +} + +/** + * @brief Performs self test. + * + * @param dev - The device structure. + * + * @return 0 in case of success, negative error code otherwise. + */ +int adxl367_self_test(const struct device *dev) +{ + int ret; + struct adxl367_data *data = dev->data; + const struct adxl367_dev_config *cfg = dev->config; + int16_t x_axis_1, x_axis_2, dif, min, max; + uint8_t read_val[2]; + + uint32_t st_delay_ms; + + /* 4 / ODR value in ms */ + switch (cfg->odr) { + case ADXL367_ODR_12P5HZ: + st_delay_ms = 320; + break; + case ADXL367_ODR_25HZ: + st_delay_ms = 160; + break; + case ADXL367_ODR_50HZ: + st_delay_ms = 80; + break; + case ADXL367_ODR_100HZ: + st_delay_ms = 40; + break; + case ADXL367_ODR_200HZ: + st_delay_ms = 20; + break; + case ADXL367_ODR_400HZ: + st_delay_ms = 10; + break; + default: + return -EINVAL; + } + + ret = adxl367_set_op_mode(dev, ADXL367_MEASURE); + if (ret != 0) { + return ret; + } + + ret = data->hw_tf->write_reg_mask(dev, ADXL367_SELF_TEST, ADXL367_SELF_TEST_ST_MSK, + FIELD_PREP(ADXL367_SELF_TEST_ST_MSK, 1)); + if (ret != 0) { + return ret; + } + + /* 4 / ODR */ + k_sleep(K_MSEC(st_delay_ms)); + + ret = data->hw_tf->read_reg_multiple(dev, ADXL367_X_DATA_H, read_val, 2); + if (ret != 0) { + return ret; + } + + x_axis_1 = ((int16_t)read_val[0] << 6) + (read_val[1] >> 2); + + /* extend sign to 16 bits */ + if ((x_axis_1 & BIT(13)) != 0) { + x_axis_1 |= GENMASK(15, 14); + } + + ret = data->hw_tf->write_reg_mask(dev, ADXL367_SELF_TEST, + ADXL367_SELF_TEST_ST_FORCE_MSK, + FIELD_PREP(ADXL367_SELF_TEST_ST_FORCE_MSK, 1)); + if (ret != 0) { + return ret; + } + + /* 4 / ODR */ + k_sleep(K_MSEC(st_delay_ms)); + + ret = data->hw_tf->read_reg_multiple(dev, ADXL367_X_DATA_H, read_val, 2); + if (ret != 0) { + return ret; + } + + x_axis_2 = ((int16_t)read_val[0] << 6) + (read_val[1] >> 2); + + /* extend sign to 16 bits */ + if ((x_axis_2 & BIT(13)) != 0) + x_axis_2 |= GENMASK(15, 14); + + ret = adxl367_set_op_mode(dev, ADXL367_STANDBY); + if (ret != 0) { + return ret; + } + + ret = data->hw_tf->write_reg_mask(dev, ADXL367_SELF_TEST, ADXL367_SELF_TEST_ST_FORCE_MSK | + ADXL367_SELF_TEST_ST_MSK, + FIELD_PREP(ADXL367_SELF_TEST_ST_FORCE_MSK, 0) | + FIELD_PREP(ADXL367_SELF_TEST_ST_MSK, 0)); + if (ret != 0) { + return ret; + } + + dif = x_axis_2 - x_axis_1; + min = ADXL367_SELF_TEST_MIN * adxl367_scale_mul[data->range]; + max = ADXL367_SELF_TEST_MAX * adxl367_scale_mul[data->range]; + + if ((dif >= min) && (dif <= max)) { + LOG_INF("ADXL367 passed self-test\n"); + ret = 0; + } else { + LOG_ERR("ADXL367 failed self-test\n"); + ret = -EINVAL; + } + + return ret; +} + +/** + * @brief Enables temperature reading. + * + * @param dev - The device structure. + * @param enable - 1 - ENABLE + * 2 - DISABLE + * + * @return 0 in case of success, negative error code otherwise. + */ +int adxl367_temp_read_en(const struct device *dev, bool enable) +{ + struct adxl367_data *data = dev->data; + + return data->hw_tf->write_reg_mask(dev, + ADXL367_TEMP_CTL, + ADXL367_TEMP_EN_MSK, + FIELD_PREP(ADXL367_TEMP_EN_MSK, enable)); +} + +/** + * @brief Sets the number of FIFO sample sets. + * + * @param dev - The device structure. + * @param sets_nb - Sample sets number. For example, if ADXL367_FIFO_FORMAT_XYZ + * is selected, a value of 2 will represent 6 entries. + * + * @return 0 in case of success, negative error code otherwise. + */ +int adxl367_set_fifo_sample_sets_nb(const struct device *dev, + uint16_t sets_nb) +{ + struct adxl367_data *data = dev->data; + int ret; + uint8_t fifo_samples_msb = sets_nb & BIT(9) ? 1U : 0U; + + /* bit 9 goes to FIFO_SAMPLES from ADXL367_FIFO_CONTROL */ + ret = data->hw_tf->write_reg_mask(dev, ADXL367_FIFO_CONTROL, + ADXL367_FIFO_CONTROL_FIFO_SAMPLES_MSK, + FIELD_PREP(ADXL367_FIFO_CONTROL_FIFO_SAMPLES_MSK, + fifo_samples_msb)); + if (ret != 0) { + return ret; + } + + /* write last 8 bits to ADXL367_FIFO_SAMPLES */ + return data->hw_tf->write_reg(dev, ADXL367_FIFO_SAMPLES, sets_nb & 0xFF); +} + +/** + * @brief Sets FIFO mode. + * + * @param dev - The device structure. + * @param mode - FIFO mode. + * Accepted values: ADXL367_FIFO_DISABLED, + * ADXL367_OLDEST_SAVED, + * ADXL367_STREAM_MODE, + * ADXL367_TRIGGERED_MODE + * + * @return 0 in case of success, negative error code otherwise. + */ +int adxl367_set_fifo_mode(const struct device *dev, + enum adxl367_fifo_mode mode) +{ + struct adxl367_data *data = dev->data; + + return data->hw_tf->write_reg_mask(dev, + ADXL367_FIFO_CONTROL, + ADXL367_FIFO_CONTROL_FIFO_MODE_MSK, + FIELD_PREP(ADXL367_FIFO_CONTROL_FIFO_MODE_MSK, mode)); +} + +/** + * @brief Sets FIFO read mode. + * + * @param dev - The device structure. + * @param read_mode - FIFO read mode. + * Accepted values: ADXL367_12B_CHID, + * ADXL367_8B, + * ADXL367_12B, + * ADXL367_14B_CHID + * + * @return 0 in case of success, negative error code otherwise. + */ +int adxl367_set_fifo_read_mode(const struct device *dev, + enum adxl367_fifo_read_mode read_mode) +{ + struct adxl367_data *data = dev->data; + + return data->hw_tf->write_reg_mask(dev, ADXL367_ADC_CTL, + ADXL367_FIFO_8_12BIT_MSK, + FIELD_PREP(ADXL367_FIFO_8_12BIT_MSK, read_mode)); +} + +/** + * @brief Sets FIFO format. + * + * @param dev - The device structure. + * @param format - FIFO format. + * Accepted values: ADXL367_FIFO_FORMAT_XYZ, + * ADXL367_FIFO_FORMAT_X, + * ADXL367_FIFO_FORMAT_Y, + * ADXL367_FIFO_FORMAT_Z, + * ADXL367_FIFO_FORMAT_XYZT, + * ADXL367_FIFO_FORMAT_XT, + * ADXL367_FIFO_FORMAT_YT, + * ADXL367_FIFO_FORMAT_ZT, + * ADXL367_FIFO_FORMAT_XYZA, + * ADXL367_FIFO_FORMAT_XA, + * ADXL367_FIFO_FORMAT_YA, + * ADXL367_FIFO_FORMAT_ZA + * + * @return 0 in case of success, negative error code otherwise. + */ +int adxl367_set_fifo_format(const struct device *dev, + enum adxl367_fifo_format format) +{ + int ret; + struct adxl367_data *data = dev->data; + + ret = data->hw_tf->write_reg_mask(dev, + ADXL367_FIFO_CONTROL, + ADXL367_FIFO_CONTROL_FIFO_CHANNEL_MSK, + FIELD_PREP(ADXL367_FIFO_CONTROL_FIFO_CHANNEL_MSK, format)); + if (ret != 0) { + return ret; + } + + switch (format) { + case ADXL367_FIFO_FORMAT_XYZ: + samples_per_set = 3; + break; + case ADXL367_FIFO_FORMAT_X: + case ADXL367_FIFO_FORMAT_Y: + case ADXL367_FIFO_FORMAT_Z: + samples_per_set = 1; + break; + case ADXL367_FIFO_FORMAT_XYZT: + case ADXL367_FIFO_FORMAT_XYZA: + samples_per_set = 4; + break; + case ADXL367_FIFO_FORMAT_XT: + case ADXL367_FIFO_FORMAT_YT: + case ADXL367_FIFO_FORMAT_ZT: + case ADXL367_FIFO_FORMAT_XA: + case ADXL367_FIFO_FORMAT_YA: + case ADXL367_FIFO_FORMAT_ZA: + samples_per_set = 2; + break; + default: + return -EINVAL; + } + + return 0; +} + +/** + * @brief Configures the FIFO feature. Uses ADXL367_14B_CHID read mode as + * default. + * + * @param dev - The device structure. + * @param mode - FIFO mode selection. + * Example: ADXL367_FIFO_DISABLED, + * ADXL367_OLDEST_SAVED, + * ADXL367_STREAM_MODE, + * ADXL367_TRIGGERED_MODE + * @param format - FIFO format selection. + * Example: ADXL367_FIFO_FORMAT_XYZ, + * ADXL367_FIFO_FORMAT_X, + * ADXL367_FIFO_FORMAT_Y, + * ADXL367_FIFO_FORMAT_Z, + * ADXL367_FIFO_FORMAT_XYZT, + * ADXL367_FIFO_FORMAT_XT, + * ADXL367_FIFO_FORMAT_YT, + * ADXL367_FIFO_FORMAT_ZT, + * ADXL367_FIFO_FORMAT_XYZA, + * ADXL367_FIFO_FORMAT_XA, + * ADXL367_FIFO_FORMAT_YA, + * ADXL367_FIFO_FORMAT_ZA + * @param read_mode - FIFO read mode. + * Accepted values: ADXL367_12B_CHID, + * ADXL367_8B, + * ADXL367_12B, + * ADXL367_14B_CHID + * @param sets_nb - Specifies the number of samples sets to store in the FIFO. + * + * @return 0 in case of success, negative error code otherwise. + */ +int adxl367_fifo_setup(const struct device *dev, + enum adxl367_fifo_mode mode, + enum adxl367_fifo_format format, + enum adxl367_fifo_read_mode read_mode, + uint8_t sets_nb) +{ + int ret; + + ret = adxl367_set_fifo_mode(dev, mode); + if (ret != 0) { + return ret; + } + + ret = adxl367_set_fifo_format(dev, format); + if (ret != 0) { + return ret; + } + + ret = adxl367_set_fifo_sample_sets_nb(dev, sets_nb); + if (ret != 0) { + return ret; + } + + return adxl367_set_fifo_read_mode(dev, read_mode); +} + +/** + * @brief Software reset. + * + * @param dev - The device structure. + * + * @return 0 in case of success, negative error code otherwise. + */ +static int adxl367_reset(const struct device *dev) +{ + int ret; + struct adxl367_data *data = dev->data; + + ret = adxl367_set_op_mode(dev, ADXL367_STANDBY); + if (ret != 0) { + return ret; + } + + /* Writing code 0x52 resets the device */ + ret = data->hw_tf->write_reg(dev, ADXL367_SOFT_RESET, ADXL367_RESET_CODE); + if (ret != 0) { + return ret; + } + + /* Delay required after performing software reset */ + k_sleep(K_MSEC(8)); + + return ret; +} + + +/** + * @brief Reads the 3-axis raw data from the accelerometer. + * + * @param dev - The device structure. + * @param accel_data - store the XYZ axis accelerometer data. + * + * @return 0 in case of success, negative error code otherwise. + */ +int adxl367_get_accel_data(const struct device *dev, + struct adxl367_xyz_accel_data *accel_data) +{ + int ret; + uint8_t xyz_values[6] = { 0 }; + uint8_t reg_data, nready = 1U; + struct adxl367_data *data = dev->data; + + while (nready != 0) { + ret = data->hw_tf->read_reg(dev, ADXL367_STATUS, ®_data); + if (ret != 0) { + return ret; + } + + if ((reg_data & ADXL367_STATUS_DATA_RDY) != 0) { + nready = 0U; + } + } + + ret = data->hw_tf->read_reg_multiple(dev, ADXL367_X_DATA_H, xyz_values, 6); + if (ret != 0) { + return ret; + } + + /* result is 14 bits long, ignore last 2 bits from low byte */ + accel_data->x = ((int16_t)xyz_values[0] << 6) + (xyz_values[1] >> 2); + accel_data->y = ((int16_t)xyz_values[2] << 6) + (xyz_values[3] >> 2); + accel_data->z = ((int16_t)xyz_values[4] << 6) + (xyz_values[5] >> 2); + + /* extend sign to 16 bits */ + if ((accel_data->x & BIT(13)) != 0) { + accel_data->x |= GENMASK(15, 14); + } + + if ((accel_data->y & BIT(13)) != 0) { + accel_data->y |= GENMASK(15, 14); + } + + if ((accel_data->z & BIT(13)) != 0) { + accel_data->z |= GENMASK(15, 14); + } + + return 0; +} + +/** + * @brief Reads the raw temperature of the device. If ADXL367_TEMP_EN is not + * set, use adxl367_temp_read_en() first to enable temperature reading. + * + * @param dev - The device structure. + * @param raw_temp - Raw value of temperature. + * + * @return 0 in case of success, negative error code otherwise. + */ +int adxl367_get_temp_data(const struct device *dev, int16_t *raw_temp) +{ + int ret; + uint8_t temp[2] = { 0 }; + uint8_t reg_data, nready = 1U; + struct adxl367_data *data = dev->data; + + while (nready != 0) { + ret = data->hw_tf->read_reg(dev, ADXL367_STATUS, ®_data); + if (ret != 0) { + return ret; + } + + if ((reg_data & ADXL367_STATUS_DATA_RDY) != 0) { + nready = 0U; + } + } + + ret = data->hw_tf->read_reg_multiple(dev, ADXL367_TEMP_H, temp, 2); + if (ret != 0) { + return ret; + } + + *raw_temp = ((int16_t)temp[0] << 6) + (temp[1] >> 2); + /* extend sign to 16 bits */ + if ((*raw_temp & BIT(13)) != 0) { + *raw_temp |= GENMASK(15, 14); + } + + return 0; +} + +static int adxl367_attr_set_thresh(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + const struct adxl367_dev_config *cfg = dev->config; + struct adxl367_activity_threshold threshold; + int64_t llvalue; + int32_t value; + int64_t micro_ms2 = val->val1 * 1000000LL + val->val2; + + llvalue = llabs((micro_ms2 * 10) / SENSOR_G); + + value = (int32_t) llvalue; + + threshold.value = value; + threshold.enable = cfg->activity_th.enable; + threshold.referenced = cfg->activity_th.referenced; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + if (attr == SENSOR_ATTR_UPPER_THRESH) { + return adxl367_setup_activity_detection(dev, &threshold); + } else { + return adxl367_setup_inactivity_detection(dev, &threshold); + } + + default: + LOG_ERR("attr_set() not supported on this channel"); + return -ENOTSUP; + } +} + +static int adxl367_attr_set_odr(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + enum adxl367_odr odr; + + switch (val->val1) { + case 12: + case 13: + odr = ADXL367_ODR_12P5HZ; + break; + case 25: + odr = ADXL367_ODR_25HZ; + break; + case 50: + odr = ADXL367_ODR_50HZ; + break; + case 100: + odr = ADXL367_ODR_100HZ; + break; + case 200: + odr = ADXL367_ODR_200HZ; + break; + case 400: + odr = ADXL367_ODR_400HZ; + break; + default: + return -EINVAL; + } + + return adxl367_set_output_rate(dev, odr); +} + +static int adxl367_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 adxl367_attr_set_odr(dev, chan, attr, val); + case SENSOR_ATTR_UPPER_THRESH: + case SENSOR_ATTR_LOWER_THRESH: + return adxl367_attr_set_thresh(dev, chan, attr, val); + default: + return -ENOTSUP; + } +} + +static int adxl367_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + struct adxl367_data *data = dev->data; + int ret; + + ret = adxl367_get_accel_data(dev, &data->sample); + if (ret != 0) { + return ret; + } + + return adxl367_get_temp_data(dev, &data->temp_val); +} + +static void adxl367_accel_convert(const struct device *dev, + struct sensor_value *val, int16_t value) +{ + struct adxl367_data *data = dev->data; + + int64_t micro_ms2 = value * (SENSOR_G * 250 / 10000 * + adxl367_scale_mul[data->range] / 1000); + + val->val1 = micro_ms2 / 1000000; + val->val2 = micro_ms2 % 1000000; +} + +static void adxl367_temp_convert(struct sensor_value *val, int16_t value) +{ + int64_t temp_data = (value + ADXL367_TEMP_OFFSET) * ADXL367_TEMP_SCALE; + + val->val1 = temp_data / ADXL367_TEMP_SCALE_DIV; + val->val2 = temp_data % ADXL367_TEMP_SCALE_DIV; +} + +static int adxl367_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct adxl367_data *data = dev->data; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + adxl367_accel_convert(dev, val, data->sample.x); + break; + case SENSOR_CHAN_ACCEL_Y: + adxl367_accel_convert(dev, val, data->sample.y); + break; + case SENSOR_CHAN_ACCEL_Z: + adxl367_accel_convert(dev, val, data->sample.z); + break; + case SENSOR_CHAN_ACCEL_XYZ: + adxl367_accel_convert(dev, val++, data->sample.x); + adxl367_accel_convert(dev, val++, data->sample.y); + adxl367_accel_convert(dev, val, data->sample.z); + break; + case SENSOR_CHAN_DIE_TEMP: + adxl367_temp_convert(val, data->temp_val); + default: + return -ENOTSUP; + } + + return 0; +} + +static const struct sensor_driver_api adxl367_api_funcs = { + .attr_set = adxl367_attr_set, + .sample_fetch = adxl367_sample_fetch, + .channel_get = adxl367_channel_get, +#ifdef CONFIG_ADXL367_TRIGGER + .trigger_set = adxl367_trigger_set, +#endif +}; + +static int adxl367_probe(const struct device *dev) +{ + const struct adxl367_dev_config *cfg = dev->config; + struct adxl367_data *data = dev->data; + uint8_t dev_id, part_id; + int ret; + + ret = adxl367_reset(dev); + if (ret != 0) { + return ret; + } + + ret = data->hw_tf->read_reg(dev, ADXL367_DEVID, &dev_id); + if (ret != 0) { + return ret; + } + ret = data->hw_tf->read_reg(dev, ADXL367_PART_ID, &part_id); + if (ret != 0) { + return ret; + } + + if (dev_id != ADXL367_DEVID_VAL || part_id != ADXL367_PARTID_VAL) { + LOG_ERR("failed to read id (0x%X:0x%X)\n", dev_id, part_id); + return -ENODEV; + } + + data->range = cfg->range; + +#ifdef CONFIG_ADXL367_TRIGGER + data->act_proc_mode = ADXL367_LINKED; +#else + data->act_proc_mode = ADXL367_LOOPED; +#endif + + ret = adxl367_self_test(dev); + if (ret != 0) { + return ret; + } + + ret = adxl367_temp_read_en(dev, cfg->temp_en); + if (ret != 0) { + return ret; + } + + ret = adxl367_set_autosleep(dev, cfg->autosleep); + if (ret != 0) { + return ret; + } + + ret = adxl367_set_low_noise(dev, cfg->low_noise); + if (ret != 0) { + return ret; + } + + ret = adxl367_setup_activity_detection(dev, &cfg->activity_th); + if (ret != 0) { + return ret; + } + + ret = adxl367_setup_inactivity_detection(dev, &cfg->inactivity_th); + if (ret != 0) { + return ret; + } + + ret = adxl367_set_activity_time(dev, cfg->activity_time); + if (ret != 0) { + return ret; + } + + ret = adxl367_set_inactivity_time(dev, cfg->inactivity_time); + if (ret != 0) { + return ret; + } + + ret = adxl367_set_output_rate(dev, cfg->odr); + if (ret != 0) { + return ret; + } + + ret = adxl367_fifo_setup(dev, cfg->fifo_config.fifo_mode, + cfg->fifo_config.fifo_format, + cfg->fifo_config.fifo_read_mode, + cfg->fifo_config.fifo_samples); + if (ret != 0) { + return ret; + } + +if (IS_ENABLED(CONFIG_ADXL367_TRIGGER)) { + ret = adxl367_init_interrupt(dev); + if (ret != 0) { + LOG_ERR("Failed to initialize interrupt!"); + return -EIO; + } +} + + ret = adxl367_set_op_mode(dev, cfg->op_mode); + if (ret != 0) { + return ret; + } + + ret = adxl367_set_range(dev, data->range); + if (ret != 0) { + return ret; + } + + return adxl367_set_act_proc_mode(dev, data->act_proc_mode); +} + +static int adxl367_init(const struct device *dev) +{ + int ret; + const struct adxl367_dev_config *cfg = dev->config; + + ret = cfg->bus_init(dev); + if (ret != 0) { + LOG_ERR("Failed to initialize sensor bus\n"); + return ret; + } + + return adxl367_probe(dev); +} + +#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0 +#warning "ADXL367 driver enabled without any devices" +#endif + +/* + * Device creation macro, shared by ADXL367_DEFINE_SPI() and + * ADXL367_DEFINE_I2C(). + */ + +#define ADXL367_DEVICE_INIT(inst) \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, \ + adxl367_init, \ + NULL, \ + &adxl367_data_##inst, \ + &adxl367_config_##inst, \ + POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, \ + &adxl367_api_funcs); + +#ifdef CONFIG_ADXL367_TRIGGER +#define ADXL367_CFG_IRQ(inst) \ + .interrupt = GPIO_DT_SPEC_INST_GET(inst, int1_gpios), +#else +#define ADXL367_CFG_IRQ(inst) +#endif /* CONFIG_ADXL367_TRIGGER */ + +#define ADXL367_CONFIG(inst) \ + .odr = DT_INST_PROP(inst, odr), \ + .autosleep = false, \ + .low_noise = false, \ + .temp_en = true, \ + .range = ADXL367_2G_RANGE, \ + .activity_th.value = CONFIG_ADXL367_ACTIVITY_THRESHOLD, \ + .activity_th.referenced = \ + IS_ENABLED(CONFIG_ADXL367_REFERENCED_ACTIVITY_DETECTION_MODE), \ + .activity_th.enable = \ + IS_ENABLED(CONFIG_ADXL367_ACTIVITY_DETECTION_MODE), \ + .activity_time = CONFIG_ADXL367_ACTIVITY_TIME, \ + .inactivity_th.value = CONFIG_ADXL367_INACTIVITY_THRESHOLD, \ + .inactivity_th.referenced = \ + IS_ENABLED(CONFIG_ADXL367_REFERENCED_INACTIVITY_DETECTION_MODE),\ + .inactivity_th.enable = \ + IS_ENABLED(CONFIG_ADXL367_INACTIVITY_DETECTION_MODE), \ + .inactivity_time = CONFIG_ADXL367_INACTIVITY_TIME, \ + .fifo_config.fifo_mode = ADXL367_FIFO_DISABLED, \ + .fifo_config.fifo_format = ADXL367_FIFO_FORMAT_XYZ, \ + .fifo_config.fifo_samples = 128, \ + .fifo_config.fifo_read_mode = ADXL367_14B_CHID, \ + .op_mode = ADXL367_MEASURE, + +/* + * Instantiation macros used when a device is on a SPI bus. + */ + +#define ADXL367_CONFIG_SPI(inst) \ + { \ + .bus_init = adxl367_spi_init, \ + .spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8) | \ + SPI_TRANSFER_MSB, 0), \ + ADXL367_CONFIG(inst) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + (ADXL367_CFG_IRQ(inst)), ()) \ + } + +#define ADXL367_DEFINE_SPI(inst) \ + static struct adxl367_data adxl367_data_##inst; \ + static const struct adxl367_dev_config adxl367_config_##inst = \ + ADXL367_CONFIG_SPI(inst); \ + ADXL367_DEVICE_INIT(inst) + +/* + * Instantiation macros used when a device is on an I2C bus. + */ + +#define ADXL367_CONFIG_I2C(inst) \ + { \ + .bus_init = adxl367_i2c_init, \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + ADXL367_CONFIG(inst) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + (ADXL367_CFG_IRQ(inst)), ()) \ + } + +#define ADXL367_DEFINE_I2C(inst) \ + static struct adxl367_data adxl367_data_##inst; \ + static const struct adxl367_dev_config adxl367_config_##inst = \ + ADXL367_CONFIG_I2C(inst); \ + ADXL367_DEVICE_INIT(inst) +/* + * Main instantiation macro. Use of COND_CODE_1() selects the right + * bus-specific macro at preprocessor time. + */ + +#define ADXL367_DEFINE(inst) \ + COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ + (ADXL367_DEFINE_SPI(inst)), \ + (ADXL367_DEFINE_I2C(inst))) + +DT_INST_FOREACH_STATUS_OKAY(ADXL367_DEFINE) diff --git a/drivers/sensor/adxl367/adxl367.h b/drivers/sensor/adxl367/adxl367.h new file mode 100644 index 000000000000000..8cef47420bbd82c --- /dev/null +++ b/drivers/sensor/adxl367/adxl367.h @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_ADXL367_ADXL367_H_ +#define ZEPHYR_DRIVERS_SENSOR_ADXL367_ADXL367_H_ + +#include +#include +#include +#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) */ + +/* + * ADXL367 registers definition + */ +#define ADXL367_DEVID 0x00u /* Analog Devices accelerometer ID */ +#define ADXL367_DEVID_MST 0x01u /* Analog Devices MEMS device ID */ +#define ADXL367_PART_ID 0x02u /* Device ID */ +#define ADXL367_REV_ID 0x03u /* product revision ID*/ +#define ADXL367_SERIAL_NR_3 0x04u /* Serial Number 3 */ +#define ADXL367_SERIAL_NR_2 0x05u /* Serial Number 2 */ +#define ADXL367_SERIAL_NR_1 0x06u /* Serial Number 1 */ +#define ADXL367_SERIAL_NR_0 0x07u /* Serial Number 0 */ +#define ADXL367_XDATA 0x08u /* X-axis acceleration data [13:6] */ +#define ADXL367_YDATA 0x09u /* Y-axis acceleration data [13:6] */ +#define ADXL367_ZDATA 0x0Au /* Z-axis acceleration data [13:6] */ +#define ADXL367_STATUS 0x0Bu /* Status */ +#define ADXL367_FIFO_ENTRIES_L 0x0Cu /* FIFO Entries Low */ +#define ADXL367_FIFO_ENTRIES_H 0x0Du /* FIFO Entries High */ +#define ADXL367_X_DATA_H 0x0Eu /* X-axis acceleration data [13:6] */ +#define ADXL367_X_DATA_L 0x0Fu /* X-axis acceleration data [5:0] */ +#define ADXL367_Y_DATA_H 0x10u /* Y-axis acceleration data [13:6] */ +#define ADXL367_Y_DATA_L 0x11u /* Y-axis acceleration data [5:0] */ +#define ADXL367_Z_DATA_H 0x12u /* Z-axis acceleration data [13:6] */ +#define ADXL367_Z_DATA_L 0x13u /* Z-axis acceleration data [5:0] */ +#define ADXL367_TEMP_H 0x14u /* Temperate data [13:6] */ +#define ADXL367_TEMP_L 0x15u /* Temperate data [5:0] */ +#define ADXL367_EX_ADC_H 0x16u /* Extended ADC data [13:6] */ +#define ADXL367_EX_ADC_L 0x17u /* Extended ADC data [5:0] */ +#define ADXL367_I2C_FIFO_DATA 0x18u /* I2C FIFO Data address */ +#define ADXL367_SOFT_RESET 0x1Fu /* Software reset register */ +#define ADXL367_THRESH_ACT_H 0x20u /* Activity Threshold [12:6] */ +#define ADXL367_THRESH_ACT_L 0x21u /* Activity Threshold [5:0] */ +#define ADXL367_TIME_ACT 0x22u /* Activity Time */ +#define ADXL367_THRESH_INACT_H 0x23u /* Inactivity Threshold [12:6] */ +#define ADXL367_THRESH_INACT_L 0x24u /* Inactivity Threshold [5:0] */ +#define ADXL367_TIME_INACT_H 0x25u /* Inactivity Time [12:6] */ +#define ADXL367_TIME_INACT_L 0x26u /* Inactivity Time [5:0] */ +#define ADXL367_ACT_INACT_CTL 0x27u /* Activity Inactivity Control */ +#define ADXL367_FIFO_CONTROL 0x28u /* FIFO Control */ +#define ADXL367_FIFO_SAMPLES 0x29u /* FIFO Samples */ +#define ADXL367_INTMAP1_LOWER 0x2Au /* Interrupt 1 mapping control lower */ +#define ADXL367_INTMAP2_LOWER 0x2Bu /* Interrupt 2 mapping control lower */ +#define ADXL367_FILTER_CTL 0x2Cu /* Filter Control register */ +#define ADXL367_POWER_CTL 0x2Du /* Power Control register */ +#define ADXL367_SELF_TEST 0x2Eu /* Self Test */ +#define ADXL367_TAP_THRESH 0x2Fu /* Tap Threshold */ +#define ADXL367_TAP_DUR 0x30u /* Tap Duration */ +#define ADXL367_TAP_LATENT 0x31u /* Tap Latency */ +#define ADXL367_TAP_WINDOW 0x32u /* Tap Window */ +#define ADXL367_X_OFFSET 0x33u /* X-axis offset */ +#define ADXL367_Y_OFFSET 0x34u /* Y-axis offset */ +#define ADXL367_Z_OFFSET 0x35u /* Z-axis offset */ +#define ADXL367_X_SENS 0x36u /* X-axis user sensitivity */ +#define ADXL367_Y_SENS 0x37u /* Y-axis user sensitivity */ +#define ADXL367_Z_SENS 0x38u /* Z-axis user sensitivity */ +#define ADXL367_TIMER_CTL 0x39u /* Timer Control */ +#define ADXL367_INTMAP1_UPPER 0x3Au /* Interrupt 1 mapping control upper */ +#define ADXL367_INTMAP2_UPPER 0x3Bu /* Interrupt 2 mapping control upper */ +#define ADXL367_ADC_CTL 0x3Cu /* ADC Control Register */ +#define ADXL367_TEMP_CTL 0x3Du /* Temperature Control Register */ +#define ADXL367_TEMP_ADC_OTH_H 0x3Eu /* Temperature ADC Over Threshold [12:6]*/ +#define ADXL367_TEMP_ADC_OTH_L 0x3Fu /* Temperature ADC Over Threshold [5:0]*/ +#define ADXL367_TEMP_ADC_UTH_H 0x40u /* Temperature ADC Under Threshold [12:6]*/ +#define ADXL367_TEMP_ADC_UTH_L 0x41u /* Temperature ADC Under Threshold [5:0]*/ +#define ADXL367_TEMP_ADC_TIMER 0x42u /* Temperature Activiy Inactivity Timer */ +#define ADXL367_AXIS_MASK 0x43u /* Axis Mask Register */ +#define ADXL367_STATUS_COPY 0x44u /* Status Copy Register */ +#define ADXL367_STATUS2 0x45u /* Status 2 Register */ + +#define ADXL367_DEVID_VAL 0xADu /* Analog Devices accelerometer ID */ +#define ADXL367_MST_DEVID_VAL 0x1Du /* Analog Devices MEMS device ID */ +#define ADXL367_PARTID_VAL 0xF7u /* Device ID */ +#define ADXL367_REVID_VAL 0x03u /* product revision ID*/ +#define ADXL367_RESET_CODE 0x52u /* Writing code 0x52 resets the device */ + +#define ADXL367_READ 0x01u +#define ADXL367_REG_READ(x) (((x & 0xFF) << 1) | ADXL367_READ) +#define ADXL367_REG_WRITE(x) ((x & 0xFF) << 1) +#define ADXL367_TO_REG(x) ((x) >> 1) +#define ADXL367_SPI_WRITE_REG 0x0Au +#define ADXL367_SPI_READ_REG 0x0Bu + +#define ADXL367_ABSOLUTE 0x00 +#define ADXL367_REFERENCED 0x01 + +/* ADXL367_POWER_CTL */ +#define ADXL367_POWER_CTL_EXT_CLK_MSK BIT(6) +#define ADXL367_POWER_CTL_NOISE_MSK GENMASK(5, 4) +#define ADXL367_POWER_CTL_WAKEUP_MSK BIT(3) +#define ADXL367_POWER_CTL_AUTOSLEEP_MSK BIT(2) +#define ADXL367_POWER_CTL_MEASURE_MSK GENMASK(1, 0) + +/* ADXL367_ACT_INACT_CTL */ +#define ADXL367_ACT_INACT_CTL_LINKLOOP_MSK GENMASK(5, 4) +#define ADXL367_ACT_INACT_CTL_INACT_REF_MSK BIT(3) +#define ADXL367_ACT_INACT_CTL_INACT_EN_MSK BIT(2) +#define ADXL367_ACT_INACT_CTL_ACT_REF_MSK BIT(1) +#define ADXL367_ACT_INACT_CTL_ACT_EN_MSK BIT(0) + +/* ADXL367_ACT_INACT_CTL_INACT_EN options */ +#define ADXL367_NO_INACTIVITY_DETECTION_ENABLED 0x0 +#define ADXL367_INACTIVITY_ENABLE 0x1 +#define ADXL367_NO_INACTIVITY_DETECTION_ENABLED_2 0x2 +#define ADXL367_REFERENCED_INACTIVITY_ENABLE 0x3 + +/* ADXL367_ACT_INACT_CTL_ACT_EN options */ +#define ADXL367_NO_ACTIVITY_DETECTION 0x0 +#define ADXL367_ACTIVITY_ENABLE 0x1 +#define ADXL367_NO_ACTIVITY_DETECTION_2 0x2 +#define ADXL367_REFERENCED_ACTIVITY_ENABLE 0x3 + +#define ADXL367_TEMP_OFFSET 1185 +#define ADXL367_TEMP_25C 165 +#define ADXL367_TEMP_SCALE 18518518LL +#define ADXL367_TEMP_SCALE_DIV 1000000000 + +#define ADXL367_THRESH_H_MSK GENMASK(6, 0) +#define ADXL367_THRESH_L_MSK GENMASK(7, 2) + +/* ADXL367_REG_TEMP_CTL definitions. */ +#define ADXL367_TEMP_INACT_EN_MSK BIT(3) +#define ADXL367_TEMP_ACT_EN_MSK BIT(1) +#define ADXL367_TEMP_EN_MSK BIT(0) + +/* ADXL367_SELF_TEST */ +#define ADXL367_SELF_TEST_ST_FORCE_MSK BIT(1) +#define ADXL367_SELF_TEST_ST_MSK BIT(0) + +/* ADXL367_REG_FILTER_CTL definitions */ +#define ADXL367_FILTER_CTL_RANGE_MSK GENMASK(7, 6) +#define ADXL367_FILTER_I2C_HS BIT(5) +#define ADXL367_FILTER_CTL_RES BIT(4) +#define ADXL367_FILTER_CTL_EXT_SAMPLE BIT(3) +#define ADXL367_FILTER_CTL_ODR_MSK GENMASK(2, 0) + +/* ADXL367_REG_FIFO_CONTROL */ +#define ADXL367_FIFO_CONTROL_FIFO_CHANNEL_MSK GENMASK(6, 3) +#define ADXL367_FIFO_CONTROL_FIFO_SAMPLES_MSK BIT(2) +#define ADXL367_FIFO_CONTROL_FIFO_MODE_MSK GENMASK(1, 0) + +/* ADXL367_REG_ADC_CTL definitions. */ +#define ADXL367_FIFO_8_12BIT_MSK GENMASK(7, 6) +#define ADXL367_ADC_INACT_EN BIT(3) +#define ADXL367_ADC_ACT_EN BIT(1) +#define ADXL367_ADC_EN BIT(0) + +/* ADXL367_REG_STATUS definitions */ +#define ADXL367_STATUS_ERR_USER_REGS BIT(7) +#define ADXL367_STATUS_AWAKE BIT(6) +#define ADXL367_STATUS_INACT BIT(5) +#define ADXL367_STATUS_ACT BIT(4) +#define ADXL367_STATUS_FIFO_OVERRUN BIT(3) +#define ADXL367_STATUS_FIFO_WATERMARK BIT(2) +#define ADXL367_STATUS_FIFO_RDY BIT(1) +#define ADXL367_STATUS_DATA_RDY BIT(0) + +/* ADXL367_INTMAP_LOWER */ +#define ADXL367_INT_LOW BIT(7) +#define ADXL367_AWAKE_INT BIT(6) +#define ADXL367_INACT_INT BIT(5) +#define ADXL367_ACT_INT BIT(4) +#define ADXL367_FIFO_OVERRUN BIT(3) +#define ADXL367_FIFO_WATERMARK BIT(2) +#define ADXL367_FIFO_RDY BIT(1) +#define ADXL367_DATA_RDY BIT(0) + +/* ADXL367_INTMAP_UPPER */ +#define ADXL367_ERR_FUSE BIT(7) +#define ADXL367_ERR_USER_REGS BIT(6) +#define ADXL367_KPALV_TIMER BIT(4) +#define ADXL367_TEMP_ADC_HI BIT(3) +#define ADXL367_TEMP_ADC_LOW BIT(2) +#define ADXL367_TAP_TWO BIT(1) +#define ADXL367_TAP_ONE BIT(0) + +/* Min change = 90mg. Sensitivity = 4LSB / mg */ +#define ADXL367_SELF_TEST_MIN (90 * 100 / 25) +/* Max change = 270mg. Sensitivity = 4LSB / mg */ +#define ADXL367_SELF_TEST_MAX (270 * 100 / 25) + +enum adxl367_axis { + ADXL367_X_AXIS, + ADXL367_Y_AXIS, + ADXL367_Z_AXIS +}; + +enum adxl367_op_mode { + ADXL367_STANDBY = 0, + ADXL367_MEASURE = 2, +}; + +enum adxl367_range { + ADXL367_2G_RANGE, + ADXL367_4G_RANGE, + ADXL367_8G_RANGE, +}; + +enum adxl367_act_proc_mode { + ADXL367_DEFAULT = 0, + ADXL367_LINKED = 1, + ADXL367_LOOPED = 3, +}; + +enum adxl367_odr { + ADXL367_ODR_12P5HZ, + ADXL367_ODR_25HZ, + ADXL367_ODR_50HZ, + ADXL367_ODR_100HZ, + ADXL367_ODR_200HZ, + ADXL367_ODR_400HZ, +}; + +enum adxl367_fifo_format { + ADXL367_FIFO_FORMAT_XYZ, + ADXL367_FIFO_FORMAT_X, + ADXL367_FIFO_FORMAT_Y, + ADXL367_FIFO_FORMAT_Z, + ADXL367_FIFO_FORMAT_XYZT, + ADXL367_FIFO_FORMAT_XT, + ADXL367_FIFO_FORMAT_YT, + ADXL367_FIFO_FORMAT_ZT, + ADXL367_FIFO_FORMAT_XYZA, + ADXL367_FIFO_FORMAT_XA, + ADXL367_FIFO_FORMAT_YA, + ADXL367_FIFO_FORMAT_ZA +}; + +enum adxl367_fifo_mode { + ADXL367_FIFO_DISABLED, + ADXL367_OLDEST_SAVED, + ADXL367_STREAM_MODE, + ADXL367_TRIGGERED_MODE +}; + +enum adxl367_fifo_read_mode { + ADXL367_12B_CHID, + ADXL367_8B, + ADXL367_12B, + ADXL367_14B_CHID +}; + +struct adxl367_fifo_config { + enum adxl367_fifo_mode fifo_mode; + enum adxl367_fifo_format fifo_format; + enum adxl367_fifo_read_mode fifo_read_mode; + uint16_t fifo_samples; +}; + +struct adxl367_activity_threshold { + uint16_t value; + bool referenced; + bool enable; +}; + +struct adxl367_xyz_accel_data { + int16_t x; + int16_t y; + int16_t z; +}; + +struct adxl367_transfer_function { + int (*read_reg_multiple)(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint16_t len); + int (*write_reg)(const struct device *dev, uint8_t reg_addr, + uint8_t value); + int (*read_reg)(const struct device *dev, uint8_t reg_addr, + uint8_t *value); + int (*write_reg_mask)(const struct device *dev, uint8_t reg_addr, + uint32_t mask, uint8_t value); +}; + +struct adxl367_data { + struct adxl367_xyz_accel_data sample; + int16_t temp_val; + const struct adxl367_transfer_function *hw_tf; + struct adxl367_fifo_config fifo_config; + enum adxl367_act_proc_mode act_proc_mode; + enum adxl367_range range; +#ifdef CONFIG_ADXL367_TRIGGER + struct gpio_callback gpio_cb; + + sensor_trigger_handler_t th_handler; + const struct sensor_trigger *th_trigger; + sensor_trigger_handler_t drdy_handler; + const struct sensor_trigger *drdy_trigger; + const struct device *dev; + +#if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_ADXL367_THREAD_STACK_SIZE); + struct k_sem gpio_sem; + struct k_thread thread; +#elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif +#endif /* CONFIG_ADXL367_TRIGGER */ +}; + +struct adxl367_dev_config { +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + struct i2c_dt_spec i2c; +#endif +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + struct spi_dt_spec spi; +#endif + int (*bus_init)(const struct device *dev); + +#ifdef CONFIG_ADXL367_TRIGGER + struct gpio_dt_spec interrupt; +#endif + + enum adxl367_odr odr; + + /* Device Settings */ + bool autosleep; + bool low_noise; + bool temp_en; + + struct adxl367_activity_threshold activity_th; + struct adxl367_activity_threshold inactivity_th; + struct adxl367_fifo_config fifo_config; + + enum adxl367_range range; + enum adxl367_op_mode op_mode; + + uint16_t inactivity_time; + uint8_t activity_time; +}; + +int adxl367_spi_init(const struct device *dev); +int adxl367_i2c_init(const struct device *dev); +int adxl367_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int adxl367_init_interrupt(const struct device *dev); + +#endif /* ZEPHYR_DRIVERS_SENSOR_ADXL367_ADXL367_H_ */ diff --git a/drivers/sensor/adxl367/adxl367_i2c.c b/drivers/sensor/adxl367/adxl367_i2c.c new file mode 100644 index 000000000000000..762334ad8dafd2e --- /dev/null +++ b/drivers/sensor/adxl367/adxl367_i2c.c @@ -0,0 +1,103 @@ +/* adxl367_i2c.c - I2C routines for ADXL367 driver + */ + +/* + * Copyright (c) 2023 Analog Devices + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_adxl367 + +#include +#include + +#include "adxl367.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + +LOG_MODULE_DECLARE(ADXL367, CONFIG_SENSOR_LOG_LEVEL); + +static int adxl367_bus_access(const struct device *dev, uint8_t reg, + void *data, size_t length) +{ + const struct adxl367_dev_config *config = dev->config; + + if ((reg & ADXL367_READ) != 0) { + return i2c_burst_read_dt(&config->i2c, + ADXL367_TO_REG(reg), + (uint8_t *) data, length); + } else { + if (length != 1) + return -EINVAL; + + return i2c_reg_write_byte_dt(&config->i2c, + ADXL367_TO_REG(reg), + *(uint8_t *)data); + } +} + +static int adxl367_i2c_reg_read(const struct device *dev, uint8_t reg_addr, + uint8_t *reg_data) +{ + return adxl367_bus_access(dev, ADXL367_REG_READ(reg_addr), reg_data, 1); +} + +static int adxl367_i2c_reg_read_multiple(const struct device *dev, + uint8_t reg_addr, + uint8_t *reg_data, + uint16_t count) +{ + return adxl367_bus_access(dev, ADXL367_REG_READ(reg_addr), + reg_data, count); +} + +static int adxl367_i2c_reg_write(const struct device *dev, + uint8_t reg_addr, + uint8_t reg_data) +{ + return adxl367_bus_access(dev, ADXL367_REG_WRITE(reg_addr), + ®_data, 1); +} + + +int adxl367_i2c_reg_write_mask(const struct device *dev, + uint8_t reg_addr, + uint32_t mask, + uint8_t data) +{ + int ret; + uint8_t tmp; + + ret = adxl367_i2c_reg_read(dev, reg_addr, &tmp); + if (ret != 0) { + return ret; + } + + tmp &= ~mask; + tmp |= data; + + return adxl367_i2c_reg_write(dev, reg_addr, tmp); +} + +static const struct adxl367_transfer_function adxl367_i2c_transfer_fn = { + .read_reg_multiple = adxl367_i2c_reg_read_multiple, + .write_reg = adxl367_i2c_reg_write, + .read_reg = adxl367_i2c_reg_read, + .write_reg_mask = adxl367_i2c_reg_write_mask, +}; + +int adxl367_i2c_init(const struct device *dev) +{ + struct adxl367_data *data = dev->data; + const struct adxl367_dev_config *config = dev->config; + + data->hw_tf = &adxl367_i2c_transfer_fn; + + if (!i2c_is_ready_dt(&config->i2c)) { + return -ENODEV; + } + + return 0; +} +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ diff --git a/drivers/sensor/adxl367/adxl367_spi.c b/drivers/sensor/adxl367/adxl367_spi.c new file mode 100644 index 000000000000000..a5b9c633b68eeac --- /dev/null +++ b/drivers/sensor/adxl367/adxl367_spi.c @@ -0,0 +1,131 @@ +/* adxl367_spi.c - SPI routines for ADXL367 driver + */ + +/* + * Copyright (c) 2023 Analog Devices + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_adxl367 + +#include +#include + +#include "adxl367.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + +LOG_MODULE_DECLARE(ADXL367, CONFIG_SENSOR_LOG_LEVEL); + +static int adxl367_bus_access(const struct device *dev, uint8_t reg, + void *data, size_t length) +{ + const struct adxl367_dev_config *config = dev->config; + uint8_t rw_reg, addr_reg; + + if ((reg & ADXL367_READ) != 0) { + rw_reg = ADXL367_SPI_READ_REG; + } else { + rw_reg = ADXL367_SPI_WRITE_REG; + } + + addr_reg = ADXL367_TO_REG(reg); + + const struct spi_buf buf[3] = { + { + .buf = &rw_reg, + .len = 1 + }, { + .buf = &addr_reg, + .len = 1 + }, { + .buf = data, + .len = length + } + }; + + struct spi_buf_set tx = { + .buffers = buf, + }; + + if ((reg & ADXL367_READ) != 0) { + const struct spi_buf_set rx = { + .buffers = buf, + .count = 3 + }; + + tx.count = 2; + + return spi_transceive_dt(&config->spi, &tx, &rx); + } + + tx.count = 3; + + return spi_write_dt(&config->spi, &tx); +} + +static int adxl367_spi_reg_read(const struct device *dev, uint8_t reg_addr, + uint8_t *reg_data) +{ + return adxl367_bus_access(dev, ADXL367_REG_READ(reg_addr), reg_data, 1); +} + +static int adxl367_spi_reg_read_multiple(const struct device *dev, + uint8_t reg_addr, + uint8_t *reg_data, + uint16_t count) +{ + return adxl367_bus_access(dev, ADXL367_REG_READ(reg_addr), + reg_data, count); +} + +static int adxl367_spi_reg_write(const struct device *dev, + uint8_t reg_addr, + uint8_t reg_data) +{ + return adxl367_bus_access(dev, ADXL367_REG_WRITE(reg_addr), + ®_data, 1); +} + +int adxl367_spi_reg_write_mask(const struct device *dev, + uint8_t reg_addr, + uint32_t mask, + uint8_t data) +{ + int ret; + uint8_t tmp; + + ret = adxl367_spi_reg_read(dev, reg_addr, &tmp); + if (ret != 0) { + return ret; + } + + tmp &= ~mask; + tmp |= data; + + return adxl367_spi_reg_write(dev, reg_addr, tmp); +} + +static const struct adxl367_transfer_function adxl367_spi_transfer_fn = { + .read_reg_multiple = adxl367_spi_reg_read_multiple, + .write_reg = adxl367_spi_reg_write, + .read_reg = adxl367_spi_reg_read, + .write_reg_mask = adxl367_spi_reg_write_mask, +}; + +int adxl367_spi_init(const struct device *dev) +{ + struct adxl367_data *data = dev->data; + const struct adxl367_dev_config *config = dev->config; + + data->hw_tf = &adxl367_spi_transfer_fn; + + if (!spi_is_ready_dt(&config->spi)) { + return -ENODEV; + } + + return 0; +} + +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ diff --git a/drivers/sensor/adxl367/adxl367_trigger.c b/drivers/sensor/adxl367/adxl367_trigger.c new file mode 100644 index 000000000000000..4e86d466343cd05 --- /dev/null +++ b/drivers/sensor/adxl367/adxl367_trigger.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include "adxl367.h" + +#include +LOG_MODULE_DECLARE(ADXL367, CONFIG_SENSOR_LOG_LEVEL); + +static void adxl367_thread_cb(const struct device *dev) +{ + const struct adxl367_dev_config *cfg = dev->config; + struct adxl367_data *drv_data = dev->data; + uint8_t status; + int ret; + + /* Clear the status */ + ret = drv_data->hw_tf->read_reg(dev, ADXL367_STATUS, &status); + if (ret != 0) { + return; + } + + if (drv_data->th_handler != NULL) { + if (((FIELD_GET(ADXL367_STATUS_INACT, status)) != 0) || + (FIELD_GET(ADXL367_STATUS_ACT, status)) != 0) { + drv_data->th_handler(dev, drv_data->th_trigger); + } + } + + if ((drv_data->drdy_handler != NULL) && + (FIELD_GET(ADXL367_STATUS_DATA_RDY, status) != 0)) { + drv_data->drdy_handler(dev, drv_data->drdy_trigger); + } + + ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt, + GPIO_INT_EDGE_TO_ACTIVE); + __ASSERT(ret == 0, "Interrupt configuration failed"); +} + +static void adxl367_gpio_callback(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct adxl367_data *drv_data = + CONTAINER_OF(cb, struct adxl367_data, gpio_cb); + const struct adxl367_dev_config *cfg = drv_data->dev->config; + + gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_DISABLE); + +#if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD) + k_sem_give(&drv_data->gpio_sem); +#elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD) + k_work_submit(&drv_data->work); +#endif +} + +#if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD) +static void adxl367_thread(struct adxl367_data *drv_data) +{ + while (true) { + k_sem_take(&drv_data->gpio_sem, K_FOREVER); + adxl367_thread_cb(drv_data->dev); + } +} + +#elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD) +static void adxl367_work_cb(struct k_work *work) +{ + struct adxl367_data *drv_data = + CONTAINER_OF(work, struct adxl367_data, work); + + adxl367_thread_cb(drv_data->dev); +} +#endif + +int adxl367_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + const struct adxl367_dev_config *cfg = dev->config; + struct adxl367_data *drv_data = dev->data; + uint8_t int_mask, int_en, status; + int ret; + + ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt, + GPIO_INT_DISABLE); + if (ret != 0) { + return ret; + } + + switch (trig->type) { + case SENSOR_TRIG_THRESHOLD: + drv_data->th_handler = handler; + drv_data->th_trigger = trig; + int_mask = ADXL367_ACT_INT | ADXL367_INACT_INT; + break; + case SENSOR_TRIG_DATA_READY: + drv_data->drdy_handler = handler; + drv_data->drdy_trigger = trig; + int_mask = ADXL367_DATA_RDY; + break; + default: + LOG_ERR("Unsupported sensor trigger"); + return -ENOTSUP; + } + + if (handler != NULL) { + int_en = int_mask; + } else { + int_en = 0U; + } + + ret = drv_data->hw_tf->write_reg_mask(dev, ADXL367_INTMAP1_LOWER, int_mask, int_en); + if (ret != 0) { + return ret; + } + + /* Clear status */ + ret = drv_data->hw_tf->read_reg(dev, ADXL367_STATUS, &status); + if (ret != 0) { + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret != 0) { + return ret; + } + + return 0; +} + +int adxl367_init_interrupt(const struct device *dev) +{ + const struct adxl367_dev_config *cfg = dev->config; + struct adxl367_data *drv_data = dev->data; + int ret; + + if (!gpio_is_ready_dt(&cfg->interrupt)) { + LOG_ERR("GPIO port %s not ready", cfg->interrupt.port->name); + return -EINVAL; + } + + ret = gpio_pin_configure_dt(&cfg->interrupt, GPIO_INPUT); + if (ret != 0) { + return ret; + } + + gpio_init_callback(&drv_data->gpio_cb, + adxl367_gpio_callback, + BIT(cfg->interrupt.pin)); + + ret = gpio_add_callback(cfg->interrupt.port, &drv_data->gpio_cb); + if (ret != 0) { + LOG_ERR("Failed to set gpio callback!"); + return ret; + } + + drv_data->dev = dev; + +#if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD) + k_sem_init(&drv_data->gpio_sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&drv_data->thread, drv_data->thread_stack, + CONFIG_ADXL367_THREAD_STACK_SIZE, + (k_thread_entry_t)adxl367_thread, drv_data, + NULL, NULL, K_PRIO_COOP(CONFIG_ADXL367_THREAD_PRIORITY), + 0, K_NO_WAIT); +#elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD) + drv_data->work.handler = adxl367_work_cb; +#endif + + return 0; +} diff --git a/drivers/sensor/adxl372/adxl372.h b/drivers/sensor/adxl372/adxl372.h index 39d1959b220455a..13b4d93454b056e 100644 --- a/drivers/sensor/adxl372/adxl372.h +++ b/drivers/sensor/adxl372/adxl372.h @@ -365,14 +365,11 @@ int adxl372_i2c_init(const struct device *dev); int adxl372_get_status(const struct device *dev, uint8_t *status1, uint8_t *status2, uint16_t *fifo_entries); -int adxl372_reg_write_mask(const struct device *dev, - uint8_t reg_addr, uint32_t mask, uint8_t data); - int adxl372_trigger_set(const struct device *dev, const struct sensor_trigger *trig, sensor_trigger_handler_t handler); int adxl372_init_interrupt(const struct device *dev); -#endif /* CONFIG_ADT7420_TRIGGER */ +#endif /* CONFIG_ADXL372_TRIGGER */ #endif /* ZEPHYR_DRIVERS_SENSOR_ADXL372_ADXL372_H_ */ diff --git a/drivers/sensor/adxl372/adxl372_trigger.c b/drivers/sensor/adxl372/adxl372_trigger.c index adc3d0ba1f7a513..2d9cca6cfd869a1 100644 --- a/drivers/sensor/adxl372/adxl372_trigger.c +++ b/drivers/sensor/adxl372/adxl372_trigger.c @@ -69,8 +69,13 @@ static void adxl372_gpio_callback(const struct device *dev, } #if defined(CONFIG_ADXL372_TRIGGER_OWN_THREAD) -static void adxl372_thread(struct adxl372_data *drv_data) +static void adxl372_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct adxl372_data *drv_data = p1; + while (true) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); adxl372_thread_cb(drv_data->dev); @@ -177,7 +182,7 @@ int adxl372_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_ADXL372_THREAD_STACK_SIZE, - (k_thread_entry_t)adxl372_thread, drv_data, + adxl372_thread, drv_data, NULL, NULL, K_PRIO_COOP(CONFIG_ADXL372_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_ADXL372_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/ags10/CMakeLists.txt b/drivers/sensor/ags10/CMakeLists.txt new file mode 100644 index 000000000000000..bbc0a09038b5b63 --- /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 000000000000000..f406e29d3b7bf25 --- /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 000000000000000..e5d761bfdf451e7 --- /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 000000000000000..d3f73ccd11b8d03 --- /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 2765d70a21ee2fb..d90f8662dc51da4 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 a8ce27fd3d36415..adb237e1256c489 100644 --- a/drivers/sensor/akm09918c/akm09918c_emul.c +++ b/drivers/sensor/akm09918c/akm09918c_emul.c @@ -87,7 +87,7 @@ static int akm09918c_emul_transfer_i2c(const struct emul *target, struct i2c_msg return -EIO; } if (msgs->len < 1) { - LOG_ERR("Unexpected msg0 length %s", msgs->len); + LOG_ERR("Unexpected msg0 length %d", msgs->len); return -EIO; } @@ -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/CMakeLists.txt b/drivers/sensor/amd_sb_tsi/CMakeLists.txt new file mode 100644 index 000000000000000..e9a33c445ae0a8b --- /dev/null +++ b/drivers/sensor/amd_sb_tsi/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(sb_tsi.c) +zephyr_library_sources_ifdef(CONFIG_EMUL_AMD_SB_TSI sb_tsi_emul.c) diff --git a/drivers/sensor/amd_sb_tsi/Kconfig b/drivers/sensor/amd_sb_tsi/Kconfig new file mode 100644 index 000000000000000..93e7ddb52e1e069 --- /dev/null +++ b/drivers/sensor/amd_sb_tsi/Kconfig @@ -0,0 +1,21 @@ +# SB-TSI configuration options + +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config AMD_SB_TSI + bool "AMD SB Temperature Sensor Interface" + default y + depends on DT_HAS_AMD_SB_TSI_ENABLED + select I2C + help + Enable the driver for SB Temperature Sensor Interface. This + is an I2C temperature sensor on AMD SoCs. + +config EMUL_AMD_SB_TSI + bool "Emulator for AMD SB-TSI" + default y + depends on AMD_SB_TSI + depends on EMUL + help + Enable the hardware emulator for the AMD SB-TSI. diff --git a/drivers/sensor/amd_sb_tsi/sb_tsi.c b/drivers/sensor/amd_sb_tsi/sb_tsi.c new file mode 100644 index 000000000000000..de0b91f570d2a4a --- /dev/null +++ b/drivers/sensor/amd_sb_tsi/sb_tsi.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT amd_sb_tsi + +#include +#include +#include +#include +#include +#include +#include "sb_tsi.h" + +LOG_MODULE_REGISTER(AMD_SB_TSI, CONFIG_SENSOR_LOG_LEVEL); + +struct sb_tsi_data { + uint8_t sample_int; + uint8_t sample_dec; +}; + +struct sb_tsi_config { + struct i2c_dt_spec i2c; +}; + +static int sb_tsi_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + struct sb_tsi_data *data = dev->data; + const struct sb_tsi_config *config = dev->config; + enum pm_device_state pm_state; + int res; + + (void)pm_device_state_get(dev, &pm_state); + if (pm_state != PM_DEVICE_STATE_ACTIVE) { + return -EIO; + } + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) { + return -ENOTSUP; + } + + /* + * ReadOrder specifies the order for atomically reading the temp. + * The reset value is 0, which means reading Int latches Dec. + */ + res = i2c_reg_read_byte_dt(&config->i2c, SB_TSI_TEMP_INT, &data->sample_int); + if (res) { + return res; + } + + res = i2c_reg_read_byte_dt(&config->i2c, SB_TSI_TEMP_DEC, &data->sample_dec); + if (res) { + return res; + } + + return 0; +} + +static int sb_tsi_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct sb_tsi_data *data = dev->data; + + if (chan != SENSOR_CHAN_AMBIENT_TEMP) { + return -ENOTSUP; + } + + val->val1 = data->sample_int; + val->val2 = (data->sample_dec >> SB_TSI_TEMP_DEC_SHIFT) * + (1000000 / SB_TSI_TEMP_DEC_SCALE); + + return 0; +} + +static const struct sensor_driver_api sb_tsi_driver_api = { + .sample_fetch = sb_tsi_sample_fetch, + .channel_get = sb_tsi_channel_get, +}; + +static int sb_tsi_init(const struct device *dev) +{ + const struct sb_tsi_config *config = dev->config; + int res = 0; + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("I2C device not ready"); + return -ENODEV; + } + +#ifdef CONFIG_PM_DEVICE_RUNTIME + pm_device_init_suspended(dev); + + res = pm_device_runtime_enable(dev); + if (res) { + LOG_ERR("Failed to enable runtime power management"); + } +#endif + + return res; +} + +#ifdef CONFIG_PM_DEVICE +static int sb_tsi_pm_action(const struct device *dev, enum pm_device_action action) +{ + switch (action) { + case PM_DEVICE_ACTION_TURN_ON: + case PM_DEVICE_ACTION_RESUME: + case PM_DEVICE_ACTION_TURN_OFF: + case PM_DEVICE_ACTION_SUSPEND: + return 0; + default: + return -ENOTSUP; + } +} +#endif + +#define SB_TSI_INST(inst) \ + static struct sb_tsi_data sb_tsi_data_##inst; \ + static const struct sb_tsi_config sb_tsi_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + PM_DEVICE_DT_INST_DEFINE(inst, sb_tsi_pm_action); \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, sb_tsi_init, PM_DEVICE_DT_INST_GET(inst), \ + &sb_tsi_data_##inst, &sb_tsi_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &sb_tsi_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(SB_TSI_INST) diff --git a/drivers/sensor/amd_sb_tsi/sb_tsi.h b/drivers/sensor/amd_sb_tsi/sb_tsi.h new file mode 100644 index 000000000000000..10cb0fa28c6ad8f --- /dev/null +++ b/drivers/sensor/amd_sb_tsi/sb_tsi.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_SB_TSI_SB_TSI_H_ +#define ZEPHYR_DRIVERS_SENSOR_SB_TSI_SB_TSI_H_ + +#define SB_TSI_TEMP_INT 0x01 +#define SB_TSI_TEMP_DEC 0x10 +#define SB_TSI_TEMP_DEC_SHIFT 5 +#define SB_TSI_TEMP_DEC_SCALE 8 + +#endif diff --git a/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c b/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c new file mode 100644 index 000000000000000..1c12942c876ec9d --- /dev/null +++ b/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT amd_sb_tsi + +#include +#include +#include +#include +#include +#include +#include "sb_tsi.h" + +LOG_MODULE_DECLARE(AMD_SB_TSI, CONFIG_SENSOR_LOG_LEVEL); + +#define NUM_REGS 128 + +struct sb_tsi_emul_data { + uint8_t reg[NUM_REGS]; +}; + +static void sb_tsi_emul_set_reg(const struct emul *target, uint8_t reg, uint8_t val) +{ + struct sb_tsi_emul_data *data = target->data; + + __ASSERT_NO_MSG(reg < NUM_REGS); + data->reg[reg] = val; +} + +static uint8_t sb_tsi_emul_get_reg(const struct emul *target, uint8_t reg) +{ + struct sb_tsi_emul_data *data = target->data; + + __ASSERT_NO_MSG(reg < NUM_REGS); + return data->reg[reg]; +} + +static void sb_tsi_emul_reset(const struct emul *target) +{ + struct sb_tsi_emul_data *data = target->data; + + memset(data->reg, 0, NUM_REGS); +} + +static int sb_tsi_emul_transfer_i2c(const struct emul *target, struct i2c_msg *msgs, + int num_msgs, int addr) +{ + /* Largely copied from emul_bmi160.c */ + unsigned int val; + int reg; + + __ASSERT_NO_MSG(msgs && num_msgs); + + i2c_dump_msgs_rw(target->dev, msgs, num_msgs, addr, false); + switch (num_msgs) { + case 2: + 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; + } + reg = msgs->buf[0]; + + /* Now process the 'read' part of the message */ + msgs++; + if (msgs->flags & I2C_MSG_READ) { + switch (msgs->len) { + case 1: + val = sb_tsi_emul_get_reg(target, reg); + msgs->buf[0] = val; + break; + default: + LOG_ERR("Unexpected msg1 length %d", msgs->len); + return -EIO; + } + } else { + if (msgs->len != 1) { + LOG_ERR("Unexpected msg1 length %d", msgs->len); + } + sb_tsi_emul_set_reg(target, reg, msgs->buf[0]); + } + break; + default: + LOG_ERR("Invalid number of messages: %d", num_msgs); + return -EIO; + } + + return 0; +} + +static int sb_tsi_emul_init(const struct emul *target, const struct device *parent) +{ + sb_tsi_emul_reset(target); + return 0; +} + +static int sb_tsi_emul_set_channel(const struct emul *target, enum sensor_channel chan, + const q31_t *value, int8_t shift) +{ + struct sb_tsi_emul_data *data = target->data; + int64_t scaled_value; + int32_t millicelsius; + int32_t reg_value; + + if (chan != SENSOR_CHAN_AMBIENT_TEMP) { + return -ENOTSUP; + } + + scaled_value = (int64_t)*value << shift; + millicelsius = scaled_value * 1000 / ((int64_t)INT32_MAX + 1); + reg_value = CLAMP(millicelsius / 125, 0, 0x7ff); + + data->reg[SB_TSI_TEMP_INT] = reg_value >> 3; + data->reg[SB_TSI_TEMP_DEC] = (reg_value & 0x7) << 5; + + return 0; +} + +static int sb_tsi_emul_get_sample_range(const struct emul *target, enum sensor_channel chan, + q31_t *lower, q31_t *upper, q31_t *epsilon, int8_t *shift) +{ + if (chan != SENSOR_CHAN_AMBIENT_TEMP) { + return -ENOTSUP; + } + + *shift = 8; + *lower = 0; + *upper = (int64_t)(255.875 * ((int64_t)INT32_MAX + 1)) >> *shift; + *epsilon = (int64_t)(0.125 * ((int64_t)INT32_MAX + 1)) >> *shift; + + return 0; +} + +static const struct i2c_emul_api sb_tsi_emul_api_i2c = { + .transfer = sb_tsi_emul_transfer_i2c, +}; + +static const struct emul_sensor_backend_api sb_tsi_emul_api_sensor = { + .set_channel = sb_tsi_emul_set_channel, + .get_sample_range = sb_tsi_emul_get_sample_range, +}; + +#define SB_TSI_EMUL(n) \ + struct sb_tsi_emul_data sb_tsi_emul_data_##n; \ + EMUL_DT_INST_DEFINE(n, sb_tsi_emul_init, &sb_tsi_emul_data_##n, NULL, \ + &sb_tsi_emul_api_i2c, &sb_tsi_emul_api_sensor) + +DT_INST_FOREACH_STATUS_OKAY(SB_TSI_EMUL) diff --git a/drivers/sensor/amg88xx/amg88xx_trigger.c b/drivers/sensor/amg88xx/amg88xx_trigger.c index fa1e237edaba40f..7b8d4979ec88d5e 100644 --- a/drivers/sensor/amg88xx/amg88xx_trigger.c +++ b/drivers/sensor/amg88xx/amg88xx_trigger.c @@ -113,8 +113,13 @@ static void amg88xx_thread_cb(const struct device *dev) } #ifdef CONFIG_AMG88XX_TRIGGER_OWN_THREAD -static void amg88xx_thread(struct amg88xx_data *drv_data) +static void amg88xx_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct amg88xx_data *drv_data = p1; + while (42) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); amg88xx_thread_cb(drv_data->dev); @@ -196,7 +201,7 @@ int amg88xx_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_AMG88XX_THREAD_STACK_SIZE, - (k_thread_entry_t)amg88xx_thread, drv_data, + amg88xx_thread, drv_data, NULL, NULL, K_PRIO_COOP(CONFIG_AMG88XX_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_AMG88XX_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/bma280/bma280_trigger.c b/drivers/sensor/bma280/bma280_trigger.c index a20ce6dc85327be..5c39950b49feb71 100644 --- a/drivers/sensor/bma280/bma280_trigger.c +++ b/drivers/sensor/bma280/bma280_trigger.c @@ -127,8 +127,13 @@ static void bma280_thread_cb(const struct device *dev) } #ifdef CONFIG_BMA280_TRIGGER_OWN_THREAD -static void bma280_thread(struct bma280_data *drv_data) +static void bma280_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct bma280_data *drv_data = p1; + while (1) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); bma280_thread_cb(drv_data->dev); @@ -281,7 +286,7 @@ int bma280_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_BMA280_THREAD_STACK_SIZE, - (k_thread_entry_t)bma280_thread, drv_data, + bma280_thread, drv_data, NULL, NULL, K_PRIO_COOP(CONFIG_BMA280_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_BMA280_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/bma4xx/CMakeLists.txt b/drivers/sensor/bma4xx/CMakeLists.txt new file mode 100644 index 000000000000000..a0151e081d61e16 --- /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 000000000000000..01a09ccdfd540d3 --- /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 000000000000000..9d8656d67aa8086 --- /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 000000000000000..0badd51b9514f4a --- /dev/null +++ b/drivers/sensor/bma4xx/bma4xx.h @@ -0,0 +1,228 @@ +/* + * 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_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_INTR_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) + +/* 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) + +/* + * 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_i2c.c b/drivers/sensor/bma4xx/bma4xx_i2c.c new file mode 100644 index 000000000000000..e21631c45fe1aff --- /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 000000000000000..708c9cc7ad0da13 --- /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/bmc150_magn/bmc150_magn_trigger.c b/drivers/sensor/bmc150_magn/bmc150_magn_trigger.c index c51d965bc51f261..230b5daa8ae66b6 100644 --- a/drivers/sensor/bmc150_magn/bmc150_magn_trigger.c +++ b/drivers/sensor/bmc150_magn/bmc150_magn_trigger.c @@ -81,8 +81,12 @@ static void bmc150_magn_gpio_drdy_callback(const struct device *dev, k_sem_give(&data->sem); } -static void bmc150_magn_thread_main(struct bmc150_magn_data *data) +static void bmc150_magn_thread_main(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct bmc150_magn_data *data = p1; const struct bmc150_magn_config *config = data->dev->config; uint8_t reg_val; @@ -145,7 +149,7 @@ int bmc150_magn_init_interrupt(const struct device *dev) k_thread_create(&data->thread, data->thread_stack, CONFIG_BMC150_MAGN_TRIGGER_THREAD_STACK, - (k_thread_entry_t)bmc150_magn_thread_main, + bmc150_magn_thread_main, data, NULL, NULL, K_PRIO_COOP(10), 0, K_NO_WAIT); diff --git a/drivers/sensor/bmg160/bmg160_trigger.c b/drivers/sensor/bmg160/bmg160_trigger.c index c4c7696cf3e5f89..dc6946e7ee91de2 100644 --- a/drivers/sensor/bmg160/bmg160_trigger.c +++ b/drivers/sensor/bmg160/bmg160_trigger.c @@ -181,8 +181,13 @@ static void bmg160_handle_int(const struct device *dev) static K_KERNEL_STACK_DEFINE(bmg160_thread_stack, CONFIG_BMG160_THREAD_STACK_SIZE); static struct k_thread bmg160_thread; -static void bmg160_thread_main(struct bmg160_device_data *bmg160) +static void bmg160_thread_main(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct bmg160_device_data *bmg160 = p1; + while (true) { k_sem_take(&bmg160->trig_sem, K_FOREVER); @@ -245,7 +250,7 @@ int bmg160_trigger_init(const struct device *dev) k_sem_init(&bmg160->trig_sem, 0, K_SEM_MAX_LIMIT); k_thread_create(&bmg160_thread, bmg160_thread_stack, CONFIG_BMG160_THREAD_STACK_SIZE, - (k_thread_entry_t)bmg160_thread_main, + bmg160_thread_main, bmg160, NULL, NULL, K_PRIO_COOP(CONFIG_BMG160_THREAD_PRIORITY), 0, K_NO_WAIT); diff --git a/drivers/sensor/bmi160/bmi160.c b/drivers/sensor/bmi160/bmi160.c index d79259c8ba2fe28..8f19cedac7809e9 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 1399d88b76c9da1..a0beb7f05bc49d6 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/bmi160_trigger.c b/drivers/sensor/bmi160/bmi160_trigger.c index 3110977427e980c..3cb870f1285d93c 100644 --- a/drivers/sensor/bmi160/bmi160_trigger.c +++ b/drivers/sensor/bmi160/bmi160_trigger.c @@ -71,8 +71,10 @@ static void bmi160_handle_interrupts(const struct device *dev) static K_KERNEL_STACK_DEFINE(bmi160_thread_stack, CONFIG_BMI160_THREAD_STACK_SIZE); static struct k_thread bmi160_thread; -static void bmi160_thread_main(struct bmi160_data *data) +static void bmi160_thread_main(void *p1, void *p2, void *p3) { + struct bmi160_data *data = p1; + while (1) { k_sem_take(&data->sem, K_FOREVER); bmi160_handle_interrupts(data->dev); @@ -276,7 +278,7 @@ int bmi160_trigger_mode_init(const struct device *dev) k_thread_create(&bmi160_thread, bmi160_thread_stack, CONFIG_BMI160_THREAD_STACK_SIZE, - (k_thread_entry_t)bmi160_thread_main, + bmi160_thread_main, data, NULL, NULL, K_PRIO_COOP(CONFIG_BMI160_THREAD_PRIORITY), 0, K_NO_WAIT); diff --git a/drivers/sensor/bmi160/emul_bmi160.c b/drivers/sensor/bmi160/emul_bmi160.c index 3870346cd301911..3ed71790fbedd2c 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 000000000000000..e16b089c4619f28 --- /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/bmi270/bmi270_trigger.c b/drivers/sensor/bmi270/bmi270_trigger.c index 1fc21b14251d5b5..656b5d23d161d65 100644 --- a/drivers/sensor/bmi270/bmi270_trigger.c +++ b/drivers/sensor/bmi270/bmi270_trigger.c @@ -85,8 +85,13 @@ static void bmi270_thread_cb(const struct device *dev) } #ifdef CONFIG_BMI270_TRIGGER_OWN_THREAD -static void bmi270_thread(struct bmi270_data *data) +static void bmi270_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct bmi270_data *data = p1; + while (1) { k_sem_take(&data->trig_sem, K_FOREVER); bmi270_thread_cb(data->dev); @@ -173,7 +178,7 @@ int bmi270_init_interrupts(const struct device *dev) #if CONFIG_BMI270_TRIGGER_OWN_THREAD k_sem_init(&data->trig_sem, 0, 1); k_thread_create(&data->thread, data->thread_stack, CONFIG_BMI270_THREAD_STACK_SIZE, - (k_thread_entry_t)bmi270_thread, data, NULL, NULL, + bmi270_thread, data, NULL, NULL, K_PRIO_COOP(CONFIG_BMI270_THREAD_PRIORITY), 0, K_NO_WAIT); #elif CONFIG_BMI270_TRIGGER_GLOBAL_THREAD k_work_init(&data->trig_work, bmi270_trig_work_cb); diff --git a/drivers/sensor/bmi323/bmi323.c b/drivers/sensor/bmi323/bmi323.c index a77e4271070073f..65bdef619ec844b 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 000000000000000..2f471fda359a0e2 --- /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 000000000000000..325276b7a97a830 --- /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 000000000000000..9989f51d0ad5b76 --- /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 000000000000000..cdbe7f7e0b8f91b --- /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 0cf52c79f17819d..13275638df5c4ec 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, @@ -321,6 +324,69 @@ static int bq27427_ccgain_quirk(const struct device *dev) return 0; } +static int bq274xx_ensure_chemistry(const struct device *dev) +{ + struct bq274xx_data *data = dev->data; + const struct bq274xx_config *const config = dev->config; + uint16_t chem_id = config->chemistry_id; + + if (chem_id == 0) { + /* No chemistry ID set, rely on the default of the device.*/ + return 0; + } + int ret; + uint16_t val; + + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_CHEM_ID); + if (ret < 0) { + LOG_ERR("Unable to write control register"); + return -EIO; + } + + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_CONTROL, &val); + if (ret < 0) { + LOG_ERR("Unable to read register"); + return -EIO; + } + + LOG_DBG("Chem ID: %04x", val); + + if (val != chem_id) { + /* Only the bq27427 has a configurable Chemistry ID. On bq27421, it depends on the + * variant of the chip, so just error out if the chemistry ID is wrong. + */ + if (data->regs != &bq27427_regs) { + LOG_ERR("Unable to confirm chemistry ID 0x%04x. Device reported 0x%04x", + chem_id, val); + return -EIO; + } + + uint16_t cmd; + + switch (val) { + case BQ27427_CHEM_ID_A: + cmd = BQ27427_CTRL_CHEM_A; + break; + case BQ27427_CHEM_ID_B: + cmd = BQ27427_CTRL_CHEM_B; + break; + case BQ27427_CHEM_ID_C: + cmd = BQ27427_CTRL_CHEM_C; + break; + default: + LOG_ERR("Unsupported chemistry ID 0x%04x", val); + return -EINVAL; + } + + ret = bq274xx_ctrl_reg_write(dev, cmd); + if (ret < 0) { + LOG_ERR("Unable to configure chemistry"); + return -EIO; + } + } + return 0; +} + static int bq274xx_gauge_configure(const struct device *dev) { const struct bq274xx_config *const config = dev->config; @@ -390,6 +456,11 @@ static int bq274xx_gauge_configure(const struct device *dev) } } + ret = bq274xx_ensure_chemistry(dev); + if (ret < 0) { + return ret; + } + ret = bq274xx_mode_cfgupdate(dev, false); if (ret < 0) { return ret; @@ -417,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: @@ -441,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: @@ -798,6 +871,7 @@ static const struct sensor_driver_api bq274xx_battery_driver_api = { .design_capacity = DT_INST_PROP(index, design_capacity), \ .taper_current = DT_INST_PROP(index, taper_current), \ .terminate_voltage = DT_INST_PROP(index, terminate_voltage), \ + .chemistry_id = DT_INST_PROP_OR(index, chemistry_id, 0), \ .lazy_loading = DT_INST_PROP(index, zephyr_lazy_load), \ }; \ \ diff --git a/drivers/sensor/bq274xx/bq274xx.h b/drivers/sensor/bq274xx/bq274xx.h index ead248a47380494..3fbf4f52f089130 100644 --- a/drivers/sensor/bq274xx/bq274xx.h +++ b/drivers/sensor/bq274xx/bq274xx.h @@ -9,6 +9,7 @@ #include #include +#include /*** General Constant ***/ #define BQ274XX_UNSEAL_KEY_A 0x8000 /* Unseal code one on BQ27441-G1A and similar */ @@ -59,6 +60,11 @@ #define BQ274XX_CTRL_EXIT_CFGUPDATE 0x0043 #define BQ274XX_CTRL_EXIT_RESIM 0x0044 +/* BQ27427 */ +#define BQ27427_CTRL_CHEM_A 0x0030 +#define BQ27427_CTRL_CHEM_B 0x0031 +#define BQ27427_CTRL_CHEM_C 0x0032 + /*** Extended Data Commands ***/ #define BQ274XX_EXT_OPCONFIG 0x3A /* OpConfig() */ #define BQ274XX_EXT_CAPACITY 0x3C /* DesignCapacity() */ @@ -119,6 +125,7 @@ struct bq274xx_config { #if defined(CONFIG_BQ274XX_PM) || defined(CONFIG_BQ274XX_TRIGGER) struct gpio_dt_spec int_gpios; #endif + uint16_t chemistry_id; bool lazy_loading; }; diff --git a/drivers/sensor/bq274xx/bq274xx_trigger.c b/drivers/sensor/bq274xx/bq274xx_trigger.c index 9b276f3b5ff25ad..40f20e8b955853a 100644 --- a/drivers/sensor/bq274xx/bq274xx_trigger.c +++ b/drivers/sensor/bq274xx/bq274xx_trigger.c @@ -31,8 +31,13 @@ static void bq274xx_handle_interrupts(const struct device *dev) static K_KERNEL_STACK_DEFINE(bq274xx_thread_stack, CONFIG_BQ274XX_THREAD_STACK_SIZE); static struct k_thread bq274xx_thread; -static void bq274xx_thread_main(struct bq274xx_data *data) +static void bq274xx_thread_main(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct bq274xx_data *data = p1; + while (1) { k_sem_take(&data->sem, K_FOREVER); bq274xx_handle_interrupts(data->dev); @@ -79,7 +84,7 @@ int bq274xx_trigger_mode_init(const struct device *dev) k_thread_create(&bq274xx_thread, bq274xx_thread_stack, CONFIG_BQ274XX_THREAD_STACK_SIZE, - (k_thread_entry_t)bq274xx_thread_main, + bq274xx_thread_main, data, NULL, NULL, K_PRIO_COOP(CONFIG_BQ274XX_THREAD_PRIORITY), 0, K_NO_WAIT); diff --git a/drivers/sensor/ccs811/ccs811_trigger.c b/drivers/sensor/ccs811/ccs811_trigger.c index 29750bd6bb37ccd..5a7ef006d0192da 100644 --- a/drivers/sensor/ccs811/ccs811_trigger.c +++ b/drivers/sensor/ccs811/ccs811_trigger.c @@ -98,8 +98,13 @@ static void gpio_callback(const struct device *dev, } #ifdef CONFIG_CCS811_TRIGGER_OWN_THREAD -static void irq_thread(struct ccs811_data *drv_data) +static void irq_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct ccs811_data *drv_data = p1; + while (1) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); process_irq(drv_data->dev); @@ -192,7 +197,7 @@ int ccs811_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_CCS811_THREAD_STACK_SIZE, - (k_thread_entry_t)irq_thread, drv_data, + irq_thread, drv_data, NULL, NULL, K_PRIO_COOP(CONFIG_CCS811_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_CCS811_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/default_rtio_sensor.c b/drivers/sensor/default_rtio_sensor.c index e088b4f61c28895..3f9377c33b35916 100644 --- a/drivers/sensor/default_rtio_sensor.c +++ b/drivers/sensor/default_rtio_sensor.c @@ -28,8 +28,10 @@ static void sensor_iodev_submit(struct rtio_iodev_sqe *iodev_sqe) if (api->submit != NULL) { api->submit(dev, iodev_sqe); - } else { + } else if (!cfg->is_streaming) { sensor_submit_fallback(dev, iodev_sqe); + } else { + rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP); } } @@ -235,7 +237,7 @@ static void sensor_submit_fallback(const struct device *dev, struct rtio_iodev_s } sample_idx += num_samples; } - LOG_DBG("Total channels in header: %u", header->num_channels); + LOG_DBG("Total channels in header: %" PRIu32, header->num_channels); rtio_iodev_sqe_ok(iodev_sqe, 0); } diff --git a/drivers/sensor/explorir_m/CMakeLists.txt b/drivers/sensor/explorir_m/CMakeLists.txt new file mode 100644 index 000000000000000..71125b505f38076 --- /dev/null +++ b/drivers/sensor/explorir_m/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(explorir_m.c) diff --git a/drivers/sensor/explorir_m/Kconfig b/drivers/sensor/explorir_m/Kconfig new file mode 100644 index 000000000000000..02806bf82a80e74 --- /dev/null +++ b/drivers/sensor/explorir_m/Kconfig @@ -0,0 +1,13 @@ +# ExplorIR-M CO2 sensor configuration options + +# Copyright (c) 2023, Vitrolife A/S +# SPDX-License-Identifier: Apache-2.0 + +config EXPLORIR_M + bool "ExplorIR-M CO2 Sensor" + default y + depends on DT_HAS_GSS_EXPLORIR_M_ENABLED + depends on UART_INTERRUPT_DRIVEN + select UART + help + Enable driver for ExplorIR-M CO2 Sensor. diff --git a/drivers/sensor/explorir_m/explorir_m.c b/drivers/sensor/explorir_m/explorir_m.c new file mode 100644 index 000000000000000..058c43faf2b4952 --- /dev/null +++ b/drivers/sensor/explorir_m/explorir_m.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2023, Vitrolife A/S + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.gassensing.co.uk/wp-content/uploads/2023/05/ExplorIR-M-Data-Sheet-Rev-4.13_3.pdf + * + */ + +#define DT_DRV_COMPAT gss_explorir_m + +#include + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(explorir_m_sensor, CONFIG_SENSOR_LOG_LEVEL); + +#define EXPLORIR_M_BEGIN_CHAR ' ' + +#define EXPLORIR_M_SET_FILTER_CHAR 'A' +#define EXPLORIR_M_GET_FILTER_CHAR 'a' +#define EXPLORIR_M_MODE_CHAR 'K' +#define EXPLORIR_M_CO2_FILTERED_CHAR 'Z' +#define EXPLORIR_M_SCALING_CHAR '.' +#define EXPLORIR_M_NOT_RECOGNISED_CHAR '?' + +#define EXPLORIR_M_SEPARATOR_CHAR ' ' +#define EXPLORIR_M_PRE_END_CHAR '\r' +#define EXPLORIR_M_END_CHAR '\n' + +#define EXPLORIR_M_TYPE_INDEX 1 +#define EXPLORIR_M_VALUE_INDEX 3 + +#define EXPLORIR_M_BUFFER_LENGTH 16 + +#define EXPLORIR_M_MAX_RESPONSE_DELAY 200 /* Add margin to the specified 100 in datasheet */ +#define EXPLORIR_M_CO2_VALID_DELAY 1200 + +struct explorir_m_data { + struct k_mutex uart_mutex; + struct k_sem uart_rx_sem; + uint16_t filtered; + uint16_t scaling; + uint8_t read_index; + uint8_t read_buffer[EXPLORIR_M_BUFFER_LENGTH]; +}; + +struct explorir_m_cfg { + const struct device *uart_dev; + uart_irq_callback_user_data_t cb; +}; + +enum explorir_m_uart_set_usage { + EXPLORIR_M_SET_NONE, + EXPLORIR_M_SET_VAL_ONE, + EXPLORIR_M_SET_VAL_ONE_TWO, +}; + +enum EXPLORIR_M_MODE { + EXPLORIR_M_MODE_COMMAND, + EXPLORIR_M_MODE_STREAM, + EXPLORIR_M_MODE_POLL, +}; + +static void explorir_m_uart_flush(const struct device *uart_dev) +{ + uint8_t tmp; + + while (uart_fifo_read(uart_dev, &tmp, 1) > 0) { + continue; + } +} + +static void explorir_m_uart_flush_until_end(const struct device *uart_dev) +{ + uint8_t tmp; + uint32_t uptime; + + uptime = k_uptime_get_32(); + do { + uart_poll_in(uart_dev, &tmp); + } while (tmp != EXPLORIR_M_END_CHAR && + k_uptime_get_32() - uptime < EXPLORIR_M_MAX_RESPONSE_DELAY); +} + +static void explorir_m_buffer_reset(struct explorir_m_data *data) +{ + memset(data->read_buffer, 0, data->read_index); + data->read_index = 0; +} + +static int explorir_m_buffer_verify(const struct explorir_m_data *data, char type) +{ + char buffer_type = data->read_buffer[EXPLORIR_M_TYPE_INDEX]; + + if (data->read_buffer[0] == EXPLORIR_M_NOT_RECOGNISED_CHAR) { + LOG_WRN("Sensor did not recognise the command"); + return -EIO; + } + + if (buffer_type != type) { + LOG_WRN("Expected type %c but got %c", type, buffer_type); + return -EIO; + } + + if (data->read_buffer[0] != EXPLORIR_M_BEGIN_CHAR || + data->read_buffer[2] != EXPLORIR_M_SEPARATOR_CHAR || + data->read_buffer[data->read_index - 2] != EXPLORIR_M_PRE_END_CHAR) { + LOG_HEXDUMP_WRN(data->read_buffer, data->read_index, "Invalid buffer"); + return -EIO; + } + + return 0; +} + +static int explorir_m_buffer_process(struct explorir_m_data *data, char type, + struct sensor_value *val) +{ + if (explorir_m_buffer_verify(data, type) != 0) { + return -EIO; + } + + switch (type) { + case EXPLORIR_M_SET_FILTER_CHAR: + case EXPLORIR_M_MODE_CHAR: + break; + + case EXPLORIR_M_CO2_FILTERED_CHAR: + data->scaling = strtol(&data->read_buffer[EXPLORIR_M_VALUE_INDEX], NULL, 10); + break; + + case EXPLORIR_M_SCALING_CHAR: + data->filtered = strtol(&data->read_buffer[EXPLORIR_M_VALUE_INDEX], NULL, 10); + break; + + case EXPLORIR_M_GET_FILTER_CHAR: + val->val1 = strtol(&data->read_buffer[EXPLORIR_M_VALUE_INDEX], NULL, 10); + break; + + default: + LOG_ERR("Unknown type %c/0x%02x", type, type); + return -EIO; + } + + return 0; +} + +static void explorir_m_uart_isr(const struct device *uart_dev, void *user_data) +{ + const struct device *dev = user_data; + struct explorir_m_data *data = dev->data; + int rc, read_len; + + if (!device_is_ready(uart_dev)) { + LOG_DBG("UART device is not ready"); + return; + } + + if (!uart_irq_update(uart_dev)) { + LOG_DBG("Unable to process interrupts"); + return; + } + + if (!uart_irq_rx_ready(uart_dev)) { + LOG_DBG("No RX data"); + return; + } + + read_len = EXPLORIR_M_BUFFER_LENGTH - data->read_index; + rc = uart_fifo_read(uart_dev, &data->read_buffer[data->read_index], read_len); + + if (rc < 0 || rc == read_len) { + LOG_ERR("UART read failed: %d", rc < 0 ? rc : -ERANGE); + explorir_m_uart_flush(uart_dev); + LOG_HEXDUMP_WRN(data->read_buffer, data->read_index, "Discarding"); + explorir_m_buffer_reset(data); + } else { + data->read_index += rc; + + if (data->read_buffer[data->read_index - 1] != EXPLORIR_M_END_CHAR) { + return; + } + } + + k_sem_give(&data->uart_rx_sem); +} + +static void explorir_m_uart_terminate(const struct device *uart_dev) +{ + uart_poll_out(uart_dev, EXPLORIR_M_PRE_END_CHAR); + uart_poll_out(uart_dev, EXPLORIR_M_END_CHAR); +} + +static int explorir_m_await_receive(struct explorir_m_data *data) +{ + int rc = k_sem_take(&data->uart_rx_sem, K_MSEC(EXPLORIR_M_MAX_RESPONSE_DELAY)); + + /* Reset semaphore if sensor did not respond within maximum specified response time */ + if (rc == -EAGAIN) { + k_sem_reset(&data->uart_rx_sem); + } + + return rc; +} + +static int explorir_m_uart_transceive(const struct device *dev, char type, struct sensor_value *val, + enum explorir_m_uart_set_usage set) +{ + const struct explorir_m_cfg *cfg = dev->config; + struct explorir_m_data *data = dev->data; + char buf[EXPLORIR_M_BUFFER_LENGTH]; + int rc, len; + + if (val == NULL && set != EXPLORIR_M_SET_NONE) { + LOG_ERR("val is NULL but set is not NONE"); + return -EINVAL; + } + + k_mutex_lock(&data->uart_mutex, K_FOREVER); + + explorir_m_buffer_reset(data); + + uart_poll_out(cfg->uart_dev, type); + + if (set == EXPLORIR_M_SET_VAL_ONE) { + len = snprintf(buf, EXPLORIR_M_BUFFER_LENGTH, "%c%u", EXPLORIR_M_SEPARATOR_CHAR, + val->val1); + } else if (set == EXPLORIR_M_SET_VAL_ONE_TWO) { + len = snprintf(buf, EXPLORIR_M_BUFFER_LENGTH, "%c%u%c%u", EXPLORIR_M_SEPARATOR_CHAR, + val->val1, EXPLORIR_M_SEPARATOR_CHAR, val->val2); + } else { + len = 0; + } + + if (len == EXPLORIR_M_BUFFER_LENGTH) { + LOG_WRN("Set value truncated"); + } + for (int i = 0; i != len; i++) { + uart_poll_out(cfg->uart_dev, buf[i]); + } + + explorir_m_uart_terminate(cfg->uart_dev); + + rc = explorir_m_await_receive(data); + if (rc != 0) { + LOG_WRN("%c did not receive a response: %d", type, rc); + } + + if (rc == 0) { + rc = explorir_m_buffer_process(data, type, val); + } + + k_mutex_unlock(&data->uart_mutex); + + return rc; +} + +static int explorir_m_attr_get(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, struct sensor_value *val) +{ + if (chan != SENSOR_CHAN_CO2) { + return -ENOTSUP; + } + + switch (attr) { + case SENSOR_ATTR_EXPLORIR_M_FILTER: + return explorir_m_uart_transceive(dev, EXPLORIR_M_GET_FILTER_CHAR, val, + EXPLORIR_M_SET_NONE); + default: + return -ENOTSUP; + } +} + +static int explorir_m_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + if (chan != SENSOR_CHAN_CO2) { + return -ENOTSUP; + } + + switch (attr) { + case SENSOR_ATTR_EXPLORIR_M_FILTER: + if (val->val1 < 0 || val->val1 > 255) { + return -ERANGE; + } + return explorir_m_uart_transceive(dev, EXPLORIR_M_SET_FILTER_CHAR, + (struct sensor_value *)val, + EXPLORIR_M_SET_VAL_ONE); + default: + return -ENOTSUP; + } +} + +static int explorir_m_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + if (chan != SENSOR_CHAN_CO2 && chan != SENSOR_CHAN_ALL) { + return -ENOTSUP; + } + + return explorir_m_uart_transceive(dev, EXPLORIR_M_CO2_FILTERED_CHAR, NULL, + EXPLORIR_M_SET_NONE); +} + +static int explorir_m_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct explorir_m_data *data = dev->data; + + if (chan != SENSOR_CHAN_CO2) { + return -ENOTSUP; + } + + if (k_uptime_get() < EXPLORIR_M_CO2_VALID_DELAY) { + return -EAGAIN; + } + + val->val1 = data->filtered * data->scaling; + val->val2 = 0; + + return 0; +} + +static const struct sensor_driver_api explorir_m_api_funcs = { + .attr_set = explorir_m_attr_set, + .attr_get = explorir_m_attr_get, + .sample_fetch = explorir_m_sample_fetch, + .channel_get = explorir_m_channel_get, +}; + +static int explorir_m_init(const struct device *dev) +{ + const struct explorir_m_cfg *cfg = dev->config; + struct explorir_m_data *data = dev->data; + struct sensor_value val; + int rc; + + LOG_DBG("Initializing %s", dev->name); + + if (!device_is_ready(cfg->uart_dev)) { + return -ENODEV; + } + + k_mutex_init(&data->uart_mutex); + k_sem_init(&data->uart_rx_sem, 0, 1); + + uart_irq_rx_disable(cfg->uart_dev); + uart_irq_tx_disable(cfg->uart_dev); + + rc = uart_irq_callback_user_data_set(cfg->uart_dev, cfg->cb, (void *)dev); + if (rc != 0) { + LOG_ERR("UART IRQ setup failed: %d", rc); + return rc; + } + + /* Terminate garbled tx due to GPIO setup or crash during unfinished send */ + explorir_m_uart_terminate(cfg->uart_dev); + explorir_m_uart_flush_until_end(cfg->uart_dev); + + uart_irq_rx_enable(cfg->uart_dev); + + val.val1 = EXPLORIR_M_MODE_POLL; + explorir_m_uart_transceive(dev, EXPLORIR_M_MODE_CHAR, &val, EXPLORIR_M_SET_VAL_ONE); + explorir_m_uart_transceive(dev, EXPLORIR_M_SCALING_CHAR, NULL, EXPLORIR_M_SET_NONE); + + return rc; +} + +#define EXPLORIR_M_INIT(n) \ + \ + static struct explorir_m_data explorir_m_data_##n; \ + \ + static const struct explorir_m_cfg explorir_m_cfg_##n = { \ + .uart_dev = DEVICE_DT_GET(DT_INST_BUS(n)), \ + .cb = explorir_m_uart_isr, \ + }; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, explorir_m_init, NULL, &explorir_m_data_##n, \ + &explorir_m_cfg_##n, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &explorir_m_api_funcs); + +DT_INST_FOREACH_STATUS_OKAY(EXPLORIR_M_INIT) diff --git a/drivers/sensor/f75303/f75303_emul.c b/drivers/sensor/f75303/f75303_emul.c index 3e33a7b6f7b2e54..5bab9cd429466e0 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/fdc2x1x/fdc2x1x_trigger.c b/drivers/sensor/fdc2x1x/fdc2x1x_trigger.c index 61697d24605ca63..519d5af0d61e2a5 100644 --- a/drivers/sensor/fdc2x1x/fdc2x1x_trigger.c +++ b/drivers/sensor/fdc2x1x/fdc2x1x_trigger.c @@ -60,8 +60,13 @@ static void fdc2x1x_gpio_callback(const struct device *dev, } #ifdef CONFIG_FDC2X1X_TRIGGER_OWN_THREAD -static void fdc2x1x_thread(struct fdc2x1x_data *drv_data) +static void fdc2x1x_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct fdc2x1x_data *drv_data = p1; + while (true) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); fdc2x1x_thread_cb(drv_data->dev); @@ -158,7 +163,7 @@ int fdc2x1x_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_FDC2X1X_THREAD_STACK_SIZE, - (k_thread_entry_t)fdc2x1x_thread, + fdc2x1x_thread, drv_data, 0, NULL, K_PRIO_COOP(CONFIG_FDC2X1X_THREAD_PRIORITY), 0, K_NO_WAIT); diff --git a/drivers/sensor/fxas21002/fxas21002_trigger.c b/drivers/sensor/fxas21002/fxas21002_trigger.c index 966ed5e2cba0f94..b32d2f5f7d0216c 100644 --- a/drivers/sensor/fxas21002/fxas21002_trigger.c +++ b/drivers/sensor/fxas21002/fxas21002_trigger.c @@ -68,8 +68,13 @@ static void fxas21002_handle_int(const struct device *dev) } #ifdef CONFIG_FXAS21002_TRIGGER_OWN_THREAD -static void fxas21002_thread_main(struct fxas21002_data *data) +static void fxas21002_thread_main(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct fxas21002_data *data = p1; + while (true) { k_sem_take(&data->trig_sem, K_FOREVER); fxas21002_handle_int(data->dev); @@ -173,7 +178,7 @@ int fxas21002_trigger_init(const struct device *dev) k_sem_init(&data->trig_sem, 0, K_SEM_MAX_LIMIT); k_thread_create(&data->thread, data->thread_stack, CONFIG_FXAS21002_THREAD_STACK_SIZE, - (k_thread_entry_t)fxas21002_thread_main, data, 0, NULL, + fxas21002_thread_main, data, 0, NULL, K_PRIO_COOP(CONFIG_FXAS21002_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_FXAS21002_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/fxos8700/fxos8700_trigger.c b/drivers/sensor/fxos8700/fxos8700_trigger.c index d9adaf8d38f0e5a..53d493ac44ddd28 100644 --- a/drivers/sensor/fxos8700/fxos8700_trigger.c +++ b/drivers/sensor/fxos8700/fxos8700_trigger.c @@ -168,8 +168,13 @@ static void fxos8700_handle_int(const struct device *dev) } #ifdef CONFIG_FXOS8700_TRIGGER_OWN_THREAD -static void fxos8700_thread_main(struct fxos8700_data *data) +static void fxos8700_thread_main(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct fxos8700_data *data = p1; + while (true) { k_sem_take(&data->trig_sem, K_FOREVER); fxos8700_handle_int(data->dev); @@ -395,7 +400,7 @@ int fxos8700_trigger_init(const struct device *dev) k_sem_init(&data->trig_sem, 0, K_SEM_MAX_LIMIT); k_thread_create(&data->thread, data->thread_stack, CONFIG_FXOS8700_THREAD_STACK_SIZE, - (k_thread_entry_t)fxos8700_thread_main, + fxos8700_thread_main, data, NULL, NULL, K_PRIO_COOP(CONFIG_FXOS8700_THREAD_PRIORITY), 0, K_NO_WAIT); diff --git a/drivers/sensor/grow_r502a/grow_r502a_trigger.c b/drivers/sensor/grow_r502a/grow_r502a_trigger.c index 7f4e97874bdc15d..1513b896d94b69e 100644 --- a/drivers/sensor/grow_r502a/grow_r502a_trigger.c +++ b/drivers/sensor/grow_r502a/grow_r502a_trigger.c @@ -71,8 +71,13 @@ static void grow_r502a_gpio_callback(const struct device *dev, } #if defined(CONFIG_GROW_R502A_TRIGGER_OWN_THREAD) -static void grow_r502a_thread(struct grow_r502a_data *drv_data) +static void grow_r502a_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct grow_r502a_data *drv_data = p1; + while (true) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); process_int(drv_data->gpio_dev); @@ -111,7 +116,7 @@ int grow_r502a_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_GROW_R502A_THREAD_STACK_SIZE, - (k_thread_entry_t)grow_r502a_thread, drv_data, NULL, + grow_r502a_thread, drv_data, NULL, NULL, K_PRIO_COOP(CONFIG_GROW_R502A_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_GROW_R502A_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/hmc5883l/hmc5883l_trigger.c b/drivers/sensor/hmc5883l/hmc5883l_trigger.c index da73a10807c40e1..c3a1d00891cb5a6 100644 --- a/drivers/sensor/hmc5883l/hmc5883l_trigger.c +++ b/drivers/sensor/hmc5883l/hmc5883l_trigger.c @@ -78,8 +78,13 @@ static void hmc5883l_thread_cb(const struct device *dev) } #ifdef CONFIG_HMC5883L_TRIGGER_OWN_THREAD -static void hmc5883l_thread(struct hmc5883l_data *drv_data) +static void hmc5883l_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct hmc5883l_data *drv_data = p1; + while (1) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); hmc5883l_thread_cb(drv_data->dev); @@ -124,7 +129,7 @@ int hmc5883l_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_HMC5883L_THREAD_STACK_SIZE, - (k_thread_entry_t)hmc5883l_thread, + hmc5883l_thread, drv_data, NULL, NULL, K_PRIO_COOP(CONFIG_HMC5883L_THREAD_PRIORITY), 0, K_NO_WAIT); diff --git a/drivers/sensor/hs300x/CMakeLists.txt b/drivers/sensor/hs300x/CMakeLists.txt new file mode 100644 index 000000000000000..f937e6bb6f11b3e --- /dev/null +++ b/drivers/sensor/hs300x/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(hs300x.c) diff --git a/drivers/sensor/hs300x/Kconfig b/drivers/sensor/hs300x/Kconfig new file mode 100644 index 000000000000000..53060cb5c217efd --- /dev/null +++ b/drivers/sensor/hs300x/Kconfig @@ -0,0 +1,12 @@ +# Renesas HS300x temperature and humidity sensor configuration options + +# Copyright (c) 2023 Ian Morris +# SPDX-License-Identifier: Apache-2.0 + +config HS300X + bool "HS300x Temperature and Humidity Sensor" + default y + depends on DT_HAS_RENESAS_HS300X_ENABLED + select I2C + help + Enable driver for HS300x temperature and humidity sensors. diff --git a/drivers/sensor/hs300x/hs300x.c b/drivers/sensor/hs300x/hs300x.c new file mode 100644 index 000000000000000..9faabbb1e352092 --- /dev/null +++ b/drivers/sensor/hs300x/hs300x.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2023 Ian Morris + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_hs300x + +#include +#include +#include +#include +#include +#include +#include + +#define HS300X_STATUS_MASK (BIT(0) | BIT(1)) + +LOG_MODULE_REGISTER(HS300X, CONFIG_SENSOR_LOG_LEVEL); + +struct hs300x_config { + struct i2c_dt_spec bus; +}; + +struct hs300x_data { + int16_t t_sample; + uint16_t rh_sample; +}; + +static int hs300x_read_sample(const struct device *dev, uint16_t *t_sample, uint16_t *rh_sample) +{ + const struct hs300x_config *cfg = dev->config; + uint8_t rx_buf[4]; + int rc; + + rc = i2c_read_dt(&cfg->bus, rx_buf, sizeof(rx_buf)); + if (rc < 0) { + LOG_ERR("Failed to read data from device."); + return rc; + } + + if ((rx_buf[3] & HS300X_STATUS_MASK) != 0) { + LOG_ERR("Stale data"); + return -EIO; + } + + *rh_sample = sys_get_be16(rx_buf); + *t_sample = sys_get_be16(&rx_buf[2]); + + /* Remove status bits (only present in temperature value)*/ + *t_sample >>= 2; + + return 0; +} + +static int hs300x_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct hs300x_data *data = dev->data; + const struct hs300x_config *cfg = dev->config; + int rc; + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP && + chan != SENSOR_CHAN_HUMIDITY) { + return -ENOTSUP; + } + + /* + * Initiate a measurement simply by sending 7-bit address followed + * by an eighth bit set to 0 (write) and NO data. + */ + rc = i2c_write_dt(&cfg->bus, NULL, 0); + if (rc < 0) { + LOG_ERR("Failed to start measurement."); + return rc; + } + + /* + * According to datasheet maximum time to make temperature and humidity + * measurements is 33ms, add a little safety margin... + */ + k_msleep(50); + + rc = hs300x_read_sample(dev, &data->t_sample, &data->rh_sample); + if (rc < 0) { + LOG_ERR("Failed to fetch data."); + return rc; + } + + return 0; +} + +static void hs300x_temp_convert(struct sensor_value *val, int16_t raw) +{ + int32_t micro_c; + + /* + * Convert to micro Celsius. See datasheet "Calculating Humidity and + * Temperature Output" section for more details on processing sample data. + */ + micro_c = (((int64_t)raw * 165000000) / 16383) - 40000000; + + val->val1 = micro_c / 1000000; + val->val2 = micro_c % 1000000; +} + +static void hs300x_rh_convert(struct sensor_value *val, uint16_t raw) +{ + int32_t micro_rh; + + /* + * Convert to micro %RH. See datasheet "Calculating Humidity and + * Temperature Output" section for more details on processing sample data. + */ + micro_rh = ((uint64_t)raw * 100000000) / 16383; + + val->val1 = micro_rh / 1000000; + val->val2 = micro_rh % 1000000; +} + +static int hs300x_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + const struct hs300x_data *data = dev->data; + + if (chan == SENSOR_CHAN_AMBIENT_TEMP) { + hs300x_temp_convert(val, data->t_sample); + } else if (chan == SENSOR_CHAN_HUMIDITY) { + hs300x_rh_convert(val, data->rh_sample); + } else { + return -ENOTSUP; + } + + return 0; +} + +static int hs300x_init(const struct device *dev) +{ + const struct hs300x_config *cfg = dev->config; + + if (!i2c_is_ready_dt(&cfg->bus)) { + LOG_ERR("I2C dev %s not ready", cfg->bus.bus->name); + return -ENODEV; + } + + return 0; +} + +static const struct sensor_driver_api hs300x_driver_api = {.sample_fetch = hs300x_sample_fetch, + .channel_get = hs300x_channel_get}; + +#define DEFINE_HS300X(n) \ + static struct hs300x_data hs300x_data_##n; \ + \ + static const struct hs300x_config hs300x_config_##n = {.bus = I2C_DT_SPEC_INST_GET(n)}; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, hs300x_init, NULL, &hs300x_data_##n, &hs300x_config_##n, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &hs300x_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DEFINE_HS300X) diff --git a/drivers/sensor/hts221/Kconfig b/drivers/sensor/hts221/Kconfig index 5c3ff69273aed57..bb2ce7d848ac73c 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/hts221/hts221_trigger.c b/drivers/sensor/hts221/hts221_trigger.c index 9019706a34b7473..1ebccb2a3c54ad5 100644 --- a/drivers/sensor/hts221/hts221_trigger.c +++ b/drivers/sensor/hts221/hts221_trigger.c @@ -95,8 +95,13 @@ static void hts221_drdy_callback(const struct device *dev, } #ifdef CONFIG_HTS221_TRIGGER_OWN_THREAD -static void hts221_thread(struct hts221_data *data) +static void hts221_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct hts221_data *data = p1; + while (1) { k_sem_take(&data->drdy_sem, K_FOREVER); process_drdy(data->dev); @@ -163,7 +168,7 @@ int hts221_init_interrupt(const struct device *dev) k_thread_create(&data->thread, data->thread_stack, CONFIG_HTS221_THREAD_STACK_SIZE, - (k_thread_entry_t)hts221_thread, data, + hts221_thread, data, NULL, NULL, K_PRIO_COOP(CONFIG_HTS221_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_HTS221_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/i3g4250d/Kconfig b/drivers/sensor/i3g4250d/Kconfig index 4a9d5b80fd6e1e8..6f9dd720a9597d7 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/CMakeLists.txt b/drivers/sensor/icm42688/CMakeLists.txt index cf9308bb95c4478..fbc63b6a4b22918 100644 --- a/drivers/sensor/icm42688/CMakeLists.txt +++ b/drivers/sensor/icm42688/CMakeLists.txt @@ -10,6 +10,7 @@ zephyr_library_sources( zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API icm42688_rtio.c) zephyr_library_sources_ifdef(CONFIG_ICM42688_DECODER icm42688_decoder.c) +zephyr_library_sources_ifdef(CONFIG_ICM42688_STREAM icm42688_rtio_stream.c) zephyr_library_sources_ifdef(CONFIG_ICM42688_TRIGGER icm42688_trigger.c) zephyr_library_sources_ifdef(CONFIG_EMUL_ICM42688 icm42688_emul.c) zephyr_include_directories_ifdef(CONFIG_EMUL_ICM42688 .) diff --git a/drivers/sensor/icm42688/Kconfig b/drivers/sensor/icm42688/Kconfig index 2944a9d1183ad41..aea3cc6480ffee4 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,27 +12,27 @@ 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 default ICM42688_TRIGGER_GLOBAL_THREAD help Specify the type of triggering to be used by the driver @@ -50,6 +50,15 @@ config ICM42688_TRIGGER_OWN_THREAD endchoice +config ICM42688_STREAM + bool "Use hardware FIFO to stream data" + select ICM42688_TRIGGER + default y + depends on SPI_RTIO + depends on SENSOR_ASYNC_API + help + Use this config option to enable streaming sensor data via RTIO subsystem. + config ICM42688_TRIGGER bool diff --git a/drivers/sensor/icm42688/icm42688.c b/drivers/sensor/icm42688/icm42688.c index 43fd6a72f47f684..a6b4cd06c521978 100644 --- a/drivers/sensor/icm42688/icm42688.c +++ b/drivers/sensor/icm42688/icm42688.c @@ -82,7 +82,7 @@ int icm42688_channel_parse_readings(enum sensor_channel chan, int16_t readings[7 } static int icm42688_channel_get(const struct device *dev, enum sensor_channel chan, - struct sensor_value *val) + struct sensor_value *val) { struct icm42688_dev_data *data = dev->data; @@ -156,6 +156,17 @@ static int icm42688_attr_set(const struct device *dev, enum sensor_channel chan, res = -EINVAL; } break; + case SENSOR_CHAN_ALL: + if (attr == SENSOR_ATTR_BATCH_DURATION) { + if (val->val1 < 0) { + return -EINVAL; + } + new_config.batch_ticks = val->val1; + } else { + LOG_ERR("Unsupported attribute"); + res = -EINVAL; + } + break; default: LOG_ERR("Unsupported channel"); res = -EINVAL; @@ -204,6 +215,15 @@ static int icm42688_attr_get(const struct device *dev, enum sensor_channel chan, res = -EINVAL; } break; + case SENSOR_CHAN_ALL: + if (attr == SENSOR_ATTR_BATCH_DURATION) { + val->val1 = cfg->batch_ticks; + val->val2 = 0; + } else { + LOG_ERR("Unsupported attribute"); + res = -EINVAL; + } + break; default: LOG_ERR("Unsupported channel"); res = -EINVAL; @@ -257,7 +277,13 @@ int icm42688_init(const struct device *dev) data->cfg.gyro_mode = ICM42688_GYRO_LN; data->cfg.gyro_fs = ICM42688_GYRO_FS_125; data->cfg.gyro_odr = ICM42688_GYRO_ODR_1000; - data->cfg.fifo_en = false; + data->cfg.temp_dis = false; + data->cfg.fifo_en = IS_ENABLED(CONFIG_ICM42688_STREAM); + data->cfg.batch_ticks = 0; + data->cfg.fifo_hires = 0; + data->cfg.interrupt1_drdy = 0; + data->cfg.interrupt1_fifo_ths = 0; + data->cfg.interrupt1_fifo_full = 0; res = icm42688_configure(dev, &data->cfg); if (res != 0) { @@ -283,8 +309,15 @@ void icm42688_unlock(const struct device *dev) #define ICM42688_SPI_CFG \ SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8) | SPI_TRANSFER_MSB +#define ICM42688_RTIO_DEFINE(inst) \ + SPI_DT_IODEV_DEFINE(icm42688_spi_iodev_##inst, DT_DRV_INST(inst), ICM42688_SPI_CFG, 0U); \ + RTIO_DEFINE(icm42688_rtio_##inst, 8, 4); + #define ICM42688_DEFINE_DATA(inst) \ - static struct icm42688_dev_data icm42688_driver_##inst; + IF_ENABLED(CONFIG_ICM42688_STREAM, (ICM42688_RTIO_DEFINE(inst))); \ + static struct icm42688_dev_data icm42688_driver_##inst = { \ + IF_ENABLED(CONFIG_ICM42688_STREAM, (.r = &icm42688_rtio_##inst, \ + .spi_iodev = &icm42688_spi_iodev_##inst,))}; #define ICM42688_INIT(inst) \ ICM42688_DEFINE_DATA(inst); \ diff --git a/drivers/sensor/icm42688/icm42688.h b/drivers/sensor/icm42688/icm42688.h index 18ae4606e72593a..5ec470cff270c38 100644 --- a/drivers/sensor/icm42688/icm42688.h +++ b/drivers/sensor/icm42688/icm42688.h @@ -380,11 +380,14 @@ struct icm42688_cfg { /* TODO timestamp options */ bool fifo_en; - uint16_t fifo_wm; + int32_t batch_ticks; bool fifo_hires; /* TODO additional FIFO options */ /* TODO interrupt options */ + bool interrupt1_drdy; + bool interrupt1_fifo_ths; + bool interrupt1_fifo_full; }; struct icm42688_trigger_entry { @@ -405,6 +408,15 @@ struct icm42688_dev_data { #elif defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) struct k_work work; #endif +#ifdef CONFIG_ICM42688_STREAM + struct rtio_iodev_sqe *streaming_sqe; + struct rtio *r; + struct rtio_iodev *spi_iodev; + uint8_t int_status; + uint16_t fifo_count; + uint64_t timestamp; + atomic_t reading_fifo; +#endif /* CONFIG_ICM42688_STREAM */ const struct device *dev; struct gpio_callback gpio_cb; sensor_trigger_handler_t data_ready_handler; diff --git a/drivers/sensor/icm42688/icm42688_common.c b/drivers/sensor/icm42688/icm42688_common.c index 3ccd107cfbb3ef7..4df2f7870927665 100644 --- a/drivers/sensor/icm42688/icm42688_common.c +++ b/drivers/sensor/icm42688/icm42688_common.c @@ -12,6 +12,7 @@ #include "icm42688.h" #include "icm42688_reg.h" #include "icm42688_spi.h" +#include "icm42688_trigger.h" #include LOG_MODULE_REGISTER(ICM42688_LL, CONFIG_SENSOR_LOG_LEVEL); @@ -61,6 +62,62 @@ int icm42688_reset(const struct device *dev) return 0; } +static uint16_t icm42688_compute_fifo_wm(const struct icm42688_cfg *cfg) +{ + const bool accel_enabled = cfg->accel_mode != ICM42688_ACCEL_OFF; + const bool gyro_enabled = cfg->gyro_mode != ICM42688_GYRO_OFF; + const int pkt_size = cfg->fifo_hires ? 20 : (accel_enabled && gyro_enabled ? 16 : 8); + int accel_modr = 0; + int gyro_modr = 0; + int64_t modr; + + if (cfg->batch_ticks == 0 || (!accel_enabled && !gyro_enabled)) { + return 0; + } + + if (accel_enabled) { + struct sensor_value val = {0}; + + icm42688_accel_reg_to_hz(cfg->accel_odr, &val); + accel_modr = sensor_value_to_micro(&val) / 1000; + } + if (gyro_enabled) { + struct sensor_value val = {0}; + + icm42688_gyro_reg_to_odr(cfg->gyro_odr, &val); + gyro_modr = sensor_value_to_micro(&val) / 1000; + } + + if (accel_modr == 0) { + modr = gyro_modr; + } else if (gyro_modr == 0) { + modr = accel_modr; + } else { + /* Need to find the least common multiplier (LCM) */ + int n1 = accel_modr; + int n2 = gyro_modr; + + while (n1 != n2) { + if (n1 > n2) { + n1 -= n2; + } else { + n2 -= n1; + } + } + LOG_DBG("GCD=%d", n1); + modr = ((int64_t)accel_modr * (int64_t)gyro_modr) / n1; + } + /* At this point we have 'modr' as mHz which is 1 / msec. */ + + /* Convert 'modr' to bytes * batch_ticks / msec */ + modr *= (int64_t)cfg->batch_ticks * pkt_size; + + /* 'modr' = byte_ticks_per_msec / kticks_per_sec */ + modr = DIV_ROUND_UP(modr, CONFIG_SYS_CLOCK_TICKS_PER_SEC * INT64_C(1000)); + + return (uint16_t)MIN(modr, 0x7ff); +} + int icm42688_configure(const struct device *dev, struct icm42688_cfg *cfg) { struct icm42688_dev_data *dev_data = dev->data; @@ -165,8 +222,12 @@ int icm42688_configure(const struct device *dev, struct icm42688_cfg *cfg) } /* Pulse mode with async reset (resets interrupt line on int status read) */ - res = icm42688_spi_single_write(&dev_cfg->spi, REG_INT_CONFIG, - BIT_INT1_DRIVE_CIRCUIT | BIT_INT1_POLARITY); + if (IS_ENABLED(CONFIG_ICM42688_TRIGGER)) { + res = icm42688_trigger_enable_interrupt(dev, cfg); + } else { + res = icm42688_spi_single_write(&dev_cfg->spi, REG_INT_CONFIG, + BIT_INT1_DRIVE_CIRCUIT | BIT_INT1_POLARITY); + } if (res) { LOG_ERR("Error writing to INT_CONFIG"); return res; @@ -205,7 +266,8 @@ int icm42688_configure(const struct device *dev, struct icm42688_cfg *cfg) } /* Set watermark and interrupt handling first */ - uint8_t fifo_wml = (cfg->fifo_wm) & 0xFF; + uint16_t fifo_wm = icm42688_compute_fifo_wm(cfg); + uint8_t fifo_wml = fifo_wm & 0xFF; LOG_DBG("FIFO_CONFIG2( (0x%x)) (WM Low) 0x%x", REG_FIFO_CONFIG2, fifo_wml); res = icm42688_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG2, fifo_wml); @@ -214,7 +276,7 @@ int icm42688_configure(const struct device *dev, struct icm42688_cfg *cfg) return -EINVAL; } - uint8_t fifo_wmh = (cfg->fifo_wm >> 8) & 0x0F; + uint8_t fifo_wmh = (fifo_wm >> 8) & 0x0F; LOG_DBG("FIFO_CONFIG3 (0x%x) (WM High) 0x%x", REG_FIFO_CONFIG3, fifo_wmh); res = icm42688_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG3, fifo_wmh); diff --git a/drivers/sensor/icm42688/icm42688_decoder.c b/drivers/sensor/icm42688/icm42688_decoder.c index 0a340aff3695672..3dc556ac61c7c3c 100644 --- a/drivers/sensor/icm42688/icm42688_decoder.c +++ b/drivers/sensor/icm42688/icm42688_decoder.c @@ -198,9 +198,262 @@ int icm42688_encode(const struct device *dev, const enum sensor_channel *const c return 0; } +#define IS_ACCEL(chan) ((chan) >= SENSOR_CHAN_ACCEL_X && (chan) <= SENSOR_CHAN_ACCEL_XYZ) +#define IS_GYRO(chan) ((chan) >= SENSOR_CHAN_GYRO_X && (chan) <= SENSOR_CHAN_GYRO_XYZ) + +static inline q31_t icm42688_read_temperature_from_packet(const uint8_t *pkt) +{ + int32_t temperature; + int32_t whole; + int32_t fraction; + + /* Temperature always assumes a shift of 9 for a range of (-273,273) C */ + if (FIELD_GET(FIFO_HEADER_20, pkt[0]) == 1) { + temperature = (pkt[0xd] << 8) | pkt[0xe]; + + icm42688_temp_c(temperature, &whole, &fraction); + } else { + if (FIELD_GET(FIFO_HEADER_ACCEL, pkt[0]) == 1 && + FIELD_GET(FIFO_HEADER_GYRO, pkt[0]) == 1) { + temperature = pkt[0xd]; + } else { + temperature = pkt[0x7]; + } + + int64_t sensitivity = 207; + int64_t temperature100 = (temperature * 100) + (25 * sensitivity); + + whole = temperature100 / sensitivity; + fraction = + ((temperature100 - whole * sensitivity) * INT64_C(1000000)) / sensitivity; + } + __ASSERT_NO_MSG(whole >= -512 && whole <= 511); + return FIELD_PREP(GENMASK(31, 22), whole) | (fraction * GENMASK64(21, 0) / 1000000); +} + +static int icm42688_read_imu_from_packet(const uint8_t *pkt, bool is_accel, int fs, + uint8_t axis_offset, q31_t *out) +{ + int32_t value; + int64_t scale = 0; + int32_t max = BIT(15); + int offset = 1 + (axis_offset * 2); + + if (is_accel) { + switch (fs) { + case ICM42688_ACCEL_FS_2G: + scale = INT64_C(2) * BIT(31 - 5) * 9.80665; + break; + case ICM42688_ACCEL_FS_4G: + scale = INT64_C(4) * BIT(31 - 6) * 9.80665; + break; + case ICM42688_ACCEL_FS_8G: + scale = INT64_C(8) * BIT(31 - 7) * 9.80665; + break; + case ICM42688_ACCEL_FS_16G: + scale = INT64_C(16) * BIT(31 - 8) * 9.80665; + break; + } + } else { + switch (fs) { + case ICM42688_GYRO_FS_2000: + scale = 164; + break; + case ICM42688_GYRO_FS_1000: + scale = 328; + break; + case ICM42688_GYRO_FS_500: + scale = 655; + break; + case ICM42688_GYRO_FS_250: + scale = 1310; + break; + case ICM42688_GYRO_FS_125: + scale = 2620; + break; + case ICM42688_GYRO_FS_62_5: + scale = 5243; + break; + case ICM42688_GYRO_FS_31_25: + scale = 10486; + break; + case ICM42688_GYRO_FS_15_625: + scale = 20972; + break; + } + } + + if (!is_accel && FIELD_GET(FIFO_HEADER_ACCEL, pkt[0]) == 1) { + offset += 7; + } + + value = (int16_t)sys_le16_to_cpu((pkt[offset] << 8) | pkt[offset + 1]); + + if (FIELD_GET(FIFO_HEADER_20, pkt[0]) == 1) { + uint32_t mask = is_accel ? GENMASK(7, 4) : GENMASK(3, 0); + + offset = 0x11 + axis_offset; + value = (value << 4) | FIELD_GET(mask, pkt[offset]); + /* In 20 bit mode, FS can only be +/-16g and +/-2000dps */ + scale = is_accel ? (INT64_C(16) * BIT(8) * 9.80665) : 131; + max = is_accel ? BIT(18) : BIT(19); + if (value == -524288) { + /* Invalid 20 bit value */ + return -ENODATA; + } + } else { + if (value <= -32767) { + /* Invalid 16 bit value */ + return -ENODATA; + } + } + + *out = (q31_t)(value * scale / max); + return 0; +} + +static uint32_t accel_period_ns[] = { + [ICM42688_ACCEL_ODR_1_5625] = UINT32_C(10000000000000) / 15625, + [ICM42688_ACCEL_ODR_3_125] = UINT32_C(10000000000000) / 31250, + [ICM42688_ACCEL_ODR_6_25] = UINT32_C(10000000000000) / 62500, + [ICM42688_ACCEL_ODR_12_5] = UINT32_C(10000000000000) / 12500, + [ICM42688_ACCEL_ODR_25] = UINT32_C(1000000000) / 25, + [ICM42688_ACCEL_ODR_50] = UINT32_C(1000000000) / 50, + [ICM42688_ACCEL_ODR_100] = UINT32_C(1000000000) / 100, + [ICM42688_ACCEL_ODR_200] = UINT32_C(1000000000) / 200, + [ICM42688_ACCEL_ODR_500] = UINT32_C(1000000000) / 500, + [ICM42688_ACCEL_ODR_1000] = UINT32_C(1000000), + [ICM42688_ACCEL_ODR_2000] = UINT32_C(1000000) / 2, + [ICM42688_ACCEL_ODR_4000] = UINT32_C(1000000) / 4, + [ICM42688_ACCEL_ODR_8000] = UINT32_C(1000000) / 8, + [ICM42688_ACCEL_ODR_16000] = UINT32_C(1000000) / 16, + [ICM42688_ACCEL_ODR_32000] = UINT32_C(1000000) / 32, +}; + +static uint32_t gyro_period_ns[] = { + [ICM42688_GYRO_ODR_12_5] = UINT32_C(10000000000000) / 12500, + [ICM42688_GYRO_ODR_25] = UINT32_C(1000000000) / 25, + [ICM42688_GYRO_ODR_50] = UINT32_C(1000000000) / 50, + [ICM42688_GYRO_ODR_100] = UINT32_C(1000000000) / 100, + [ICM42688_GYRO_ODR_200] = UINT32_C(1000000000) / 200, + [ICM42688_GYRO_ODR_500] = UINT32_C(1000000000) / 500, + [ICM42688_GYRO_ODR_1000] = UINT32_C(1000000), + [ICM42688_GYRO_ODR_2000] = UINT32_C(1000000) / 2, + [ICM42688_GYRO_ODR_4000] = UINT32_C(1000000) / 4, + [ICM42688_GYRO_ODR_8000] = UINT32_C(1000000) / 8, + [ICM42688_GYRO_ODR_16000] = UINT32_C(1000000) / 16, + [ICM42688_GYRO_ODR_32000] = UINT32_C(1000000) / 32, +}; + +static int icm42688_fifo_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 icm42688_fifo_data *edata = (const struct icm42688_fifo_data *)buffer; + const uint8_t *buffer_end = buffer + sizeof(struct icm42688_fifo_data) + edata->fifo_count; + int accel_frame_count = 0; + int gyro_frame_count = 0; + int count = 0; + int rc; + + if ((uintptr_t)buffer_end <= *fit || channel_idx != 0) { + return 0; + } + + ((struct sensor_data_header *)data_out)->base_timestamp_ns = edata->header.timestamp; + + buffer += sizeof(struct icm42688_fifo_data); + while (count < max_count && buffer < buffer_end) { + const bool is_20b = FIELD_GET(FIFO_HEADER_20, buffer[0]) == 1; + const bool has_accel = FIELD_GET(FIFO_HEADER_ACCEL, buffer[0]) == 1; + const bool has_gyro = FIELD_GET(FIFO_HEADER_GYRO, buffer[0]) == 1; + const uint8_t *frame_end = buffer; + + if (is_20b) { + frame_end += 20; + } else if (has_accel && has_gyro) { + frame_end += 16; + } else { + frame_end += 8; + } + if (has_accel) { + accel_frame_count++; + } + if (has_gyro) { + gyro_frame_count++; + } + + if ((uintptr_t)buffer < *fit) { + /* This frame was already decoded, move on to the next frame */ + buffer = frame_end; + continue; + } + if (channel == SENSOR_CHAN_DIE_TEMP) { + struct sensor_q31_data *data = (struct sensor_q31_data *)data_out; + + data->shift = 9; + if (has_accel) { + data->readings[count].timestamp_delta = + accel_period_ns[edata->accel_odr] * (accel_frame_count - 1); + } else { + data->readings[count].timestamp_delta = + gyro_period_ns[edata->gyro_odr] * (gyro_frame_count - 1); + } + data->readings[count].temperature = + icm42688_read_temperature_from_packet(buffer); + } else if (IS_ACCEL(channel) && has_accel) { + /* Decode accel */ + struct sensor_three_axis_data *data = + (struct sensor_three_axis_data *)data_out; + uint64_t period_ns = accel_period_ns[edata->accel_odr]; + + icm42688_get_shift(SENSOR_CHAN_ACCEL_XYZ, edata->header.accel_fs, + edata->header.gyro_fs, &data->shift); + + data->readings[count].timestamp_delta = (accel_frame_count - 1) * period_ns; + rc = icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 0, + &data->readings[count].x); + rc |= icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 1, + &data->readings[count].y); + rc |= icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 2, + &data->readings[count].z); + if (rc != 0) { + accel_frame_count--; + buffer = frame_end; + continue; + } + } else if (IS_GYRO(channel) && has_gyro) { + /* Decode gyro */ + struct sensor_three_axis_data *data = + (struct sensor_three_axis_data *)data_out; + uint64_t period_ns = accel_period_ns[edata->gyro_odr]; + + icm42688_get_shift(SENSOR_CHAN_GYRO_XYZ, edata->header.accel_fs, + edata->header.gyro_fs, &data->shift); + + data->readings[count].timestamp_delta = (gyro_frame_count - 1) * period_ns; + rc = icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 0, + &data->readings[count].x); + rc |= icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 1, + &data->readings[count].y); + rc |= icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 2, + &data->readings[count].z); + if (rc != 0) { + gyro_frame_count--; + buffer = frame_end; + continue; + } + } + buffer = frame_end; + *fit = (uintptr_t)frame_end; + count++; + } + return count; +} + static int icm42688_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) + size_t channel_idx, uint32_t *fit, uint16_t max_count, + void *data_out) { const struct icm42688_encoded_data *edata = (const struct icm42688_encoded_data *)buffer; const struct icm42688_decoder_header *header = &edata->header; @@ -318,34 +571,76 @@ static int icm42688_one_shot_decode(const uint8_t *buffer, enum sensor_channel c } static int icm42688_decoder_decode(const uint8_t *buffer, enum sensor_channel channel, - size_t channel_idx, uint32_t *fit, - uint16_t max_count, void *data_out) + size_t channel_idx, uint32_t *fit, uint16_t max_count, + void *data_out) { + const struct icm42688_decoder_header *header = + (const struct icm42688_decoder_header *)buffer; + + if (header->is_fifo) { + return icm42688_fifo_decode(buffer, channel, channel_idx, fit, max_count, data_out); + } return icm42688_one_shot_decode(buffer, channel, channel_idx, fit, max_count, data_out); } static int icm42688_decoder_get_frame_count(const uint8_t *buffer, enum sensor_channel channel, size_t channel_idx, uint16_t *frame_count) { - ARG_UNUSED(buffer); + const struct icm42688_fifo_data *data = (const struct icm42688_fifo_data *)buffer; + const struct icm42688_decoder_header *header = &data->header; + if (channel_idx != 0) { return -ENOTSUP; } - switch (channel) { - case SENSOR_CHAN_ACCEL_X: - case SENSOR_CHAN_ACCEL_Y: - case SENSOR_CHAN_ACCEL_Z: - case SENSOR_CHAN_ACCEL_XYZ: - case SENSOR_CHAN_GYRO_X: - case SENSOR_CHAN_GYRO_Y: - case SENSOR_CHAN_GYRO_Z: - case SENSOR_CHAN_GYRO_XYZ: - case SENSOR_CHAN_DIE_TEMP: - *frame_count = 1; + + 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: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_DIE_TEMP: + *frame_count = 1; + return 0; + default: + return -ENOTSUP; + } return 0; - default: - return -ENOTSUP; } + + /* Skip the header */ + buffer += sizeof(struct icm42688_fifo_data); + + uint16_t count = 0; + const uint8_t *end = buffer + data->fifo_count; + + while (buffer < end) { + bool is_20b = FIELD_GET(FIFO_HEADER_20, buffer[0]); + int size = is_20b ? 3 : 2; + + if (FIELD_GET(FIFO_HEADER_ACCEL, buffer[0])) { + size += 6; + } + if (FIELD_GET(FIFO_HEADER_GYRO, buffer[0])) { + size += 6; + } + if (FIELD_GET(FIFO_HEADER_TIMESTAMP_FSYNC, buffer[0])) { + size += 2; + } + if (is_20b) { + size += 3; + } + + buffer += size; + ++count; + } + + *frame_count = count; + return 0; } static int icm42688_decoder_get_size_info(enum sensor_channel channel, size_t *base_size, @@ -372,10 +667,31 @@ static int icm42688_decoder_get_size_info(enum sensor_channel channel, size_t *b } } +static bool icm24688_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger) +{ + const struct icm42688_fifo_data *edata = (const struct icm42688_fifo_data *)buffer; + + if (!edata->header.is_fifo) { + return false; + } + + switch (trigger) { + case SENSOR_TRIG_DATA_READY: + return FIELD_GET(BIT_INT_STATUS_DATA_RDY, edata->int_status); + case SENSOR_TRIG_FIFO_WATERMARK: + return FIELD_GET(BIT_INT_STATUS_FIFO_THS, edata->int_status); + case SENSOR_TRIG_FIFO_FULL: + return FIELD_GET(BIT_INT_STATUS_FIFO_FULL, edata->int_status); + default: + return false; + } +} + SENSOR_DECODER_API_DT_DEFINE() = { .get_frame_count = icm42688_decoder_get_frame_count, .get_size_info = icm42688_decoder_get_size_info, .decode = icm42688_decoder_decode, + .has_trigger = icm24688_decoder_has_trigger, }; int icm42688_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder) diff --git a/drivers/sensor/icm42688/icm42688_decoder.h b/drivers/sensor/icm42688/icm42688_decoder.h index 2ef806373c94021..499cf3d0801554d 100644 --- a/drivers/sensor/icm42688/icm42688_decoder.h +++ b/drivers/sensor/icm42688/icm42688_decoder.h @@ -18,6 +18,15 @@ struct icm42688_decoder_header { uint8_t reserved: 2; } __attribute__((__packed__)); +struct icm42688_fifo_data { + struct icm42688_decoder_header header; + uint8_t int_status; + uint16_t gyro_odr: 4; + uint16_t accel_odr: 4; + uint16_t fifo_count: 11; + uint16_t reserved: 5; +} __attribute__((__packed__)); + struct icm42688_encoded_data { struct icm42688_decoder_header header; struct { diff --git a/drivers/sensor/icm42688/icm42688_emul.c b/drivers/sensor/icm42688/icm42688_emul.c index e01b90742e347a7..732af64289bdd5f 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_reg.h b/drivers/sensor/icm42688/icm42688_reg.h index dfc348c072c8c75..5f3b58f0b3c074d 100644 --- a/drivers/sensor/icm42688/icm42688_reg.h +++ b/drivers/sensor/icm42688/icm42688_reg.h @@ -286,4 +286,12 @@ #define MCLK_POLL_ATTEMPTS 100 #define SOFT_RESET_TIME_MS 2 /* 1ms + elbow room */ +/* FIFO header */ +#define FIFO_HEADER_ACCEL BIT(6) +#define FIFO_HEADER_GYRO BIT(5) +#define FIFO_HEADER_20 BIT(4) +#define FIFO_HEADER_TIMESTAMP_FSYNC GENMASK(3, 2) +#define FIFO_HEADER_ODR_ACCEL BIT(1) +#define FIFO_HEADER_ODR_GYRO BIT(0) + #endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_REG_H_ */ diff --git a/drivers/sensor/icm42688/icm42688_rtio.c b/drivers/sensor/icm42688/icm42688_rtio.c index c1b20689393d6c0..ccb9532ee45a2c8 100644 --- a/drivers/sensor/icm42688/icm42688_rtio.c +++ b/drivers/sensor/icm42688/icm42688_rtio.c @@ -8,6 +8,7 @@ #include "icm42688.h" #include "icm42688_decoder.h" #include "icm42688_reg.h" +#include "icm42688_rtio.h" #include "icm42688_spi.h" #include @@ -42,7 +43,7 @@ static int icm42688_rtio_sample_fetch(const struct device *dev, int16_t readings return 0; } -int icm42688_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +static int icm42688_submit_one_shot(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) { const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; const enum sensor_channel *const channels = cfg->channels; @@ -78,4 +79,17 @@ int icm42688_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) return 0; } +int icm42688_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 icm42688_submit_one_shot(dev, iodev_sqe); + } else if (IS_ENABLED(CONFIG_ICM42688_STREAM)) { + return icm42688_submit_stream(dev, iodev_sqe); + } else { + return -ENOTSUP; + } +} + BUILD_ASSERT(sizeof(struct icm42688_decoder_header) == 9); diff --git a/drivers/sensor/icm42688/icm42688_rtio.h b/drivers/sensor/icm42688/icm42688_rtio.h index 748c8a022b09238..888e8e95357aeae 100644 --- a/drivers/sensor/icm42688/icm42688_rtio.h +++ b/drivers/sensor/icm42688/icm42688_rtio.h @@ -7,6 +7,13 @@ #ifndef ZEPHYR_DRIVERS_SENSOR_ICM42688_RTIO_H_ #define ZEPHYR_DRIVERS_SENSOR_ICM42688_RTIO_H_ +#include +#include + int icm42688_submit(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe); +int icm42688_submit_stream(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe); + +void icm42688_fifo_event(const struct device *dev); + #endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_RTIO_H_ */ diff --git a/drivers/sensor/icm42688/icm42688_rtio_stream.c b/drivers/sensor/icm42688/icm42688_rtio_stream.c new file mode 100644 index 000000000000000..57d1a66cfde9ccf --- /dev/null +++ b/drivers/sensor/icm42688/icm42688_rtio_stream.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "icm42688.h" +#include "icm42688_decoder.h" +#include "icm42688_reg.h" +#include "icm42688_rtio.h" + +LOG_MODULE_DECLARE(ICM42688_RTIO); + +int icm42688_submit_stream(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe) +{ + const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + struct icm42688_dev_data *data = sensor->data; + struct icm42688_cfg new_config = data->cfg; + + new_config.interrupt1_drdy = false; + new_config.interrupt1_fifo_ths = false; + new_config.interrupt1_fifo_full = false; + for (int i = 0; i < cfg->count; ++i) { + switch (cfg->triggers[i].trigger) { + case SENSOR_TRIG_DATA_READY: + new_config.interrupt1_drdy = true; + break; + case SENSOR_TRIG_FIFO_WATERMARK: + new_config.interrupt1_fifo_ths = true; + break; + case SENSOR_TRIG_FIFO_FULL: + new_config.interrupt1_fifo_full = true; + break; + default: + LOG_DBG("Trigger (%d) not supported", cfg->triggers[i].trigger); + break; + } + } + + if (new_config.interrupt1_drdy != data->cfg.interrupt1_drdy || + new_config.interrupt1_fifo_ths != data->cfg.interrupt1_fifo_ths || + new_config.interrupt1_fifo_full != data->cfg.interrupt1_fifo_full) { + int rc = icm42688_safely_configure(sensor, &new_config); + + if (rc != 0) { + LOG_ERR("Failed to configure sensor"); + return rc; + } + } + + data->streaming_sqe = iodev_sqe; + return 0; +} + +static void icm42688_complete_cb(struct rtio *r, const struct rtio_sqe *sqe, void *arg) +{ + const struct device *dev = arg; + struct icm42688_dev_data *drv_data = dev->data; + const struct icm42688_dev_cfg *drv_cfg = dev->config; + struct rtio_iodev_sqe *iodev_sqe = sqe->userdata; + + rtio_iodev_sqe_ok(iodev_sqe, drv_data->fifo_count); + + gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); +} + +static void icm42688_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, void *arg) +{ + const struct device *dev = arg; + struct icm42688_dev_data *drv_data = dev->data; + const struct icm42688_dev_cfg *drv_cfg = dev->config; + struct rtio_iodev *spi_iodev = drv_data->spi_iodev; + uint8_t *fifo_count_buf = (uint8_t *)&drv_data->fifo_count; + uint16_t fifo_count = ((fifo_count_buf[0] << 8) | fifo_count_buf[1]); + + drv_data->fifo_count = fifo_count; + + /* Pull a operation from our device iodev queue, validated to only be reads */ + struct rtio_iodev_sqe *iodev_sqe = drv_data->streaming_sqe; + + drv_data->streaming_sqe = NULL; + + /* Not inherently an underrun/overrun as we may have a buffer to fill next time */ + if (iodev_sqe == NULL) { + LOG_DBG("No pending SQE"); + gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); + return; + } + + const size_t packet_size = drv_data->cfg.fifo_hires ? 20 : 16; + const size_t min_read_size = sizeof(struct icm42688_fifo_data) + packet_size; + const size_t ideal_read_size = sizeof(struct icm42688_fifo_data) + fifo_count; + uint8_t *buf; + uint32_t buf_len; + + if (rtio_sqe_rx_buf(iodev_sqe, min_read_size, ideal_read_size, &buf, &buf_len) != 0) { + LOG_ERR("Failed to get buffer"); + rtio_iodev_sqe_err(iodev_sqe, -ENOMEM); + return; + } + LOG_DBG("Requesting buffer [%u, %u] got %u", (unsigned int)min_read_size, + (unsigned int)ideal_read_size, buf_len); + + /* Read FIFO and call back to rtio with rtio_sqe completion */ + /* TODO is packet format even needed? the fifo has a header per packet + * already + */ + struct icm42688_fifo_data hdr = { + .header = { + .is_fifo = true, + .gyro_fs = drv_data->cfg.gyro_fs, + .accel_fs = drv_data->cfg.accel_fs, + .timestamp = drv_data->timestamp, + }, + .int_status = drv_data->int_status, + .gyro_odr = drv_data->cfg.gyro_odr, + .accel_odr = drv_data->cfg.accel_odr, + }; + uint32_t buf_avail = buf_len; + + memcpy(buf, &hdr, sizeof(hdr)); + buf_avail -= sizeof(hdr); + + uint32_t read_len = MIN(fifo_count, buf_avail); + uint32_t pkts = read_len / packet_size; + + read_len = pkts * packet_size; + ((struct icm42688_fifo_data *)buf)->fifo_count = read_len; + + __ASSERT_NO_MSG(read_len % pkt_size == 0); + + uint8_t *read_buf = buf + sizeof(hdr); + + /* Flush out completions */ + struct rtio_cqe *cqe; + + do { + cqe = rtio_cqe_consume(r); + if (cqe != NULL) { + rtio_cqe_release(r, cqe); + } + } while (cqe != NULL); + + /* Setup new rtio chain to read the fifo data and report then check the + * result + */ + struct rtio_sqe *write_fifo_addr = rtio_sqe_acquire(r); + struct rtio_sqe *read_fifo_data = rtio_sqe_acquire(r); + struct rtio_sqe *complete_op = rtio_sqe_acquire(r); + const uint8_t reg_addr = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_FIFO_DATA); + + rtio_sqe_prep_tiny_write(write_fifo_addr, spi_iodev, RTIO_PRIO_NORM, ®_addr, 1, NULL); + write_fifo_addr->flags = RTIO_SQE_TRANSACTION; + rtio_sqe_prep_read(read_fifo_data, spi_iodev, RTIO_PRIO_NORM, read_buf, read_len, + iodev_sqe); + + rtio_sqe_prep_callback(complete_op, icm42688_complete_cb, (void *)dev, iodev_sqe); + + rtio_submit(r, 0); +} + +static struct sensor_stream_trigger * +icm42688_get_read_config_trigger(const struct sensor_read_config *cfg, + enum sensor_trigger_type trig) +{ + for (int i = 0; i < cfg->count; ++i) { + if (cfg->triggers[i].trigger == trig) { + return &cfg->triggers[i]; + } + } + LOG_DBG("Unsupported trigger (%d)", trig); + return NULL; +} + +static void icm42688_int_status_cb(struct rtio *r, const struct rtio_sqe *sqr, void *arg) +{ + const struct device *dev = arg; + struct icm42688_dev_data *drv_data = dev->data; + const struct icm42688_dev_cfg *drv_cfg = dev->config; + struct rtio_iodev *spi_iodev = drv_data->spi_iodev; + struct rtio_iodev_sqe *streaming_sqe = drv_data->streaming_sqe; + struct sensor_read_config *read_config; + + if (streaming_sqe == NULL) { + return; + } + + read_config = (struct sensor_read_config *)streaming_sqe->sqe.iodev->data; + __ASSERT_NO_MSG(read_config != NULL); + + if (!read_config->is_streaming) { + /* Oops, not really configured for streaming data */ + return; + } + + struct sensor_stream_trigger *fifo_ths_cfg = + icm42688_get_read_config_trigger(read_config, SENSOR_TRIG_FIFO_WATERMARK); + bool has_fifo_ths_trig = fifo_ths_cfg != NULL && + FIELD_GET(BIT_INT_STATUS_FIFO_THS, drv_data->int_status) != 0; + + struct sensor_stream_trigger *fifo_full_cfg = + icm42688_get_read_config_trigger(read_config, SENSOR_TRIG_FIFO_FULL); + bool has_fifo_full_trig = fifo_full_cfg != NULL && + FIELD_GET(BIT_INT_STATUS_FIFO_FULL, drv_data->int_status) != 0; + + if (!has_fifo_ths_trig && !has_fifo_full_trig) { + gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); + return; + } + + /* Flush completions */ + struct rtio_cqe *cqe; + + do { + cqe = rtio_cqe_consume(r); + if (cqe != NULL) { + rtio_cqe_release(r, cqe); + } + } while (cqe != NULL); + + enum sensor_stream_data_opt data_opt; + + if (has_fifo_ths_trig && !has_fifo_full_trig) { + /* Only care about fifo threshold */ + data_opt = fifo_ths_cfg->opt; + } else if (!has_fifo_ths_trig && has_fifo_full_trig) { + /* Only care about fifo full */ + data_opt = fifo_full_cfg->opt; + } else { + /* Both fifo threshold and full */ + data_opt = MIN(fifo_ths_cfg->opt, fifo_full_cfg->opt); + } + + if (data_opt == SENSOR_STREAM_DATA_NOP || data_opt == SENSOR_STREAM_DATA_DROP) { + uint8_t *buf; + uint32_t buf_len; + + /* Clear streaming_sqe since we're done with the call */ + drv_data->streaming_sqe = NULL; + if (rtio_sqe_rx_buf(streaming_sqe, sizeof(struct icm42688_fifo_data), + sizeof(struct icm42688_fifo_data), &buf, &buf_len) != 0) { + rtio_iodev_sqe_err(streaming_sqe, -ENOMEM); + return; + } + + struct icm42688_fifo_data *data = (struct icm42688_fifo_data *)buf; + + memset(buf, 0, buf_len); + data->header.timestamp = drv_data->timestamp; + data->int_status = drv_data->int_status; + data->fifo_count = 0; + rtio_iodev_sqe_ok(streaming_sqe, 0); + gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); + if (data_opt == SENSOR_STREAM_DATA_DROP) { + /* Flush the FIFO */ + struct rtio_sqe *write_signal_path_reset = rtio_sqe_acquire(r); + uint8_t write_buffer[] = { + FIELD_GET(REG_ADDRESS_MASK, REG_SIGNAL_PATH_RESET), + BIT_FIFO_FLUSH, + }; + + rtio_sqe_prep_tiny_write(write_signal_path_reset, spi_iodev, RTIO_PRIO_NORM, + write_buffer, ARRAY_SIZE(write_buffer), NULL); + /* TODO Add a new flag for fire-and-forget so we don't have to block here */ + rtio_submit(r, 1); + ARG_UNUSED(rtio_cqe_consume(r)); + } + return; + } + + /* We need the data, read the fifo length */ + struct rtio_sqe *write_fifo_count_reg = rtio_sqe_acquire(r); + struct rtio_sqe *read_fifo_count = rtio_sqe_acquire(r); + struct rtio_sqe *check_fifo_count = rtio_sqe_acquire(r); + uint8_t reg = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_FIFO_COUNTH); + uint8_t *read_buf = (uint8_t *)&drv_data->fifo_count; + + rtio_sqe_prep_tiny_write(write_fifo_count_reg, spi_iodev, RTIO_PRIO_NORM, ®, 1, NULL); + write_fifo_count_reg->flags = RTIO_SQE_TRANSACTION; + rtio_sqe_prep_read(read_fifo_count, spi_iodev, RTIO_PRIO_NORM, read_buf, 2, NULL); + rtio_sqe_prep_callback(check_fifo_count, icm42688_fifo_count_cb, arg, NULL); + + rtio_submit(r, 0); +} + +void icm42688_fifo_event(const struct device *dev) +{ + struct icm42688_dev_data *drv_data = dev->data; + struct rtio_iodev *spi_iodev = drv_data->spi_iodev; + struct rtio *r = drv_data->r; + + if (drv_data->streaming_sqe == NULL) { + return; + } + + drv_data->timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + + /* + * Setup rtio chain of ops with inline calls to make decisions + * 1. read int status + * 2. call to check int status and get pending RX operation + * 4. read fifo len + * 5. call to determine read len + * 6. read fifo + * 7. call to report completion + */ + struct rtio_sqe *write_int_reg = rtio_sqe_acquire(r); + struct rtio_sqe *read_int_reg = rtio_sqe_acquire(r); + struct rtio_sqe *check_int_status = rtio_sqe_acquire(r); + uint8_t reg = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_INT_STATUS); + + rtio_sqe_prep_tiny_write(write_int_reg, spi_iodev, RTIO_PRIO_NORM, ®, 1, NULL); + write_int_reg->flags = RTIO_SQE_TRANSACTION; + rtio_sqe_prep_read(read_int_reg, spi_iodev, RTIO_PRIO_NORM, &drv_data->int_status, 1, NULL); + rtio_sqe_prep_callback(check_int_status, icm42688_int_status_cb, (void *)dev, NULL); + rtio_submit(r, 0); +} diff --git a/drivers/sensor/icm42688/icm42688_trigger.c b/drivers/sensor/icm42688/icm42688_trigger.c index adaecf84baa6566..72ccd7e9059e4c2 100644 --- a/drivers/sensor/icm42688/icm42688_trigger.c +++ b/drivers/sensor/icm42688/icm42688_trigger.c @@ -12,6 +12,7 @@ #include "icm42688.h" #include "icm42688_reg.h" +#include "icm42688_rtio.h" #include "icm42688_spi.h" #include "icm42688_trigger.h" @@ -30,6 +31,9 @@ static void icm42688_gpio_callback(const struct device *dev, struct gpio_callbac #elif defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) k_work_submit(&data->work); #endif + if (IS_ENABLED(CONFIG_ICM42688_STREAM)) { + icm42688_fifo_event(data->dev); + } } #if defined(CONFIG_ICM42688_TRIGGER_OWN_THREAD) || defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) @@ -90,12 +94,12 @@ int icm42688_trigger_set(const struct device *dev, const struct sensor_trigger * switch (trig->type) { case SENSOR_TRIG_DATA_READY: + case SENSOR_TRIG_FIFO_WATERMARK: + case SENSOR_TRIG_FIFO_FULL: 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; @@ -146,7 +150,7 @@ int icm42688_trigger_init(const struct device *dev) return gpio_pin_interrupt_configure_dt(&cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); } -int icm42688_trigger_enable_interrupt(const struct device *dev) +int icm42688_trigger_enable_interrupt(const struct device *dev, struct icm42688_cfg *new_cfg) { int res; const struct icm42688_dev_cfg *cfg = dev->config; @@ -164,9 +168,19 @@ int icm42688_trigger_enable_interrupt(const struct device *dev) return res; } - /* enable data ready interrupt on INT1 pin */ - return icm42688_spi_single_write(&cfg->spi, REG_INT_SOURCE0, - FIELD_PREP(BIT_UI_DRDY_INT1_EN, 1)); + /* enable interrupts on INT1 pin */ + uint8_t value = 0; + + if (new_cfg->interrupt1_drdy) { + value |= FIELD_PREP(BIT_UI_DRDY_INT1_EN, 1); + } + if (new_cfg->interrupt1_fifo_ths) { + value |= FIELD_PREP(BIT_FIFO_THS_INT1_EN, 1); + } + if (new_cfg->interrupt1_fifo_full) { + value |= FIELD_PREP(BIT_FIFO_FULL_INT1_EN, 1); + } + return icm42688_spi_single_write(&cfg->spi, REG_INT_SOURCE0, value); } void icm42688_lock(const struct device *dev) diff --git a/drivers/sensor/icm42688/icm42688_trigger.h b/drivers/sensor/icm42688/icm42688_trigger.h index 5ed382eb0d403a1..e03975916181203 100644 --- a/drivers/sensor/icm42688/icm42688_trigger.h +++ b/drivers/sensor/icm42688/icm42688_trigger.h @@ -26,9 +26,10 @@ int icm42688_trigger_init(const struct device *dev); * @brief enable the trigger gpio interrupt * * @param dev icm42688 device pointer + * @param new_cfg New configuration to use for the device * @return int 0 on success, negative error code otherwise */ -int icm42688_trigger_enable_interrupt(const struct device *dev); +int icm42688_trigger_enable_interrupt(const struct device *dev, struct icm42688_cfg *new_cfg); /** * @brief lock access to the icm42688 device driver diff --git a/drivers/sensor/iis2dh/Kconfig b/drivers/sensor/iis2dh/Kconfig index 5067b283ead0cd8..8e072265b0dbd63 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/iis2dh/iis2dh_trigger.c b/drivers/sensor/iis2dh/iis2dh_trigger.c index edbcf01493b2bb9..d108c52c398b216 100644 --- a/drivers/sensor/iis2dh/iis2dh_trigger.c +++ b/drivers/sensor/iis2dh/iis2dh_trigger.c @@ -112,8 +112,13 @@ static void iis2dh_gpio_callback(const struct device *dev, } #ifdef CONFIG_IIS2DH_TRIGGER_OWN_THREAD -static void iis2dh_thread(struct iis2dh_data *iis2dh) +static void iis2dh_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct iis2dh_data *iis2dh = p1; + while (1) { k_sem_take(&iis2dh->gpio_sem, K_FOREVER); iis2dh_handle_interrupt(iis2dh->dev); @@ -149,7 +154,7 @@ int iis2dh_init_interrupt(const struct device *dev) k_thread_create(&iis2dh->thread, iis2dh->thread_stack, CONFIG_IIS2DH_THREAD_STACK_SIZE, - (k_thread_entry_t)iis2dh_thread, iis2dh, + iis2dh_thread, iis2dh, 0, NULL, K_PRIO_COOP(CONFIG_IIS2DH_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/iis2dlpc/Kconfig b/drivers/sensor/iis2dlpc/Kconfig index 6e241af02798e65..2a7daeb4cc6aa21 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/iis2dlpc/iis2dlpc_trigger.c b/drivers/sensor/iis2dlpc/iis2dlpc_trigger.c index 381e3318aa51fb6..90cdb4b857f91dd 100644 --- a/drivers/sensor/iis2dlpc/iis2dlpc_trigger.c +++ b/drivers/sensor/iis2dlpc/iis2dlpc_trigger.c @@ -233,8 +233,13 @@ static void iis2dlpc_gpio_callback(const struct device *dev, } #ifdef CONFIG_IIS2DLPC_TRIGGER_OWN_THREAD -static void iis2dlpc_thread(struct iis2dlpc_data *iis2dlpc) +static void iis2dlpc_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct iis2dlpc_data *iis2dlpc = p1; + while (1) { k_sem_take(&iis2dlpc->gpio_sem, K_FOREVER); iis2dlpc_handle_interrupt(iis2dlpc->dev); @@ -270,7 +275,7 @@ int iis2dlpc_init_interrupt(const struct device *dev) k_thread_create(&iis2dlpc->thread, iis2dlpc->thread_stack, CONFIG_IIS2DLPC_THREAD_STACK_SIZE, - (k_thread_entry_t)iis2dlpc_thread, iis2dlpc, + iis2dlpc_thread, iis2dlpc, NULL, NULL, K_PRIO_COOP(CONFIG_IIS2DLPC_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_IIS2DLPC_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/iis2iclx/Kconfig b/drivers/sensor/iis2iclx/Kconfig index 030fc0bbd96ca79..8266a60b2f919ed 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 8395f38c6ba4776..e45203da003c5e6 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/iis2iclx/iis2iclx_trigger.c b/drivers/sensor/iis2iclx/iis2iclx_trigger.c index 6360ab69d72e75c..174583c75e77c8d 100644 --- a/drivers/sensor/iis2iclx/iis2iclx_trigger.c +++ b/drivers/sensor/iis2iclx/iis2iclx_trigger.c @@ -182,8 +182,13 @@ static void iis2iclx_gpio_callback(const struct device *dev, } #ifdef CONFIG_IIS2ICLX_TRIGGER_OWN_THREAD -static void iis2iclx_thread(struct iis2iclx_data *iis2iclx) +static void iis2iclx_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct iis2iclx_data *iis2iclx = p1; + while (1) { k_sem_take(&iis2iclx->gpio_sem, K_FOREVER); iis2iclx_handle_interrupt(iis2iclx->dev); @@ -218,7 +223,7 @@ int iis2iclx_init_interrupt(const struct device *dev) k_thread_create(&iis2iclx->thread, iis2iclx->thread_stack, CONFIG_IIS2ICLX_THREAD_STACK_SIZE, - (k_thread_entry_t)iis2iclx_thread, + iis2iclx_thread, iis2iclx, NULL, NULL, K_PRIO_COOP(CONFIG_IIS2ICLX_THREAD_PRIORITY), 0, K_NO_WAIT); diff --git a/drivers/sensor/iis2mdc/Kconfig b/drivers/sensor/iis2mdc/Kconfig index 2215c778c28850f..1f4817a0a699715 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/iis2mdc/iis2mdc_trigger.c b/drivers/sensor/iis2mdc/iis2mdc_trigger.c index 049cc5c3b955d0e..fc9f203b033e745 100644 --- a/drivers/sensor/iis2mdc/iis2mdc_trigger.c +++ b/drivers/sensor/iis2mdc/iis2mdc_trigger.c @@ -83,8 +83,13 @@ static void iis2mdc_gpio_callback(const struct device *dev, } #ifdef CONFIG_IIS2MDC_TRIGGER_OWN_THREAD -static void iis2mdc_thread(struct iis2mdc_data *iis2mdc) +static void iis2mdc_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct iis2mdc_data *iis2mdc = p1; + while (1) { k_sem_take(&iis2mdc->gpio_sem, K_FOREVER); iis2mdc_handle_interrupt(iis2mdc->dev); @@ -118,7 +123,7 @@ int iis2mdc_init_interrupt(const struct device *dev) k_sem_init(&iis2mdc->gpio_sem, 0, K_SEM_MAX_LIMIT); k_thread_create(&iis2mdc->thread, iis2mdc->thread_stack, CONFIG_IIS2MDC_THREAD_STACK_SIZE, - (k_thread_entry_t)iis2mdc_thread, iis2mdc, + iis2mdc_thread, iis2mdc, NULL, NULL, K_PRIO_COOP(CONFIG_IIS2MDC_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_IIS2MDC_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/iis3dhhc/Kconfig b/drivers/sensor/iis3dhhc/Kconfig index ecd112aa9281ef4..f48e35d81f696cb 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/iis3dhhc/iis3dhhc_trigger.c b/drivers/sensor/iis3dhhc/iis3dhhc_trigger.c index ff964e30efc5912..0ce2df490b37f8c 100644 --- a/drivers/sensor/iis3dhhc/iis3dhhc_trigger.c +++ b/drivers/sensor/iis3dhhc/iis3dhhc_trigger.c @@ -99,8 +99,13 @@ static void iis3dhhc_gpio_callback(const struct device *dev, } #ifdef CONFIG_IIS3DHHC_TRIGGER_OWN_THREAD -static void iis3dhhc_thread(struct iis3dhhc_data *iis3dhhc) +static void iis3dhhc_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct iis3dhhc_data *iis3dhhc = p1; + while (1) { k_sem_take(&iis3dhhc->gpio_sem, K_FOREVER); iis3dhhc_handle_interrupt(iis3dhhc->dev); @@ -136,7 +141,7 @@ int iis3dhhc_init_interrupt(const struct device *dev) k_thread_create(&iis3dhhc->thread, iis3dhhc->thread_stack, CONFIG_IIS3DHHC_THREAD_STACK_SIZE, - (k_thread_entry_t)iis3dhhc_thread, iis3dhhc, + iis3dhhc_thread, iis3dhhc, NULL, NULL, K_PRIO_COOP(CONFIG_IIS3DHHC_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_IIS3DHHC_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/isl29035/isl29035_trigger.c b/drivers/sensor/isl29035/isl29035_trigger.c index db4857917c63e71..a0a5d2af21fe696 100644 --- a/drivers/sensor/isl29035/isl29035_trigger.c +++ b/drivers/sensor/isl29035/isl29035_trigger.c @@ -121,8 +121,12 @@ static void isl29035_thread_cb(const struct device *dev) } #ifdef CONFIG_ISL29035_TRIGGER_OWN_THREAD -static void isl29035_thread(const struct device *dev) +static void isl29035_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; struct isl29035_driver_data *drv_data = dev->data; while (1) { @@ -205,7 +209,7 @@ int isl29035_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_ISL29035_THREAD_STACK_SIZE, - (k_thread_entry_t)isl29035_thread, + isl29035_thread, (void *)dev, NULL, NULL, K_PRIO_COOP(CONFIG_ISL29035_THREAD_PRIORITY), 0, K_NO_WAIT); diff --git a/drivers/sensor/ism330dhcx/Kconfig b/drivers/sensor/ism330dhcx/Kconfig index 75eb6d9fec9b5b4..f5a6b7d891b743d 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 3dfa7a64137feea..97d0aaa5f44842d 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/ism330dhcx/ism330dhcx_trigger.c b/drivers/sensor/ism330dhcx/ism330dhcx_trigger.c index 788313b85c572c0..ac4c16b9506ad07 100644 --- a/drivers/sensor/ism330dhcx/ism330dhcx_trigger.c +++ b/drivers/sensor/ism330dhcx/ism330dhcx_trigger.c @@ -226,8 +226,13 @@ static void ism330dhcx_gpio_callback(const struct device *dev, } #ifdef CONFIG_ISM330DHCX_TRIGGER_OWN_THREAD -static void ism330dhcx_thread(struct ism330dhcx_data *ism330dhcx) +static void ism330dhcx_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct ism330dhcx_data *ism330dhcx = p1; + while (1) { k_sem_take(&ism330dhcx->gpio_sem, K_FOREVER); ism330dhcx_handle_interrupt(ism330dhcx->dev); @@ -261,7 +266,7 @@ int ism330dhcx_init_interrupt(const struct device *dev) k_thread_create(&ism330dhcx->thread, ism330dhcx->thread_stack, CONFIG_ISM330DHCX_THREAD_STACK_SIZE, - (k_thread_entry_t)ism330dhcx_thread, + ism330dhcx_thread, ism330dhcx, NULL, NULL, K_PRIO_COOP(CONFIG_ISM330DHCX_THREAD_PRIORITY), 0, K_NO_WAIT); diff --git a/drivers/sensor/lis2dh/lis2dh.c b/drivers/sensor/lis2dh/lis2dh.c index 3aaa8ab83fec172..a12bb0e097de214 100644 --- a/drivers/sensor/lis2dh/lis2dh.c +++ b/drivers/sensor/lis2dh/lis2dh.c @@ -520,7 +520,9 @@ static int lis2dh_pm_action(const struct device *dev, .gpio_int = \ COND_CODE_1(ANYM_ON_INT1(inst), \ (GPIO_DT_SPEC_INST_GET_BY_IDX_COND(inst, irq_gpios, 0)), \ - (GPIO_DT_SPEC_INST_GET_BY_IDX_COND(inst, irq_gpios, 1))), + (GPIO_DT_SPEC_INST_GET_BY_IDX_COND(inst, irq_gpios, 1))), \ + .int1_mode = DT_INST_PROP(inst, int1_gpio_config), \ + .int2_mode = DT_INST_PROP(inst, int2_gpio_config), #else #define LIS2DH_CFG_INT(inst) #endif /* CONFIG_LIS2DH_TRIGGER */ diff --git a/drivers/sensor/lis2dh/lis2dh.h b/drivers/sensor/lis2dh/lis2dh.h index 142b1330d781ce7..f746e983e28b9ba 100644 --- a/drivers/sensor/lis2dh/lis2dh.h +++ b/drivers/sensor/lis2dh/lis2dh.h @@ -219,6 +219,8 @@ struct lis2dh_config { #ifdef CONFIG_LIS2DH_TRIGGER const struct gpio_dt_spec gpio_drdy; const struct gpio_dt_spec gpio_int; + const uint8_t int1_mode; + const uint8_t int2_mode; #endif /* CONFIG_LIS2DH_TRIGGER */ struct { bool is_lsm303agr_dev : 1; diff --git a/drivers/sensor/lis2dh/lis2dh_trigger.c b/drivers/sensor/lis2dh/lis2dh_trigger.c index 2b773b2aef8b81b..3c075b2a0e881d5 100644 --- a/drivers/sensor/lis2dh/lis2dh_trigger.c +++ b/drivers/sensor/lis2dh/lis2dh_trigger.c @@ -18,6 +18,14 @@ LOG_MODULE_DECLARE(lis2dh, CONFIG_SENSOR_LOG_LEVEL); #include "lis2dh.h" +static const gpio_flags_t gpio_int_cfg[5] = { + GPIO_INT_EDGE, + GPIO_INT_EDGE_RISING, + GPIO_INT_EDGE_FALLING, + GPIO_INT_LEVEL_HIGH, + GPIO_INT_LEVEL_LOW, + }; + static inline void setup_int1(const struct device *dev, bool enable) { @@ -25,7 +33,7 @@ static inline void setup_int1(const struct device *dev, gpio_pin_interrupt_configure_dt(&cfg->gpio_drdy, enable - ? GPIO_INT_LEVEL_ACTIVE + ? gpio_int_cfg[cfg->int1_mode] : GPIO_INT_DISABLE); } @@ -123,7 +131,7 @@ static inline void setup_int2(const struct device *dev, gpio_pin_interrupt_configure_dt(&cfg->gpio_int, enable - ? GPIO_INT_LEVEL_ACTIVE + ? gpio_int_cfg[cfg->int2_mode] : GPIO_INT_DISABLE); } @@ -506,8 +514,13 @@ static void lis2dh_thread_cb(const struct device *dev) } #ifdef CONFIG_LIS2DH_TRIGGER_OWN_THREAD -static void lis2dh_thread(struct lis2dh_data *lis2dh) +static void lis2dh_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct lis2dh_data *lis2dh = p1; + while (1) { k_sem_take(&lis2dh->gpio_sem, K_FOREVER); lis2dh_thread_cb(lis2dh->dev); @@ -538,7 +551,7 @@ int lis2dh_init_interrupt(const struct device *dev) k_sem_init(&lis2dh->gpio_sem, 0, K_SEM_MAX_LIMIT); k_thread_create(&lis2dh->thread, lis2dh->thread_stack, CONFIG_LIS2DH_THREAD_STACK_SIZE, - (k_thread_entry_t)lis2dh_thread, lis2dh, NULL, NULL, + lis2dh_thread, lis2dh, NULL, NULL, K_PRIO_COOP(CONFIG_LIS2DH_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD) lis2dh->work.handler = lis2dh_work_cb; diff --git a/drivers/sensor/lis2ds12/Kconfig b/drivers/sensor/lis2ds12/Kconfig index 14b063bd8ecc773..cc8331bdf5edde8 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/lis2ds12/lis2ds12.c b/drivers/sensor/lis2ds12/lis2ds12.c index ae7fa9eb81f643e..c9634b2179f5ca5 100644 --- a/drivers/sensor/lis2ds12/lis2ds12.c +++ b/drivers/sensor/lis2ds12/lis2ds12.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "lis2ds12.h" @@ -40,8 +41,9 @@ static int lis2ds12_set_odr(const struct device *dev, uint8_t odr) * 12,5Hz <= odr <= 800Hz are available in LP and HR mode only * odr == 1Hz is available in LP mode only */ - if ((odr >= 9 && cfg->pm != 3) || (odr < 9 && cfg->pm == 3) || - (odr == 1 && cfg->pm != 1)) { + if ((odr >= LIS2DS12_DT_ODR_1600Hz && cfg->pm != LIS2DS12_DT_HIGH_FREQUENCY) || + (odr < LIS2DS12_DT_ODR_1600Hz && cfg->pm == LIS2DS12_DT_HIGH_FREQUENCY) || + (odr == LIS2DS12_DT_ODR_1Hz_LP && cfg->pm != LIS2DS12_DT_LOW_POWER)) { LOG_ERR("%s: bad odr and pm combination", dev->name); return -ENOTSUP; } diff --git a/drivers/sensor/lis2ds12/lis2ds12_trigger.c b/drivers/sensor/lis2ds12/lis2ds12_trigger.c index 96069419907ac43..d34949133156043 100644 --- a/drivers/sensor/lis2ds12/lis2ds12_trigger.c +++ b/drivers/sensor/lis2ds12/lis2ds12_trigger.c @@ -67,8 +67,13 @@ static void lis2ds12_handle_int(const struct device *dev) } #ifdef CONFIG_LIS2DS12_TRIGGER_OWN_THREAD -static void lis2ds12_thread(struct lis2ds12_data *data) +static void lis2ds12_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct lis2ds12_data *data = p1; + while (1) { k_sem_take(&data->trig_sem, K_FOREVER); lis2ds12_handle_int(data->dev); @@ -159,7 +164,7 @@ int lis2ds12_trigger_init(const struct device *dev) k_thread_create(&data->thread, data->thread_stack, CONFIG_LIS2DS12_THREAD_STACK_SIZE, - (k_thread_entry_t)lis2ds12_thread, + lis2ds12_thread, data, NULL, NULL, K_PRIO_COOP(CONFIG_LIS2DS12_THREAD_PRIORITY), 0, K_NO_WAIT); diff --git a/drivers/sensor/lis2du12/CMakeLists.txt b/drivers/sensor/lis2du12/CMakeLists.txt new file mode 100644 index 000000000000000..378cc8f7f0d1443 --- /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 000000000000000..4c00b940ef109c2 --- /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 000000000000000..bd5d8b2faf0467e --- /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 000000000000000..f05d0511b7b3bd1 --- /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 000000000000000..d2edbad3e2b4fb5 --- /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 9e34bfaea849f75..2241505902fc5ff 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/lis2dw12/lis2dw12.c b/drivers/sensor/lis2dw12/lis2dw12.c index 2f77cbbf8c86926..97452d78c41701d 100644 --- a/drivers/sensor/lis2dw12/lis2dw12.c +++ b/drivers/sensor/lis2dw12/lis2dw12.c @@ -476,6 +476,14 @@ static int lis2dw12_init(const struct device *dev) return ret; } +#ifdef CONFIG_LIS2DW12_THRESHOLD + ret = lis2dw12_wkup_dur_set(ctx, cfg->wakeup_duration); + if (ret < 0) { + LOG_ERR("wakeup duration config error %d", ret); + return ret; + } +#endif /* CONFIG_LIS2DW12_THRESHOLD */ + return 0; } @@ -521,6 +529,13 @@ static int lis2dw12_init(const struct device *dev) #define LIS2DW12_CONFIG_FREEFALL(inst) #endif /* CONFIG_LIS2DW12_FREEFALL */ +#ifdef CONFIG_LIS2DW12_THRESHOLD +#define LIS2DW12_CONFIG_THRESHOLD(inst) \ + .wakeup_duration = DT_INST_PROP(inst, wakeup_duration), +#else +#define LIS2DW12_CONFIG_THRESHOLD(inst) +#endif + #ifdef CONFIG_LIS2DW12_TRIGGER #define LIS2DW12_CFG_IRQ(inst) \ .gpio_int = GPIO_DT_SPEC_INST_GET(inst, irq_gpios), \ @@ -540,6 +555,7 @@ static int lis2dw12_init(const struct device *dev) .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ LIS2DW12_CONFIG_TAP(inst) \ LIS2DW12_CONFIG_FREEFALL(inst) \ + LIS2DW12_CONFIG_THRESHOLD(inst) \ COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \ (LIS2DW12_CFG_IRQ(inst)), ()) diff --git a/drivers/sensor/lis2dw12/lis2dw12.h b/drivers/sensor/lis2dw12/lis2dw12.h index ba61a764114db40..d52312193c03af7 100644 --- a/drivers/sensor/lis2dw12/lis2dw12.h +++ b/drivers/sensor/lis2dw12/lis2dw12.h @@ -96,6 +96,9 @@ struct lis2dw12_device_config { uint8_t freefall_duration; uint8_t freefall_threshold; #endif /* CONFIG_LIS2DW12_FREEFALL */ +#ifdef CONFIG_LIS2DW12_THRESHOLD + uint8_t wakeup_duration; +#endif /* CONFIG_LIS2DW12_THRESHOLD */ #endif /* CONFIG_LIS2DW12_TRIGGER */ }; diff --git a/drivers/sensor/lis2dw12/lis2dw12_trigger.c b/drivers/sensor/lis2dw12/lis2dw12_trigger.c index 08030c993b61e2b..e30d6d4c1678df5 100644 --- a/drivers/sensor/lis2dw12/lis2dw12_trigger.c +++ b/drivers/sensor/lis2dw12/lis2dw12_trigger.c @@ -301,8 +301,13 @@ static void lis2dw12_gpio_callback(const struct device *dev, } #ifdef CONFIG_LIS2DW12_TRIGGER_OWN_THREAD -static void lis2dw12_thread(struct lis2dw12_data *lis2dw12) +static void lis2dw12_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct lis2dw12_data *lis2dw12 = p1; + while (1) { k_sem_take(&lis2dw12->gpio_sem, K_FOREVER); lis2dw12_handle_interrupt(lis2dw12->dev); @@ -451,7 +456,7 @@ int lis2dw12_init_interrupt(const struct device *dev) k_thread_create(&lis2dw12->thread, lis2dw12->thread_stack, CONFIG_LIS2DW12_THREAD_STACK_SIZE, - (k_thread_entry_t)lis2dw12_thread, lis2dw12, + lis2dw12_thread, lis2dw12, NULL, NULL, K_PRIO_COOP(CONFIG_LIS2DW12_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/lis2mdl/Kconfig b/drivers/sensor/lis2mdl/Kconfig index 6970a60555d5319..637b883b26e2fe8 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/lis2mdl/lis2mdl_trigger.c b/drivers/sensor/lis2mdl/lis2mdl_trigger.c index 4a77e2fa4327284..19930174ea03dd1 100644 --- a/drivers/sensor/lis2mdl/lis2mdl_trigger.c +++ b/drivers/sensor/lis2mdl/lis2mdl_trigger.c @@ -96,8 +96,13 @@ static void lis2mdl_gpio_callback(const struct device *dev, } #ifdef CONFIG_LIS2MDL_TRIGGER_OWN_THREAD -static void lis2mdl_thread(struct lis2mdl_data *lis2mdl) +static void lis2mdl_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct lis2mdl_data *lis2mdl = p1; + while (1) { k_sem_take(&lis2mdl->gpio_sem, K_FOREVER); lis2mdl_handle_interrupt(lis2mdl->dev); @@ -131,7 +136,7 @@ int lis2mdl_init_interrupt(const struct device *dev) k_sem_init(&lis2mdl->gpio_sem, 0, K_SEM_MAX_LIMIT); k_thread_create(&lis2mdl->thread, lis2mdl->thread_stack, CONFIG_LIS2MDL_THREAD_STACK_SIZE, - (k_thread_entry_t)lis2mdl_thread, lis2mdl, + lis2mdl_thread, lis2mdl, NULL, NULL, K_PRIO_COOP(CONFIG_LIS2MDL_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_LIS2MDL_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/lis3mdl/lis3mdl_trigger.c b/drivers/sensor/lis3mdl/lis3mdl_trigger.c index 05993e1ceda3886..ba94076bd14f43b 100644 --- a/drivers/sensor/lis3mdl/lis3mdl_trigger.c +++ b/drivers/sensor/lis3mdl/lis3mdl_trigger.c @@ -87,8 +87,13 @@ static void lis3mdl_thread_cb(const struct device *dev) } #ifdef CONFIG_LIS3MDL_TRIGGER_OWN_THREAD -static void lis3mdl_thread(struct lis3mdl_data *drv_data) +static void lis3mdl_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct lis3mdl_data *drv_data = p1; + while (1) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); lis3mdl_thread_cb(drv_data->dev); @@ -140,7 +145,7 @@ int lis3mdl_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_LIS3MDL_THREAD_STACK_SIZE, - (k_thread_entry_t)lis3mdl_thread, drv_data, + lis3mdl_thread, drv_data, NULL, NULL, K_PRIO_COOP(CONFIG_LIS3MDL_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_LIS3MDL_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/lps22hh/Kconfig b/drivers/sensor/lps22hh/Kconfig index ad23e07068ef1e0..2fa57a6c485823b 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/lps22hh/lps22hh_trigger.c b/drivers/sensor/lps22hh/lps22hh_trigger.c index bb8c7f406efecc9..e08a0259ee2c9a3 100644 --- a/drivers/sensor/lps22hh/lps22hh_trigger.c +++ b/drivers/sensor/lps22hh/lps22hh_trigger.c @@ -123,8 +123,13 @@ static void lps22hh_gpio_callback(const struct device *dev, } #ifdef CONFIG_LPS22HH_TRIGGER_OWN_THREAD -static void lps22hh_thread(struct lps22hh_data *lps22hh) +static void lps22hh_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct lps22hh_data *lps22hh = p1; + while (1) { k_sem_take(&lps22hh->intr_sem, K_FOREVER); lps22hh_handle_interrupt(lps22hh->dev); @@ -187,7 +192,7 @@ int lps22hh_init_interrupt(const struct device *dev) k_thread_create(&lps22hh->thread, lps22hh->thread_stack, CONFIG_LPS22HH_THREAD_STACK_SIZE, - (k_thread_entry_t)lps22hh_thread, lps22hh, + lps22hh_thread, lps22hh, NULL, NULL, K_PRIO_COOP(CONFIG_LPS22HH_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_LPS22HH_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/lps2xdf/CMakeLists.txt b/drivers/sensor/lps2xdf/CMakeLists.txt new file mode 100644 index 000000000000000..24a1b5844a8eec1 --- /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 000000000000000..754f8c3b4511f96 --- /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 000000000000000..627d02a55b90fb4 --- /dev/null +++ b/drivers/sensor/lps2xdf/lps22df.c @@ -0,0 +1,233 @@ +/* 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 */ + 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 000000000000000..bb03423ea8a568d --- /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 000000000000000..86d0ab4edf5032f --- /dev/null +++ b/drivers/sensor/lps2xdf/lps28dfw.c @@ -0,0 +1,240 @@ +/* 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 */ + 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 000000000000000..ba87caab094e8b8 --- /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 000000000000000..33d909dfbf61135 --- /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 000000000000000..10a38a5a133d677 --- /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 000000000000000..2c3aa76124baa5d --- /dev/null +++ b/drivers/sensor/lps2xdf/lps2xdf_trigger.c @@ -0,0 +1,206 @@ +/* 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; + + 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; + + 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/lsm6dsl/Kconfig b/drivers/sensor/lsm6dsl/Kconfig index 57d8f9a88b3e926..c21937cf9226fde 100644 --- a/drivers/sensor/lsm6dsl/Kconfig +++ b/drivers/sensor/lsm6dsl/Kconfig @@ -130,7 +130,7 @@ config LSM6DSL_ACCEL_FS config LSM6DSL_ACCEL_ODR int "Accelerometer Output data rate frequency" - range 0 10 + range 0 11 default 0 help Specify the default accelerometer output data rate expressed in @@ -146,6 +146,7 @@ config LSM6DSL_ACCEL_ODR 8: 1666Hz 9: 3332Hz 10: 6664Hz + 11: 1.6Hz endmenu endif # LSM6DSL diff --git a/drivers/sensor/lsm6dsl/lsm6dsl.c b/drivers/sensor/lsm6dsl/lsm6dsl.c index 8b7dc2fe8dc9b42..0a0f35258045e4b 100644 --- a/drivers/sensor/lsm6dsl/lsm6dsl.c +++ b/drivers/sensor/lsm6dsl/lsm6dsl.c @@ -18,15 +18,17 @@ #include #include #include +#include #include "lsm6dsl.h" LOG_MODULE_REGISTER(LSM6DSL, CONFIG_SENSOR_LOG_LEVEL); static const uint16_t lsm6dsl_odr_map[] = {0, 12, 26, 52, 104, 208, 416, 833, - 1666, 3332, 6664}; + 1666, 3332, 6664, 1}; -#if defined(LSM6DSL_ACCEL_ODR_RUNTIME) || defined(LSM6DSL_GYRO_ODR_RUNTIME) +#if defined(LSM6DSL_ACCEL_ODR_RUNTIME) || defined(LSM6DSL_GYRO_ODR_RUNTIME) ||\ + defined(CONFIG_PM_DEVICE) static int lsm6dsl_freq_to_odr_val(uint16_t freq) { size_t i; @@ -48,8 +50,9 @@ static int lsm6dsl_odr_to_freq_val(uint16_t odr) return lsm6dsl_odr_map[odr]; } - /* invalid index, return last entry */ - return lsm6dsl_odr_map[ARRAY_SIZE(lsm6dsl_odr_map) - 1]; + /* invalid index, return the fastest entry (6.66kHz) */ + BUILD_ASSERT(ARRAY_SIZE(lsm6dsl_odr_map) > 10); + return lsm6dsl_odr_map[10]; } #ifdef LSM6DSL_ACCEL_FS_RUNTIME @@ -168,6 +171,8 @@ static int lsm6dsl_gyro_set_odr_raw(const struct device *dev, uint8_t odr) return -EIO; } + data->gyro_freq = lsm6dsl_odr_to_freq_val(odr); + return 0; } @@ -825,6 +830,59 @@ static int lsm6dsl_init(const struct device *dev) return 0; } +#ifdef CONFIG_PM_DEVICE +static int lsm6dsl_pm_action(const struct device *dev, + enum pm_device_action action) +{ + struct lsm6dsl_data *data = dev->data; + int ret = -EIO; + uint8_t accel_odr = 0; + uint8_t gyro_odr = 0; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + /* Restore saved ODR values */ + accel_odr = lsm6dsl_freq_to_odr_val(data->accel_freq); + ret = lsm6dsl_accel_set_odr_raw(dev, accel_odr); + if (ret < 0) { + LOG_ERR("Failed to resume accelerometer"); + break; + } + gyro_odr = lsm6dsl_freq_to_odr_val(data->gyro_freq); + ret = lsm6dsl_gyro_set_odr_raw(dev, gyro_odr); + if (ret < 0) { + LOG_ERR("Failed to resume gyro"); + break; + } + break; + case PM_DEVICE_ACTION_SUSPEND: + /* + * Set accelerometer ODR to power-down. Don't use the direct + * function to not overwrite the saved value + */ + ret = data->hw_tf->update_reg(dev, LSM6DSL_REG_CTRL1_XL, + LSM6DSL_MASK_CTRL1_XL_ODR_XL, 0); + if (ret < 0) { + LOG_ERR("Failed to suspend accelerometer"); + break; + } + /* Set gyro ODR to power-down */ + ret = data->hw_tf->update_reg(dev, LSM6DSL_REG_CTRL2_G, + LSM6DSL_MASK_CTRL2_G_ODR_G, 0); + if (ret < 0) { + LOG_ERR("Failed to suspend gyro"); + break; + } + + break; + default: + return -ENOTSUP; + } + + return ret; +} +#endif + #if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0 #warning "LSM6DSL driver enabled without any devices" @@ -836,9 +894,10 @@ static int lsm6dsl_init(const struct device *dev) */ #define LSM6DSL_DEVICE_INIT(inst) \ + PM_DEVICE_DT_INST_DEFINE(inst, lsm6dsl_pm_action); \ SENSOR_DEVICE_DT_INST_DEFINE(inst, \ lsm6dsl_init, \ - NULL, \ + PM_DEVICE_DT_INST_GET(inst), \ &lsm6dsl_data_##inst, \ &lsm6dsl_config_##inst, \ POST_KERNEL, \ diff --git a/drivers/sensor/lsm6dsl/lsm6dsl.h b/drivers/sensor/lsm6dsl/lsm6dsl.h index f424cbf2326e0d5..da176f4f6923f52 100644 --- a/drivers/sensor/lsm6dsl/lsm6dsl.h +++ b/drivers/sensor/lsm6dsl/lsm6dsl.h @@ -667,6 +667,7 @@ struct lsm6dsl_data { #endif const struct lsm6dsl_transfer_function *hw_tf; uint16_t accel_freq; + uint16_t gyro_freq; #ifdef CONFIG_LSM6DSL_TRIGGER const struct device *dev; diff --git a/drivers/sensor/lsm6dsl/lsm6dsl_trigger.c b/drivers/sensor/lsm6dsl/lsm6dsl_trigger.c index b84464cb39671ad..989d322678e71bb 100644 --- a/drivers/sensor/lsm6dsl/lsm6dsl_trigger.c +++ b/drivers/sensor/lsm6dsl/lsm6dsl_trigger.c @@ -97,8 +97,12 @@ static void lsm6dsl_thread_cb(const struct device *dev) } #ifdef CONFIG_LSM6DSL_TRIGGER_OWN_THREAD -static void lsm6dsl_thread(const struct device *dev) +static void lsm6dsl_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; struct lsm6dsl_data *drv_data = dev->data; while (1) { @@ -156,7 +160,7 @@ int lsm6dsl_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_LSM6DSL_THREAD_STACK_SIZE, - (k_thread_entry_t)lsm6dsl_thread, (void *)dev, + lsm6dsl_thread, (void *)dev, NULL, NULL, K_PRIO_COOP(CONFIG_LSM6DSL_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/lsm6dso/Kconfig b/drivers/sensor/lsm6dso/Kconfig index f1948a9769e8430..272deb6be950be0 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/lsm6dso/lsm6dso_trigger.c b/drivers/sensor/lsm6dso/lsm6dso_trigger.c index 8181c91c604b598..8f8bc5272820283 100644 --- a/drivers/sensor/lsm6dso/lsm6dso_trigger.c +++ b/drivers/sensor/lsm6dso/lsm6dso_trigger.c @@ -228,8 +228,13 @@ static void lsm6dso_gpio_callback(const struct device *dev, } #ifdef CONFIG_LSM6DSO_TRIGGER_OWN_THREAD -static void lsm6dso_thread(struct lsm6dso_data *lsm6dso) +static void lsm6dso_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct lsm6dso_data *lsm6dso = p1; + while (1) { k_sem_take(&lsm6dso->gpio_sem, K_FOREVER); lsm6dso_handle_interrupt(lsm6dso->dev); @@ -265,7 +270,7 @@ int lsm6dso_init_interrupt(const struct device *dev) k_thread_create(&lsm6dso->thread, lsm6dso->thread_stack, CONFIG_LSM6DSO_THREAD_STACK_SIZE, - (k_thread_entry_t)lsm6dso_thread, lsm6dso, + lsm6dso_thread, lsm6dso, NULL, NULL, K_PRIO_COOP(CONFIG_LSM6DSO_THREAD_PRIORITY), 0, K_NO_WAIT); k_thread_name_set(&lsm6dso->thread, "lsm6dso"); diff --git a/drivers/sensor/lsm6dso16is/Kconfig b/drivers/sensor/lsm6dso16is/Kconfig index eac3312d784c5c0..7994d6a782f6c44 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/lsm6dso16is/lsm6dso16is_trigger.c b/drivers/sensor/lsm6dso16is/lsm6dso16is_trigger.c index c9bcc313bad296d..93ce4f6c0b0c0bb 100644 --- a/drivers/sensor/lsm6dso16is/lsm6dso16is_trigger.c +++ b/drivers/sensor/lsm6dso16is/lsm6dso16is_trigger.c @@ -256,8 +256,13 @@ static void lsm6dso16is_gpio_callback(const struct device *dev, } #ifdef CONFIG_LSM6DSO16IS_TRIGGER_OWN_THREAD -static void lsm6dso16is_thread(struct lsm6dso16is_data *lsm6dso16is) +static void lsm6dso16is_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct lsm6dso16is_data *lsm6dso16is = p1; + while (1) { k_sem_take(&lsm6dso16is->gpio_sem, K_FOREVER); lsm6dso16is_handle_interrupt(lsm6dso16is->dev); @@ -293,7 +298,7 @@ int lsm6dso16is_init_interrupt(const struct device *dev) k_thread_create(&lsm6dso16is->thread, lsm6dso16is->thread_stack, CONFIG_LSM6DSO16IS_THREAD_STACK_SIZE, - (k_thread_entry_t)lsm6dso16is_thread, lsm6dso16is, + lsm6dso16is_thread, lsm6dso16is, NULL, NULL, K_PRIO_COOP(CONFIG_LSM6DSO16IS_THREAD_PRIORITY), 0, K_NO_WAIT); k_thread_name_set(&lsm6dso16is->thread, "lsm6dso16is"); diff --git a/drivers/sensor/lsm6dsv16x/Kconfig b/drivers/sensor/lsm6dsv16x/Kconfig index eb894ac2e993cb8..79463a0f4e8ec1f 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 b2bed66b47de49a..d4f9a2c850d3a8c 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) { @@ -919,9 +920,11 @@ static int lsm6dsv16x_init(const struct device *dev) */ #ifdef CONFIG_LSM6DSV16X_TRIGGER -#define LSM6DSV16X_CFG_IRQ(inst) \ +#define LSM6DSV16X_CFG_IRQ(inst) \ .trig_enabled = true, \ - .gpio_drdy = GPIO_DT_SPEC_INST_GET(inst, irq_gpios), \ + .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) @@ -937,9 +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), \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \ - (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.h b/drivers/sensor/lsm6dsv16x/lsm6dsv16x.h index 92a5e4cdcbaaf7f..2b3819b306ad693 100644 --- a/drivers/sensor/lsm6dsv16x/lsm6dsv16x.h +++ b/drivers/sensor/lsm6dsv16x/lsm6dsv16x.h @@ -57,7 +57,8 @@ struct lsm6dsv16x_config { uint8_t gyro_range; uint8_t drdy_pulsed; #ifdef CONFIG_LSM6DSV16X_TRIGGER - const struct gpio_dt_spec gpio_drdy; + const struct gpio_dt_spec int1_gpio; + const struct gpio_dt_spec int2_gpio; uint8_t drdy_pin; bool trig_enabled; #endif /* CONFIG_LSM6DSV16X_TRIGGER */ @@ -102,6 +103,8 @@ struct lsm6dsv16x_data { uint8_t gyro_fs; #ifdef CONFIG_LSM6DSV16X_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; diff --git a/drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c b/drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c index b82e371bc9c72a1..52bd7d6c0dd0452 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,14 +176,9 @@ 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(&cfg->gpio_drdy, + gpio_pin_interrupt_configure_dt(lsm6dsv16x->drdy_gpio, GPIO_INT_EDGE_TO_ACTIVE); } @@ -242,11 +187,10 @@ static void lsm6dsv16x_gpio_callback(const struct device *dev, { struct lsm6dsv16x_data *lsm6dsv16x = CONTAINER_OF(cb, struct lsm6dsv16x_data, gpio_cb); - const struct lsm6dsv16x_config *cfg = lsm6dsv16x->dev->config; ARG_UNUSED(pins); - gpio_pin_interrupt_configure_dt(&cfg->gpio_drdy, GPIO_INT_DISABLE); + gpio_pin_interrupt_configure_dt(lsm6dsv16x->drdy_gpio, GPIO_INT_DISABLE); #if defined(CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD) k_sem_give(&lsm6dsv16x->gpio_sem); @@ -256,8 +200,13 @@ static void lsm6dsv16x_gpio_callback(const struct device *dev, } #ifdef CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD -static void lsm6dsv16x_thread(struct lsm6dsv16x_data *lsm6dsv16x) +static void lsm6dsv16x_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct lsm6dsv16x_data *lsm6dsv16x = p1; + while (1) { k_sem_take(&lsm6dsv16x->gpio_sem, K_FOREVER); lsm6dsv16x_handle_interrupt(lsm6dsv16x->dev); @@ -282,8 +231,12 @@ int lsm6dsv16x_init_interrupt(const struct device *dev) stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; int ret; + lsm6dsv16x->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(&cfg->gpio_drdy)) { + if (!gpio_is_ready_dt(lsm6dsv16x->drdy_gpio)) { LOG_ERR("Cannot get pointer to drdy_gpio device"); return -EINVAL; } @@ -293,7 +246,7 @@ int lsm6dsv16x_init_interrupt(const struct device *dev) k_thread_create(&lsm6dsv16x->thread, lsm6dsv16x->thread_stack, CONFIG_LSM6DSV16X_THREAD_STACK_SIZE, - (k_thread_entry_t)lsm6dsv16x_thread, lsm6dsv16x, + lsm6dsv16x_thread, lsm6dsv16x, NULL, NULL, K_PRIO_COOP(CONFIG_LSM6DSV16X_THREAD_PRIORITY), 0, K_NO_WAIT); k_thread_name_set(&lsm6dsv16x->thread, "lsm6dsv16x"); @@ -301,7 +254,7 @@ int lsm6dsv16x_init_interrupt(const struct device *dev) lsm6dsv16x->work.handler = lsm6dsv16x_work_cb; #endif /* CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD */ - ret = gpio_pin_configure_dt(&cfg->gpio_drdy, GPIO_INPUT); + ret = gpio_pin_configure_dt(lsm6dsv16x->drdy_gpio, GPIO_INPUT); if (ret < 0) { LOG_DBG("Could not configure gpio"); return ret; @@ -309,9 +262,9 @@ int lsm6dsv16x_init_interrupt(const struct device *dev) gpio_init_callback(&lsm6dsv16x->gpio_cb, lsm6dsv16x_gpio_callback, - BIT(cfg->gpio_drdy.pin)); + BIT(lsm6dsv16x->drdy_gpio->pin)); - if (gpio_add_callback(cfg->gpio_drdy.port, &lsm6dsv16x->gpio_cb) < 0) { + if (gpio_add_callback(lsm6dsv16x->drdy_gpio->port, &lsm6dsv16x->gpio_cb) < 0) { LOG_DBG("Could not set gpio callback"); return -EIO; } @@ -328,6 +281,6 @@ int lsm6dsv16x_init_interrupt(const struct device *dev) return ret; } - return gpio_pin_interrupt_configure_dt(&cfg->gpio_drdy, + return gpio_pin_interrupt_configure_dt(lsm6dsv16x->drdy_gpio, GPIO_INT_EDGE_TO_ACTIVE); } diff --git a/drivers/sensor/lsm9ds0_gyro/lsm9ds0_gyro_trigger.c b/drivers/sensor/lsm9ds0_gyro/lsm9ds0_gyro_trigger.c index 35a46032406a7ca..08441deff791d57 100644 --- a/drivers/sensor/lsm9ds0_gyro/lsm9ds0_gyro_trigger.c +++ b/drivers/sensor/lsm9ds0_gyro/lsm9ds0_gyro_trigger.c @@ -80,8 +80,12 @@ static void lsm9ds0_gyro_gpio_drdy_callback(const struct device *dev, k_sem_give(&data->sem); } -static void lsm9ds0_gyro_thread_main(const struct device *dev) +static void lsm9ds0_gyro_thread_main(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; struct lsm9ds0_gyro_data *data = dev->data; while (1) { @@ -106,7 +110,7 @@ int lsm9ds0_gyro_init_interrupt(const struct device *dev) k_thread_create(&data->thread, data->thread_stack, CONFIG_LSM9DS0_GYRO_THREAD_STACK_SIZE, - (k_thread_entry_t)lsm9ds0_gyro_thread_main, + lsm9ds0_gyro_thread_main, (void *)dev, NULL, NULL, K_PRIO_COOP(10), 0, K_NO_WAIT); if (!gpio_is_ready_dt(&config->int_gpio)) { diff --git a/drivers/sensor/ltrf216a/CMakeLists.txt b/drivers/sensor/ltrf216a/CMakeLists.txt new file mode 100644 index 000000000000000..f15dcc346b884c5 --- /dev/null +++ b/drivers/sensor/ltrf216a/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(ltrf216a.c) diff --git a/drivers/sensor/ltrf216a/Kconfig b/drivers/sensor/ltrf216a/Kconfig new file mode 100644 index 000000000000000..fa9cfe9fdbfa935 --- /dev/null +++ b/drivers/sensor/ltrf216a/Kconfig @@ -0,0 +1,12 @@ +# LTR-F216A light sensor configuration options + +# Copyright (c) 2023 Tridonic +# SPDX-License-Identifier: Apache-2.0 + +config LTR_F216A + bool "LiteOn LTR-F216A Light Sensor" + default y + depends on DT_HAS_LTR_F216A_ENABLED + select I2C + help + Enable driver for LiteOn LTR-F216A light sensors. diff --git a/drivers/sensor/ltrf216a/ltrf216a.c b/drivers/sensor/ltrf216a/ltrf216a.c new file mode 100644 index 000000000000000..5f6f9282c7505a3 --- /dev/null +++ b/drivers/sensor/ltrf216a/ltrf216a.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2023 Tridonic + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ltr_f216a + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(ltrf216a, CONFIG_SENSOR_LOG_LEVEL); + +/* + * Driver for I2C illuminance sensor LiteOn LTR-F216A. + * + * Datasheet: + * + + * 7bit Address 0x53 + * 8bit Address 0xA6 read + * 8bit Address 0xA7 write + + * NOT IMPLEMENTED: + * - Interrupt + * - Modifying Gain (using default x3) + * - Modifying Resolution (using default 100ms) + * - Modifying Measurement Rate (using default 100ms) + * - Modifying Window Factor (using default 1) + */ + +#define LTRF216A_ALS_RESET_MASK BIT(4) +#define LTRF216A_ALS_ENABLE_MASK BIT(1) + +#define LTRF216A_ALS_DATA_STATUS BIT(3) + +/* Part Number ID 7:4 0b1011 = 0xB */ +/* Revision ID 3:0 0b0001 = 0x1*/ +#define LTRF216A_PART_ID_VALUE 0xB1 + +#define LTRF216A_MAIN_CTRL 0x00 +#define LTRF216A_ALS_MEAS_RES 0x04 +#define LTRF216A_ALS_GAIN 0x05 +#define LTRF216A_PART_ID 0x06 +#define LTRF216A_MAIN_STATUS 0x07 +#define LTRF216A_ALS_CLEAR_DATA_0 0x0a +#define LTRF216A_ALS_CLEAR_DATA_1 0x0b +#define LTRF216A_ALS_CLEAR_DATA_2 0x0c +#define LTRF216A_ALS_DATA_0 0x0d +#define LTRF216A_ALS_DATA_1 0x0e +#define LTRF216A_ALS_DATA_2 0x0f +#define LTRF216A_INT_CFG 0x19 +#define LTRF216A_INT_PST 0x1a +#define LTRF216A_ALS_THRES_UP_0 0x21 +#define LTRF216A_ALS_THRES_UP_1 0x22 +#define LTRF216A_ALS_THRES_UP_2 0x23 +#define LTRF216A_ALS_THRES_LOW_0 0x24 +#define LTRF216A_ALS_THRES_LOW_1 0x25 +#define LTRF216A_ALS_THRES_LOW_2 0x26 + +#define LTRF216A_WIN_FAC 1 + +#define LTRF216A_NUMBER_DATA_REGISTERS 3 + +struct ltrf216a_data { + uint8_t sample[3]; +}; + +struct ltrf216a_config { + struct i2c_dt_spec i2c; +}; + +static int ltrf216a_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct ltrf216a_data *drv_data = dev->data; + const struct ltrf216a_config *config = dev->config; + uint8_t status; + int result; + uint8_t value; + + __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_LIGHT); + + value = LTRF216A_ALS_ENABLE_MASK; + result = i2c_reg_write_byte_dt(&config->i2c, LTRF216A_MAIN_CTRL, LTRF216A_ALS_ENABLE_MASK); + if (result != 0) { + LOG_ERR("ltfr216a: enable failed"); + return result; + } + + result = i2c_reg_read_byte_dt(&config->i2c, LTRF216A_MAIN_STATUS, &status); + if (result != 0) { + LOG_ERR("ltfr216a: read main status failed"); + return -EIO; + } + + if ((status & LTRF216A_ALS_DATA_STATUS) == 0) { + LOG_WRN("ltfr216a: main status not ready"); + return -EBUSY; + } + + if (i2c_burst_read_dt(&config->i2c, LTRF216A_ALS_DATA_0, drv_data->sample, + LTRF216A_NUMBER_DATA_REGISTERS) != 0) { + LOG_ERR("ltfr216a: reading samples failed"); + return -EIO; + } + + return 0; +} + +static int ltrf216a_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct ltrf216a_data *drv_data = dev->data; + + if (chan != SENSOR_CHAN_LIGHT) { + return -ENOTSUP; + } + + uint32_t greendata = sys_get_le24(drv_data->sample); + + /* + * 0.45 -> 45 / 100, multiplied by 1000000 for millilux + * gain 3 (default), integration time 100ms=1 + */ + uint64_t microlux = (greendata * 45000 * LTRF216A_WIN_FAC * 10) / (3 * 1); + + val->val1 = microlux / 1000000; + val->val2 = microlux % 1000000; + + return 0; +} + +static const struct sensor_driver_api ltrf216a_driver_api = { + .sample_fetch = ltrf216a_sample_fetch, + .channel_get = ltrf216a_channel_get, +}; + +static int ltrf216a_chip_init(const struct device *dev) +{ + const struct ltrf216a_config *config = dev->config; + uint8_t value; + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("Bus device is not ready"); + return -ENODEV; + } + + if (i2c_reg_read_byte_dt(&config->i2c, LTRF216A_PART_ID, &value) != 0) { + return -EIO; + } + + if (value != LTRF216A_PART_ID_VALUE) { + LOG_ERR("Bad manufacturer id 0x%x", value); + return -ENOTSUP; + } + + return 0; +} + +#define LTRF216A_DEFINE(inst) \ + static struct ltrf216a_data ltrf216a_data_##inst; \ + \ + static const struct ltrf216a_config ltrf216a_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, ltrf216a_chip_init, NULL, <rf216a_data_##inst, \ + <rf216a_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, <rf216a_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(LTRF216A_DEFINE) diff --git a/drivers/sensor/max17055/max17055.c b/drivers/sensor/max17055/max17055.c index c2db82556239be0..139cef36a5d9a8a 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 bced243b1a8796f..f94de01fdc6eb05 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 cff6bca994027f6..9efc3221499f2fd 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/mc3419/CMakeLists.txt b/drivers/sensor/mc3419/CMakeLists.txt new file mode 100644 index 000000000000000..650f3e9777e947e --- /dev/null +++ b/drivers/sensor/mc3419/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2023 Linumiz + +zephyr_library() + +zephyr_library_sources(mc3419.c) +zephyr_library_sources_ifdef(CONFIG_MC3419_TRIGGER mc3419_trigger.c) diff --git a/drivers/sensor/mc3419/Kconfig b/drivers/sensor/mc3419/Kconfig new file mode 100644 index 000000000000000..81e0665c3e0ca8d --- /dev/null +++ b/drivers/sensor/mc3419/Kconfig @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2023 Linumiz + +menuconfig MC3419 + bool "MC3419 acclerometer driver" + default y + depends on DT_HAS_MEMSIC_MC3419_ENABLED + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_MEMSIC_MC3419),i2c) + help + Enable driver for MC3419 acclerometer. + +if MC3419 + +config MC3419_TRIGGER + bool "Trigger mode" + +if MC3419_TRIGGER + +config MC3419_TRIGGER_OWN_THREAD + bool "Use own thread" + help + Enable trigger to run in own thread. By + default it is global thread mode. + +config MC3419_THREAD_PRIORITY + int "Own thread priority" + depends on MC3419_TRIGGER_OWN_THREAD + default 10 + +config MC3419_THREAD_STACK_SIZE + int "Own thread stask size" + depends on MC3419_TRIGGER_OWN_THREAD + default 1024 + +endif # MC3419_TRIGGER + +config MC3419_DECIMATION_RATE + int "Enable decimation rate" + range 0 15 + default 15 + help + This helps in producing slower interrupt. Internal Data + Rate is divide by this decimation rate. If decimation rate + is 0 then internal data rate is equal to output data rate, + then it produce interrupt floods. + +endif # MC3419 diff --git a/drivers/sensor/mc3419/mc3419.c b/drivers/sensor/mc3419/mc3419.c new file mode 100644 index 000000000000000..41f69fd3646f98c --- /dev/null +++ b/drivers/sensor/mc3419/mc3419.c @@ -0,0 +1,314 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Linumiz + */ + +#define DT_DRV_COMPAT memsic_mc3419 + +#include +#include +#include +#include +#include +#include "mc3419.h" + +LOG_MODULE_REGISTER(MC3419, CONFIG_SENSOR_LOG_LEVEL); + +static const uint16_t mc3419_accel_sense_map[] = {1, 2, 4, 8, 6}; +static struct mc3419_odr_map odr_map_table[] = { + {25}, {50}, {62, 500}, {100}, + {125}, {250}, {500}, {1000} +}; + +static int mc3419_get_odr_value(uint16_t freq, uint16_t m_freq) +{ + for (int i = 0; i < ARRAY_SIZE(odr_map_table); i++) { + if (odr_map_table[i].freq == freq && + odr_map_table[i].mfreq == m_freq) { + return i; + } + } + + return -EINVAL; +} + +static inline int mc3419_set_op_mode(const struct mc3419_config *cfg, + enum mc3419_op_mode mode) +{ + return i2c_reg_write_byte_dt(&cfg->i2c, MC3419_REG_OP_MODE, mode); +} + +static int mc3419_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + int ret = 0; + const struct mc3419_config *cfg = dev->config; + struct mc3419_driver_data *data = dev->data; + + k_sem_take(&data->sem, K_FOREVER); + ret = i2c_burst_read_dt(&cfg->i2c, MC3419_REG_XOUT_L, + (uint8_t *)data->samples, + MC3419_SAMPLE_READ_SIZE); + k_sem_give(&data->sem); + return ret; +} + +static int mc3419_to_sensor_value(double sensitivity, int16_t *raw_data, + struct sensor_value *val) +{ + double value = sys_le16_to_cpu(*raw_data); + + value *= sensitivity * SENSOR_GRAVITY_DOUBLE / 1000; + + return sensor_value_from_double(val, value); +} + +static int mc3419_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + int ret = 0; + struct mc3419_driver_data *data = dev->data; + + k_sem_take(&data->sem, K_FOREVER); + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + ret = mc3419_to_sensor_value(data->sensitivity, &data->samples[0], val); + break; + case SENSOR_CHAN_ACCEL_Y: + ret = mc3419_to_sensor_value(data->sensitivity, &data->samples[1], val); + break; + case SENSOR_CHAN_ACCEL_Z: + ret = mc3419_to_sensor_value(data->sensitivity, &data->samples[2], val); + break; + case SENSOR_CHAN_ACCEL_XYZ: + ret = mc3419_to_sensor_value(data->sensitivity, &data->samples[0], &val[0]); + ret |= mc3419_to_sensor_value(data->sensitivity, &data->samples[1], &val[1]); + ret |= mc3419_to_sensor_value(data->sensitivity, &data->samples[2], &val[2]); + break; + default: + LOG_ERR("Unsupported channel"); + ret = -ENOTSUP; + } + + k_sem_give(&data->sem); + return ret; +} + +static int mc3419_set_accel_range(const struct device *dev, uint8_t range) +{ + int ret = 0; + const struct mc3419_config *cfg = dev->config; + struct mc3419_driver_data *data = dev->data; + + if (range >= MC3419_ACCL_RANGE_END) { + LOG_ERR("Accel resolution is out of range"); + return -EINVAL; + } + + ret = i2c_reg_update_byte_dt(&cfg->i2c, MC3419_REG_RANGE_SELECT_CTRL, + MC3419_RANGE_MASK, range << 4); + if (ret < 0) { + LOG_ERR("Failed to set resolution (%d)", ret); + return ret; + } + + data->sensitivity = (double)(mc3419_accel_sense_map[range] * + SENSOR_GRAIN_VALUE); + + return 0; +} + +static int mc3419_set_odr(const struct device *dev, + const struct sensor_value *val) +{ + int ret = 0; + int data_rate = 0; + const struct mc3419_config *cfg = dev->config; + + ret = mc3419_get_odr_value(val->val1, val->val2); + if (ret < 0) { + LOG_ERR("Failed to get odr value from odr map (%d)", ret); + return ret; + } + + data_rate = MC3419_BASE_ODR_VAL + ret; + + ret = i2c_reg_write_byte_dt(&cfg->i2c, MC3419_REG_SAMPLE_RATE, + data_rate); + if (ret < 0) { + LOG_ERR("Failed to set ODR (%d)", ret); + return ret; + } + + LOG_DBG("Set ODR Rate to 0x%x", data_rate); + ret = i2c_reg_write_byte_dt(&cfg->i2c, MC3419_REG_SAMPLE_RATE_2, + CONFIG_MC3419_DECIMATION_RATE); + if (ret < 0) { + LOG_ERR("Failed to set decimation rate (%d)", ret); + return ret; + } + + return 0; +} + +#if defined(CONFIG_MC3419_TRIGGER) +static int mc3419_set_anymotion_threshold(const struct device *dev, + const struct sensor_value *val) +{ + int ret = 0; + const struct mc3419_config *cfg = dev->config; + uint8_t buf[3] = {0}; + + if (val->val1 > MC3419_ANY_MOTION_THRESH_MAX) { + return -EINVAL; + } + + buf[0] = MC3419_REG_ANY_MOTION_THRES; + sys_put_le16((uint16_t)val->val1, &buf[1]); + + ret = i2c_write_dt(&cfg->i2c, buf, sizeof(buf)); + if (ret < 0) { + LOG_ERR("Failed to set anymotion threshold (%d)", ret); + return ret; + } + + return 0; +} + +static int mc3419_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + int ret = 0; + const struct mc3419_config *cfg = dev->config; + struct mc3419_driver_data *data = dev->data; + + k_sem_take(&data->sem, K_FOREVER); + ret = mc3419_set_op_mode(cfg, MC3419_MODE_STANDBY); + if (ret < 0) { + goto exit; + } + + ret = mc3419_configure_trigger(dev, trig, handler); + if (ret < 0) { + LOG_ERR("Failed to set trigger (%d)", ret); + } + +exit: + mc3419_set_op_mode(cfg, MC3419_MODE_WAKE); + + k_sem_give(&data->sem); + return ret; +} +#endif + +static int mc3419_attr_set(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + int ret = 0; + struct mc3419_driver_data *data = dev->data; + + if (chan != SENSOR_CHAN_ACCEL_X && + chan != SENSOR_CHAN_ACCEL_Y && + chan != SENSOR_CHAN_ACCEL_Z && + chan != SENSOR_CHAN_ACCEL_XYZ) { + LOG_ERR("Not supported on this channel."); + return -ENOTSUP; + } + + k_sem_take(&data->sem, K_FOREVER); + ret = mc3419_set_op_mode(dev->config, MC3419_MODE_STANDBY); + if (ret < 0) { + goto exit; + } + + switch (attr) { + case SENSOR_ATTR_FULL_SCALE: + ret = mc3419_set_accel_range(dev, val->val1); + break; + case SENSOR_ATTR_SAMPLING_FREQUENCY: + ret = mc3419_set_odr(dev, val); + break; +#if defined(CONFIG_MC3419_TRIGGER) + case SENSOR_ATTR_SLOPE_TH: + ret = mc3419_set_anymotion_threshold(dev, val); + break; +#endif + default: + LOG_ERR("ACCEL attribute is not supported"); + ret = -EINVAL; + } + +exit: + mc3419_set_op_mode(dev->config, MC3419_MODE_WAKE); + + k_sem_give(&data->sem); + return ret; +} + +static int mc3419_init(const struct device *dev) +{ + int ret = 0; + struct mc3419_driver_data *data = dev->data; + const struct mc3419_config *cfg = dev->config; + + if (!(i2c_is_ready_dt(&cfg->i2c))) { + LOG_ERR("Bus device is not ready"); + return -ENODEV; + } + + k_sem_init(&data->sem, 1, 1); + +#if defined(CONFIG_MC3419_TRIGGER) + ret = mc3419_trigger_init(dev); + if (ret < 0) { + LOG_ERR("Could not initialize interrupts"); + return ret; + } +#endif + + /* Leave the sensor in default power on state, will be + * enabled by configure attr or setting trigger. + */ + + LOG_INF("MC3419 Initialized"); + + return ret; +} + +static const struct sensor_driver_api mc3419_api = { + .attr_set = mc3419_attr_set, +#if defined(CONFIG_MC3419_TRIGGER) + .trigger_set = mc3419_trigger_set, +#endif + .sample_fetch = mc3419_sample_fetch, + .channel_get = mc3419_channel_get, +}; + +#if defined(CONFIG_MC3419_TRIGGER) +#define MC3419_CFG_IRQ(idx) \ + .int_gpio = GPIO_DT_SPEC_INST_GET_OR(idx, int_gpios, { 0 }), \ + .int_cfg = DT_INST_PROP(idx, int_pin2), +#else +#define MC3419_CFG_IRQ(idx) +#endif + +#define MC3419_DEFINE(idx) \ + static const struct mc3419_config mc3419_config_##idx = { \ + .i2c = I2C_DT_SPEC_INST_GET(idx), \ + MC3419_CFG_IRQ(idx) \ + }; \ + static struct mc3419_driver_data mc3419_data_##idx; \ + SENSOR_DEVICE_DT_INST_DEFINE(idx, \ + mc3419_init, NULL, \ + &mc3419_data_##idx, \ + &mc3419_config_##idx, \ + POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, \ + &mc3419_api); + +DT_INST_FOREACH_STATUS_OKAY(MC3419_DEFINE) diff --git a/drivers/sensor/mc3419/mc3419.h b/drivers/sensor/mc3419/mc3419.h new file mode 100644 index 000000000000000..6085c60bc483764 --- /dev/null +++ b/drivers/sensor/mc3419/mc3419.h @@ -0,0 +1,102 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Linumiz + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_MC3419_H_ +#define ZEPHYR_DRIVERS_SENSOR_MC3419_H_ + +#include +#include +#include +#include +#include + +/* Registers */ +#define MC3419_REG_INT_CTRL 0x06 +#define MC3419_REG_OP_MODE 0x07 +#define MC3419_REG_SAMPLE_RATE 0x08 +#define MC3419_REG_MOTION_CTRL 0x09 +#define MC3419_REG_XOUT_L 0x0D +#define MC3419_REG_YOUT_L 0x0F +#define MC3419_REG_ZOUT_L 0x11 +#define MC3419_REG_STATUS 0x13 +#define MC3419_REG_INT_STATUS 0x14 +#define MC3419_REG_RANGE_SELECT_CTRL 0x20 +#define MC3419_REG_SAMPLE_RATE_2 0x30 +#define MC3419_REG_COMM_CTRL 0x31 +#define MC3419_REG_ANY_MOTION_THRES 0x43 + +#define MC3419_RANGE_MASK GENMASK(6, 4) +#define MC3419_DATA_READY_MASK BIT(7) +#define MC3419_ANY_MOTION_MASK BIT(2) +#define MC3419_INT_CLEAR 0x00 +#define MC3419_INT_ROUTE 0x10 + +#define MC3419_ANY_MOTION_THRESH_MAX 0x7FFF +#define MC3419_SAMPLE_SIZE 3 +#define MC3419_SAMPLE_READ_SIZE (MC3419_SAMPLE_SIZE * (sizeof(int16_t))) + +#define SENSOR_GRAIN_VALUE (61LL / 1000.0) +#define SENSOR_GRAVITY_DOUBLE (SENSOR_G / 1000000.0) +#define MC3419_BASE_ODR_VAL 0x10 + +#define MC3419_TRIG_DATA_READY 0 +#define MC3419_TRIG_ANY_MOTION 1 +#define MC3419_TRIG_SIZE 2 + +enum mc3419_op_mode { + MC3419_MODE_STANDBY = 0x00, + MC3419_MODE_WAKE = 0x01 +}; + +struct mc3419_odr_map { + int16_t freq; + int16_t mfreq; +}; + +enum mc3419_accl_range { + MC3419_ACCl_RANGE_2G, + MC3419_ACCl_RANGE_4G, + MC3419_ACCl_RANGE_8G, + MC3419_ACCl_RANGE_16G, + MC3419_ACCl_RANGE_12G, + MC3419_ACCL_RANGE_END +}; + +struct mc3419_config { + struct i2c_dt_spec i2c; +#if defined(CONFIG_MC3419_TRIGGER) + struct gpio_dt_spec int_gpio; + bool int_cfg; +#endif +}; + +struct mc3419_driver_data { + double sensitivity; + struct k_sem sem; + int16_t samples[MC3419_SAMPLE_SIZE]; +#if defined(CONFIG_MC3419_TRIGGER) + const struct device *gpio_dev; + struct gpio_callback gpio_cb; + sensor_trigger_handler_t handler[MC3419_TRIG_SIZE]; + const struct sensor_trigger *trigger[MC3419_TRIG_SIZE]; +#if defined(CONFIG_MC3419_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_MC3419_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem trig_sem; +#else + struct k_work work; +#endif +#endif +}; + +#if defined(CONFIG_MC3419_TRIGGER) +int mc3419_trigger_init(const struct device *dev); +int mc3419_configure_trigger(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); +#endif + +#endif diff --git a/drivers/sensor/mc3419/mc3419_trigger.c b/drivers/sensor/mc3419/mc3419_trigger.c new file mode 100644 index 000000000000000..ab44fe79d240f2e --- /dev/null +++ b/drivers/sensor/mc3419/mc3419_trigger.c @@ -0,0 +1,178 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Linumiz + */ + +#include "mc3419.h" +#include + +LOG_MODULE_DECLARE(MC3419, CONFIG_SENSOR_LOG_LEVEL); + +static void mc3419_gpio_callback(const struct device *dev, + struct gpio_callback *cb, + uint32_t pin_mask) +{ + struct mc3419_driver_data *data = CONTAINER_OF(cb, + struct mc3419_driver_data, gpio_cb); + + const struct mc3419_config *cfg = data->gpio_dev->config; + + if ((pin_mask & BIT(cfg->int_gpio.pin)) == 0U) { + return; + } + +#if defined(CONFIG_MC3419_TRIGGER_OWN_THREAD) + k_sem_give(&data->trig_sem); +#else + k_work_submit(&data->work); +#endif +} + +static void mc3419_process_int(const struct device *dev) +{ + int ret = 0; + const struct mc3419_config *cfg = dev->config; + const struct mc3419_driver_data *data = dev->data; + uint8_t int_source = 0; + + ret = i2c_reg_read_byte_dt(&cfg->i2c, MC3419_REG_INT_STATUS, &int_source); + if (ret < 0) { + goto exit; + } + + if (int_source & MC3419_DATA_READY_MASK) { + if (data->handler[MC3419_TRIG_DATA_READY]) { + data->handler[MC3419_TRIG_DATA_READY](dev, + data->trigger[MC3419_TRIG_DATA_READY]); + } + } + + if (int_source & MC3419_ANY_MOTION_MASK) { + if (data->handler[MC3419_TRIG_ANY_MOTION]) { + data->handler[MC3419_TRIG_ANY_MOTION](dev, + data->trigger[MC3419_TRIG_ANY_MOTION]); + } + } +exit: + ret = i2c_reg_write_byte_dt(&cfg->i2c, MC3419_REG_INT_STATUS, + MC3419_INT_CLEAR); + if (ret < 0) { + LOG_ERR("Failed to clear interrupt (%d)", ret); + } +} + +#if defined(CONFIG_MC3419_TRIGGER_OWN_THREAD) +static void mc3419_thread(struct mc3419_driver_data *data) +{ + while (1) { + k_sem_take(&data->trig_sem, K_FOREVER); + mc3419_process_int(data->gpio_dev); + } +} +#else +static void mc3419_work_cb(struct k_work *work) +{ + struct mc3419_driver_data *data = CONTAINER_OF(work, + struct mc3419_driver_data, work); + + mc3419_process_int(data->gpio_dev); +} +#endif + +int mc3419_configure_trigger(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + int ret = 0; + uint8_t buf = 0; + const struct mc3419_config *cfg = dev->config; + struct mc3419_driver_data *data = dev->data; + + if (!(trig->type & SENSOR_TRIG_DATA_READY) && + !(trig->type & SENSOR_TRIG_MOTION)) { + LOG_ERR("Unsupported sensor trigger"); + return -ENOTSUP; + } + + if (trig->type & SENSOR_TRIG_DATA_READY) { + data->handler[MC3419_TRIG_DATA_READY] = handler; + data->trigger[MC3419_TRIG_DATA_READY] = trig; + buf |= MC3419_DATA_READY_MASK; + } + + if (trig->type & SENSOR_TRIG_MOTION) { + uint8_t int_mask = MC3419_ANY_MOTION_MASK; + + buf |= MC3419_ANY_MOTION_MASK; + data->handler[MC3419_TRIG_ANY_MOTION] = handler; + data->trigger[MC3419_TRIG_ANY_MOTION] = trig; + + ret = i2c_reg_update_byte_dt(&cfg->i2c, MC3419_REG_MOTION_CTRL, + int_mask, handler ? int_mask : 0); + if (ret < 0) { + LOG_ERR("Failed to configure motion interrupt (%d)", ret); + return ret; + } + } + + ret = i2c_reg_update_byte_dt(&cfg->i2c, MC3419_REG_INT_CTRL, + buf, buf); + if (ret < 0) { + LOG_ERR("Failed to configure interrupt (%d)", ret); + return ret; + } + + gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_FALLING); + + return ret; +} + +int mc3419_trigger_init(const struct device *dev) +{ + int ret = 0; + struct mc3419_driver_data *data = dev->data; + const struct mc3419_config *cfg = dev->config; + + if (!gpio_is_ready_dt(&cfg->int_gpio)) { + LOG_ERR("GPIO port %s not ready", cfg->int_gpio.port->name); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Failed to configure interrupt gpio"); + return ret; + } + + data->gpio_dev = dev; + +#if defined(CONFIG_MC3419_TRIGGER_OWN_THREAD) + k_sem_init(&data->trig_sem, 0, 1); + k_thread_create(&data->thread, data->thread_stack, + CONFIG_MC3419_THREAD_STACK_SIZE, + (k_thread_entry_t)mc3419_thread, data, NULL, + NULL, K_PRIO_COOP(CONFIG_MC3419_THREAD_PRIORITY), 0, + K_NO_WAIT); +#else + k_work_init(&data->work, mc3419_work_cb); +#endif + gpio_init_callback(&data->gpio_cb, mc3419_gpio_callback, + BIT(cfg->int_gpio.pin)); + ret = gpio_add_callback(cfg->int_gpio.port, &data->gpio_cb); + if (ret < 0) { + LOG_ERR("Failed to set int callback"); + return ret; + } + + if (cfg->int_cfg) { + ret = i2c_reg_write_byte_dt(&cfg->i2c, MC3419_REG_COMM_CTRL, + MC3419_INT_ROUTE); + if (ret < 0) { + LOG_ERR("Failed to route the interrupt to INT2 pin (%d)", ret); + return ret; + } + } + + return 0; +} diff --git a/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c b/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c index 49fbbac8fe2d50e..9ee732475da93c3 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 ed5fb8b97f7d266..dfec3a5d064def4 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/mcp9808/mcp9808_trigger.c b/drivers/sensor/mcp9808/mcp9808_trigger.c index 627f77f04b5021e..6c42661d07397b5 100644 --- a/drivers/sensor/mcp9808/mcp9808_trigger.c +++ b/drivers/sensor/mcp9808/mcp9808_trigger.c @@ -129,8 +129,13 @@ static void alert_cb(const struct device *dev, struct gpio_callback *cb, #ifdef CONFIG_MCP9808_TRIGGER_OWN_THREAD -static void mcp9808_thread_main(struct mcp9808_data *data) +static void mcp9808_thread_main(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct mcp9808_data *data = p1; + while (true) { k_sem_take(&data->sem, K_FOREVER); process_int(data->dev); @@ -169,7 +174,7 @@ int mcp9808_setup_interrupt(const struct device *dev) k_thread_create(&mcp9808_thread, mcp9808_thread_stack, CONFIG_MCP9808_THREAD_STACK_SIZE, - (k_thread_entry_t)mcp9808_thread_main, data, NULL, NULL, + mcp9808_thread_main, data, NULL, NULL, K_PRIO_COOP(CONFIG_MCP9808_THREAD_PRIORITY), 0, K_NO_WAIT); #else /* CONFIG_MCP9808_TRIGGER_GLOBAL_THREAD */ diff --git a/drivers/sensor/mpu6050/mpu6050.c b/drivers/sensor/mpu6050/mpu6050.c index 34ce2d7d2605a60..f00ca138c78c660 100644 --- a/drivers/sensor/mpu6050/mpu6050.c +++ b/drivers/sensor/mpu6050/mpu6050.c @@ -161,7 +161,7 @@ int mpu6050_init(const struct device *dev) return -EIO; } - if (id != MPU6050_CHIP_ID && id != MPU9250_CHIP_ID) { + if ((id != MPU6050_CHIP_ID) && (id != MPU9250_CHIP_ID) && (id != MPU6880_CHIP_ID)) { LOG_ERR("Invalid chip ID."); return -EINVAL; } diff --git a/drivers/sensor/mpu6050/mpu6050.h b/drivers/sensor/mpu6050/mpu6050.h index 305704a4596602e..0bc20a5c0704be8 100644 --- a/drivers/sensor/mpu6050/mpu6050.h +++ b/drivers/sensor/mpu6050/mpu6050.h @@ -17,6 +17,7 @@ #define MPU6050_REG_CHIP_ID 0x75 #define MPU6050_CHIP_ID 0x68 #define MPU9250_CHIP_ID 0x71 +#define MPU6880_CHIP_ID 0x19 #define MPU6050_REG_GYRO_CFG 0x1B #define MPU6050_GYRO_FS_SHIFT 3 diff --git a/drivers/sensor/mpu6050/mpu6050_trigger.c b/drivers/sensor/mpu6050/mpu6050_trigger.c index 5415dbe1f416d39..69d45ea01829956 100644 --- a/drivers/sensor/mpu6050/mpu6050_trigger.c +++ b/drivers/sensor/mpu6050/mpu6050_trigger.c @@ -77,8 +77,13 @@ static void mpu6050_thread_cb(const struct device *dev) } #ifdef CONFIG_MPU6050_TRIGGER_OWN_THREAD -static void mpu6050_thread(struct mpu6050_data *drv_data) +static void mpu6050_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct mpu6050_data *drv_data = p1; + while (1) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); mpu6050_thread_cb(drv_data->dev); @@ -131,7 +136,7 @@ int mpu6050_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_MPU6050_THREAD_STACK_SIZE, - (k_thread_entry_t)mpu6050_thread, drv_data, + mpu6050_thread, drv_data, NULL, NULL, K_PRIO_COOP(CONFIG_MPU6050_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_MPU6050_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/mpu9250/mpu9250_trigger.c b/drivers/sensor/mpu9250/mpu9250_trigger.c index fdfeb016b191f19..5619bfb50dc554d 100644 --- a/drivers/sensor/mpu9250/mpu9250_trigger.c +++ b/drivers/sensor/mpu9250/mpu9250_trigger.c @@ -94,8 +94,13 @@ static void mpu9250_thread_cb(const struct device *dev) } #ifdef CONFIG_MPU9250_TRIGGER_OWN_THREAD -static void mpu9250_thread(struct mpu9250_data *drv_data) +static void mpu9250_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct mpu9250_data *drv_data = p1; + while (1) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); mpu9250_thread_cb(drv_data->dev); @@ -160,7 +165,7 @@ int mpu9250_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_MPU9250_THREAD_STACK_SIZE, - (k_thread_entry_t)mpu9250_thread, drv_data, + mpu9250_thread, drv_data, NULL, NULL, K_PRIO_COOP(CONFIG_MPU9250_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_MPU9250_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/npm1300_charger/npm1300_charger.c b/drivers/sensor/npm1300_charger/npm1300_charger.c index 43ac54e8ca8f64c..c6cfd8cbe2e90bf 100644 --- a/drivers/sensor/npm1300_charger/npm1300_charger.c +++ b/drivers/sensor/npm1300_charger/npm1300_charger.c @@ -20,6 +20,7 @@ struct npm1300_charger_config { int32_t dischg_limit_microamp; int32_t vbus_limit_microamp; int32_t temp_thresholds[4U]; + int32_t dietemp_thresholds[2U]; uint32_t thermistor_ohms; uint16_t thermistor_beta; uint8_t thermistor_idx; @@ -34,6 +35,7 @@ struct npm1300_charger_data { uint16_t voltage; uint16_t current; uint16_t temp; + uint16_t dietemp; uint8_t status; uint8_t error; uint8_t ibat_stat; @@ -57,6 +59,7 @@ struct npm1300_charger_data { #define CHGR_OFFSET_TRICKLE_SEL 0x0EU #define CHGR_OFFSET_ITERM_SEL 0x0FU #define CHGR_OFFSET_NTC_TEMPS 0x10U +#define CHGR_OFFSET_DIE_TEMPS 0x18U #define CHGR_OFFSET_CHG_STAT 0x34U #define CHGR_OFFSET_ERR_REASON 0x36U #define CHGR_OFFSET_VBATLOW_EN 0x50U @@ -64,6 +67,7 @@ struct npm1300_charger_data { /* nPM1300 ADC register offsets */ #define ADC_OFFSET_TASK_VBAT 0x00U #define ADC_OFFSET_TASK_TEMP 0x01U +#define ADC_OFFSET_TASK_DIE 0x02U #define ADC_OFFSET_CONFIG 0x09U #define ADC_OFFSET_NTCR_SEL 0x0AU #define ADC_OFFSET_TASK_AUTO 0x0CU @@ -71,7 +75,10 @@ struct npm1300_charger_data { #define ADC_OFFSET_IBAT_EN 0x24U /* nPM1300 VBUS register offsets */ +#define VBUS_OFFSET_ILIMUPDATE 0x00U +#define VBUS_OFFSET_ILIM 0x01U #define VBUS_OFFSET_ILIMSTARTUP 0x02U +#define VBUS_OFFSET_DETECT 0x05U #define VBUS_OFFSET_STATUS 0x07U /* Ibat status */ @@ -99,12 +106,27 @@ struct adc_results_t { #define ADC_LSB_MASK 0x03U #define ADC_LSB_VBAT_SHIFT 0U #define ADC_LSB_NTC_SHIFT 2U +#define ADC_LSB_DIE_SHIFT 4U #define ADC_LSB_IBAT_SHIFT 4U /* NTC temp masks */ #define NTCTEMP_MSB_SHIFT 2U #define NTCTEMP_LSB_MASK 0x03U +/* dietemp masks */ +#define DIETEMP_MSB_SHIFT 2U +#define DIETEMP_LSB_MASK 0x03U + +/* VBUS masks */ +#define DETECT_HI_MASK 0x0AU +#define DETECT_HI_CURRENT 1500000 +#define DETECT_LO_CURRENT 500000 + +/* Dietemp calculation constants */ +#define DIETEMP_OFFSET_MDEGC 394670 +#define DIETEMP_FACTOR_MUL 3963000 +#define DIETEMP_FACTOR_DIV 5000 + /* Linear range for charger terminal voltage */ static const struct linear_range charger_volt_ranges[] = { LINEAR_RANGE_INIT(3500000, 50000, 0U, 3U), LINEAR_RANGE_INIT(4000000, 50000, 4U, 13U)}; @@ -132,6 +154,17 @@ static void calc_temp(const struct npm1300_charger_config *const config, uint16_ valp->val2 = (int32_t)(fmodf(temp, 1.f) * 1000000.f); } +static void calc_dietemp(const struct npm1300_charger_config *const config, uint16_t code, + struct sensor_value *valp) +{ + /* Ref: Datasheet Figure 36: Die temperature (Celcius) */ + int32_t temp = + DIETEMP_OFFSET_MDEGC - (((int32_t)code * DIETEMP_FACTOR_MUL) / DIETEMP_FACTOR_DIV); + + valp->val1 = temp / 1000; + valp->val2 = (temp % 1000) * 1000; +} + static uint32_t calc_ntc_res(const struct npm1300_charger_config *const config, int32_t temp_mdegc) { float inv_t0 = 1.f / 298.15f; @@ -159,13 +192,11 @@ static void calc_current(const struct npm1300_charger_config *const config, full_scale_ma = config->dischg_limit_microamp / 1000; break; case IBAT_STAT_CHARGE_TRICKLE: - full_scale_ma = -config->current_microamp / 10000; - break; + /* Fallthrough */ case IBAT_STAT_CHARGE_COOL: - full_scale_ma = -config->current_microamp / 2000; - break; + /* Fallthrough */ case IBAT_STAT_CHARGE_NORMAL: - full_scale_ma = -config->current_microamp / 1000; + full_scale_ma = -config->current_microamp / 800; break; default: full_scale_ma = 0; @@ -213,6 +244,9 @@ int npm1300_charger_channel_get(const struct device *dev, enum sensor_channel ch valp->val1 = config->dischg_limit_microamp / 1000000; valp->val2 = config->dischg_limit_microamp % 1000000; break; + case SENSOR_CHAN_DIE_TEMP: + calc_dietemp(config, data->dietemp, valp); + break; default: return -ENOTSUP; } @@ -247,11 +281,12 @@ int npm1300_charger_sample_fetch(const struct device *dev, enum sensor_channel c data->voltage = adc_get_res(results.msb_vbat, results.lsb_a, ADC_LSB_VBAT_SHIFT); data->temp = adc_get_res(results.msb_ntc, results.lsb_a, ADC_LSB_NTC_SHIFT); + data->dietemp = adc_get_res(results.msb_die, results.lsb_a, ADC_LSB_DIE_SHIFT); data->current = adc_get_res(results.msb_ibat, results.lsb_b, ADC_LSB_IBAT_SHIFT); data->ibat_stat = results.ibat_stat; - /* Trigger temperature measurement */ - ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_TASK_TEMP, 1U); + /* Trigger ntc and die temperature measurements */ + ret = mfd_npm1300_reg_write2(config->mfd, ADC_BASE, ADC_OFFSET_TASK_TEMP, 1U, 1U); if (ret != 0) { return ret; } @@ -293,6 +328,29 @@ static int set_ntc_thresholds(const struct npm1300_charger_config *const config) return 0; } +static int set_dietemp_thresholds(const struct npm1300_charger_config *const config) +{ + for (uint8_t idx = 0U; idx < 2U; idx++) { + if (config->dietemp_thresholds[idx] < INT32_MAX) { + /* Ref: Datasheet section 6.2.6: Charger thermal regulation */ + int32_t numerator = + (DIETEMP_OFFSET_MDEGC - config->dietemp_thresholds[idx]) * + DIETEMP_FACTOR_DIV; + uint16_t code = DIV_ROUND_CLOSEST(numerator, DIETEMP_FACTOR_MUL); + + int ret = mfd_npm1300_reg_write2( + config->mfd, CHGR_BASE, CHGR_OFFSET_DIE_TEMPS + (idx * 2U), + code >> DIETEMP_MSB_SHIFT, code & DIETEMP_LSB_MASK); + + if (ret != 0) { + return ret; + } + } + } + + return 0; +} + static int npm1300_charger_attr_get(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, struct sensor_value *val) { @@ -312,6 +370,32 @@ static int npm1300_charger_attr_get(const struct device *dev, enum sensor_channe val->val2 = 0U; } return ret; + + case SENSOR_CHAN_CURRENT: + if (attr != SENSOR_ATTR_UPPER_THRESH) { + return -ENOTSUP; + } + + ret = mfd_npm1300_reg_read(config->mfd, VBUS_BASE, VBUS_OFFSET_DETECT, &data); + if (ret < 0) { + return ret; + } + + if (data == 0U) { + /* No charger connected */ + val->val1 = 0; + val->val2 = 0; + } else if ((data & DETECT_HI_MASK) != 0U) { + /* CC1 or CC2 indicate 1.5A or 3A capability */ + val->val1 = DETECT_HI_CURRENT / 1000000; + val->val2 = DETECT_HI_CURRENT % 1000000; + } else { + val->val1 = DETECT_LO_CURRENT / 1000000; + val->val2 = DETECT_LO_CURRENT % 1000000; + } + + return 0; + default: return -ENOTSUP; } @@ -323,12 +407,12 @@ static int npm1300_charger_attr_set(const struct device *dev, enum sensor_channe const struct npm1300_charger_config *const config = dev->config; int ret; + if (attr != SENSOR_ATTR_CONFIGURATION) { + return -ENOTSUP; + } + switch ((uint32_t)chan) { case SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT: - if (attr != SENSOR_ATTR_CONFIGURATION) { - return -ENOTSUP; - } - if (val->val1 == 0) { /* Disable charging */ return mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_EN_CLR, @@ -342,6 +426,27 @@ static int npm1300_charger_attr_set(const struct device *dev, enum sensor_channe } return mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_EN_SET, 1U); + case SENSOR_CHAN_CURRENT: + /* Set vbus current limit */ + int32_t current = (val->val1 * 1000000) + val->val2; + uint16_t idx; + + ret = linear_range_group_get_win_index(vbus_current_ranges, + ARRAY_SIZE(vbus_current_ranges), current, + current, &idx); + + if (ret == -EINVAL) { + return ret; + } + + ret = mfd_npm1300_reg_write(config->mfd, VBUS_BASE, VBUS_OFFSET_ILIM, idx); + if (ret != 0) { + return ret; + } + + /* Switch to new current limit, this will be reset automatically on USB removal */ + return mfd_npm1300_reg_write(config->mfd, VBUS_BASE, VBUS_OFFSET_ILIMUPDATE, 1U); + default: return -ENOTSUP; } @@ -357,7 +462,7 @@ int npm1300_charger_init(const struct device *dev) return -ENODEV; } - /* Configure thermistor */ + /* Configure temperature thresholds */ ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_NTCR_SEL, config->thermistor_idx + 1U); if (ret != 0) { @@ -369,6 +474,11 @@ int npm1300_charger_init(const struct device *dev) return ret; } + ret = set_dietemp_thresholds(config); + if (ret != 0) { + return ret; + } + /* Configure termination voltages */ ret = linear_range_group_get_win_index(charger_volt_ranges, ARRAY_SIZE(charger_volt_ranges), config->term_microvolt, config->term_microvolt, @@ -458,8 +568,8 @@ int npm1300_charger_init(const struct device *dev) return ret; } - /* Trigger temperature measurement */ - ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_TASK_TEMP, 1U); + /* Trigger ntc and die temperature measurements */ + ret = mfd_npm1300_reg_write2(config->mfd, ADC_BASE, ADC_OFFSET_TASK_TEMP, 1U, 1U); if (ret != 0) { return ret; } @@ -523,6 +633,9 @@ static const struct sensor_driver_api npm1300_charger_battery_driver_api = { .iterm_sel = DT_INST_ENUM_IDX(n, term_current_percent), \ .vbatlow_charge_enable = DT_INST_PROP(n, vbatlow_charge_enable), \ .disable_recharge = DT_INST_PROP(n, disable_recharge), \ + .dietemp_thresholds = {DT_INST_PROP_OR(n, dietemp_stop_millidegrees, INT32_MAX), \ + DT_INST_PROP_OR(n, dietemp_resume_millidegrees, \ + INT32_MAX)}, \ .temp_thresholds = {DT_INST_PROP_OR(n, thermistor_cold_millidegrees, INT32_MAX), \ DT_INST_PROP_OR(n, thermistor_cool_millidegrees, INT32_MAX), \ DT_INST_PROP_OR(n, thermistor_warm_millidegrees, INT32_MAX), \ diff --git a/drivers/sensor/ntc_thermistor/Kconfig b/drivers/sensor/ntc_thermistor/Kconfig index 8ab04aaf184a30d..140d324e9aad0ca 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 4f76ddc30f8ebfb..185e8c27673425f 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/nuvoton_adc_cmp_npcx/adc_cmp_npcx.c b/drivers/sensor/nuvoton_adc_cmp_npcx/adc_cmp_npcx.c index ff1871e8a40a8aa..cba37069ce9df28 100644 --- a/drivers/sensor/nuvoton_adc_cmp_npcx/adc_cmp_npcx.c +++ b/drivers/sensor/nuvoton_adc_cmp_npcx/adc_cmp_npcx.c @@ -251,20 +251,23 @@ static const struct sensor_driver_api adc_cmp_npcx_api = { .channel_get = adc_cmp_npcx_channel_get, }; -#define NPCX_ADC_CMP_INIT(inst) \ - static struct adc_cmp_npcx_data adc_cmp_npcx_data_##inst; \ - static const struct adc_cmp_npcx_config adc_cmp_npcx_config_##inst = {\ - .adc = DEVICE_DT_GET(DT_INST_IO_CHANNELS_CTLR(inst)), \ - .chnsel = DT_INST_IO_CHANNELS_INPUT(inst), \ - .th_sel = DT_INST_STRING_TOKEN_OR(inst, thr_sel, inst), \ - .thr_mv = DT_INST_PROP_OR(inst, threshold_mv, \ - ADC_CMP_NPCX_UNDEFINED), \ - .comparison = DT_INST_STRING_TOKEN_OR(inst, \ - comparison, ADC_CMP_NPCX_UNDEFINED) \ - }; \ - SENSOR_DEVICE_DT_INST_DEFINE(inst, adc_cmp_npcx_init, NULL, \ - &adc_cmp_npcx_data_##inst, \ - &adc_cmp_npcx_config_##inst, POST_KERNEL, \ - CONFIG_SENSOR_INIT_PRIORITY, \ - &adc_cmp_npcx_api); +#define NPCX_ADC_CMP_INIT(inst) \ + static struct adc_cmp_npcx_data adc_cmp_npcx_data_##inst; \ + static const struct adc_cmp_npcx_config adc_cmp_npcx_config_##inst = { \ + .adc = DEVICE_DT_GET(DT_INST_IO_CHANNELS_CTLR(inst)), \ + .chnsel = DT_INST_IO_CHANNELS_INPUT(inst), \ + .th_sel = DT_INST_STRING_TOKEN_OR(inst, thr_sel, inst), \ + .thr_mv = DT_INST_PROP_OR(inst, threshold_mv, \ + ADC_CMP_NPCX_UNDEFINED), \ + .comparison = DT_INST_STRING_TOKEN_OR(inst, \ + comparison, ADC_CMP_NPCX_UNDEFINED) \ + }; \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, adc_cmp_npcx_init, NULL, \ + &adc_cmp_npcx_data_##inst, \ + &adc_cmp_npcx_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, \ + &adc_cmp_npcx_api); \ + BUILD_ASSERT(DT_INST_STRING_TOKEN_OR(inst, thr_sel, inst) < \ + DT_PROP(DT_INST_IO_CHANNELS_CTLR(inst), threshold_count), \ + "Exceed the number of threshold detectors adc supports"); DT_INST_FOREACH_STATUS_OKAY(NPCX_ADC_CMP_INIT) diff --git a/drivers/sensor/qdec_nrfx/Kconfig b/drivers/sensor/qdec_nrfx/Kconfig index 64d91d6ba6f8cd4..71c3ab1d5b0d78c 100644 --- a/drivers/sensor/qdec_nrfx/Kconfig +++ b/drivers/sensor/qdec_nrfx/Kconfig @@ -7,6 +7,10 @@ config QDEC_NRFX depends on DT_HAS_NORDIC_NRF_QDEC_ENABLED select NRFX_QDEC0 if HAS_HW_NRF_QDEC0 select NRFX_QDEC1 if HAS_HW_NRF_QDEC1 + select NRFX_QDEC20 if HAS_HW_NRF_QDEC20 + select NRFX_QDEC21 if HAS_HW_NRF_QDEC21 + select NRFX_QDEC130 if HAS_HW_NRF_QDEC130 + select NRFX_QDEC131 if HAS_HW_NRF_QDEC131 select PINCTRL help Enable support for nrfx QDEC driver for nRF MCU series. diff --git a/drivers/sensor/qdec_nrfx/qdec_nrfx.c b/drivers/sensor/qdec_nrfx/qdec_nrfx.c index 81c3614fc050271..10035e0a1036595 100644 --- a/drivers/sensor/qdec_nrfx/qdec_nrfx.c +++ b/drivers/sensor/qdec_nrfx/qdec_nrfx.c @@ -135,13 +135,6 @@ static void qdec_nrfx_event_handler(nrfx_qdec_event_t event, void *p_context) unsigned int key; switch (event.type) { - case NRF_QDEC_EVENT_SAMPLERDY: - /* The underlying HAL driver may improperly forward an samplerdy event even if it's - * disabled in the configuration. Ignore the event to prevent error logs until the - * issue is fixed in HAL. - */ - break; - case NRF_QDEC_EVENT_REPORTRDY: accumulate(dev_data, event.data.report.acc); @@ -306,3 +299,19 @@ SENSOR_NRFX_QDEC_DEVICE(0); #ifdef CONFIG_HAS_HW_NRF_QDEC1 SENSOR_NRFX_QDEC_DEVICE(1); #endif + +#ifdef CONFIG_HAS_HW_NRF_QDEC20 +SENSOR_NRFX_QDEC_DEVICE(20); +#endif + +#ifdef CONFIG_HAS_HW_NRF_QDEC21 +SENSOR_NRFX_QDEC_DEVICE(21); +#endif + +#ifdef CONFIG_HAS_HW_NRF_QDEC130 +SENSOR_NRFX_QDEC_DEVICE(130); +#endif + +#ifdef CONFIG_HAS_HW_NRF_QDEC131 +SENSOR_NRFX_QDEC_DEVICE(131); +#endif diff --git a/drivers/sensor/qdec_nxp_s32/CMakeLists.txt b/drivers/sensor/qdec_nxp_s32/CMakeLists.txt new file mode 100644 index 000000000000000..a3065a37aba9457 --- /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 000000000000000..4250d9b26541ae4 --- /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 000000000000000..1b233d500e5487e --- /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_handlers.c b/drivers/sensor/sensor_handlers.c index cc1bc84f03bcd22..4643646c2155757 100644 --- a/drivers/sensor/sensor_handlers.c +++ b/drivers/sensor/sensor_handlers.c @@ -5,15 +5,15 @@ */ #include -#include +#include static inline int z_vrfy_sensor_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val) { - Z_OOPS(Z_SYSCALL_DRIVER_SENSOR(dev, attr_set)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(val, sizeof(struct sensor_value))); + K_OOPS(K_SYSCALL_DRIVER_SENSOR(dev, attr_set)); + K_OOPS(K_SYSCALL_MEMORY_READ(val, sizeof(struct sensor_value))); return z_impl_sensor_attr_set((const struct device *)dev, chan, attr, (const struct sensor_value *)val); } @@ -24,8 +24,8 @@ static inline int z_vrfy_sensor_attr_get(const struct device *dev, enum sensor_attribute attr, struct sensor_value *val) { - Z_OOPS(Z_SYSCALL_DRIVER_SENSOR(dev, attr_get)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(val, sizeof(struct sensor_value))); + K_OOPS(K_SYSCALL_DRIVER_SENSOR(dev, attr_get)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(val, sizeof(struct sensor_value))); return z_impl_sensor_attr_get((const struct device *)dev, chan, attr, (struct sensor_value *)val); } @@ -33,7 +33,7 @@ static inline int z_vrfy_sensor_attr_get(const struct device *dev, static inline int z_vrfy_sensor_sample_fetch(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_SENSOR(dev, sample_fetch)); + K_OOPS(K_SYSCALL_DRIVER_SENSOR(dev, sample_fetch)); return z_impl_sensor_sample_fetch((const struct device *)dev); } #include @@ -41,7 +41,7 @@ static inline int z_vrfy_sensor_sample_fetch(const struct device *dev) static inline int z_vrfy_sensor_sample_fetch_chan(const struct device *dev, enum sensor_channel type) { - Z_OOPS(Z_SYSCALL_DRIVER_SENSOR(dev, sample_fetch)); + K_OOPS(K_SYSCALL_DRIVER_SENSOR(dev, sample_fetch)); return z_impl_sensor_sample_fetch_chan((const struct device *)dev, type); } @@ -51,8 +51,8 @@ static inline int z_vrfy_sensor_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { - Z_OOPS(Z_SYSCALL_DRIVER_SENSOR(dev, channel_get)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(val, sizeof(struct sensor_value))); + K_OOPS(K_SYSCALL_DRIVER_SENSOR(dev, channel_get)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(val, sizeof(struct sensor_value))); return z_impl_sensor_channel_get((const struct device *)dev, chan, (struct sensor_value *)val); } @@ -62,8 +62,8 @@ static inline int z_vrfy_sensor_channel_get(const struct device *dev, static inline int z_vrfy_sensor_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SENSOR)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(decoder, sizeof(struct sensor_decoder_api))); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SENSOR)); + K_OOPS(K_SYSCALL_MEMORY_READ(decoder, sizeof(struct sensor_decoder_api))); return z_impl_sensor_get_decoder(dev, decoder); } #include @@ -73,9 +73,9 @@ static inline int z_vrfy_sensor_reconfigure_read_iodev(struct rtio_iodev *iodev, const enum sensor_channel *channels, size_t num_channels) { - Z_OOPS(Z_SYSCALL_OBJ(iodev, K_OBJ_RTIO_IODEV)); - Z_OOPS(Z_SYSCALL_OBJ(sensor, K_OBJ_DRIVER_SENSOR)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(channels, sizeof(enum sensor_channel) * num_channels)); + K_OOPS(K_SYSCALL_OBJ(iodev, K_OBJ_RTIO_IODEV)); + K_OOPS(K_SYSCALL_OBJ(sensor, K_OBJ_DRIVER_SENSOR)); + K_OOPS(K_SYSCALL_MEMORY_READ(channels, sizeof(enum sensor_channel) * num_channels)); return z_impl_sensor_reconfigure_read_iodev(iodev, sensor, channels, num_channels); } #include diff --git a/drivers/sensor/sensor_shell.c b/drivers/sensor/sensor_shell.c index a85eab23e43ec36..b0485b8378abc39 100644 --- a/drivers/sensor/sensor_shell.c +++ b/drivers/sensor/sensor_shell.c @@ -16,6 +16,8 @@ #include #include +#include "sensor_shell.h" + LOG_MODULE_REGISTER(sensor_shell); #define SENSOR_GET_HELP \ @@ -23,6 +25,11 @@ LOG_MODULE_REGISTER(sensor_shell); "when no channels are provided. Syntax:\n" \ " .. " +#define SENSOR_STREAM_HELP \ + "Start/stop streaming sensor data. Data ready trigger will be used if no triggers " \ + "are provided. Syntax:\n" \ + " on|off incl|drop|nop" + #define SENSOR_ATTR_GET_HELP \ "Get the sensor's channel attribute. Syntax:\n" \ " [ .. " \ @@ -38,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_ALL] = { +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", @@ -96,6 +103,7 @@ const char *sensor_channel_name[SENSOR_CHAN_ALL] = { [SENSOR_CHAN_GAUGE_DESIGN_VOLTAGE] = "gauge_design_voltage", [SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE] = "gauge_desired_voltage", [SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT] = "gauge_desired_charging_current", + [SENSOR_CHAN_ALL] = "all", }; static const char *sensor_attribute_name[SENSOR_ATTR_COMMON_COUNT] = { @@ -114,8 +122,36 @@ static const char *sensor_attribute_name[SENSOR_ATTR_COMMON_COUNT] = { [SENSOR_ATTR_FEATURE_MASK] = "feature_mask", [SENSOR_ATTR_ALERT] = "alert", [SENSOR_ATTR_FF_DUR] = "ff_dur", + [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); @@ -146,12 +182,32 @@ static const struct { TRIGGER_DATA_ENTRY(SENSOR_TRIG_FREEFALL, freefall, NULL), TRIGGER_DATA_ENTRY(SENSOR_TRIG_MOTION, motion, NULL), TRIGGER_DATA_ENTRY(SENSOR_TRIG_STATIONARY, stationary, NULL), + TRIGGER_DATA_ENTRY(SENSOR_TRIG_FIFO_WATERMARK, fifo_wm, NULL), + TRIGGER_DATA_ENTRY(SENSOR_TRIG_FIFO_FULL, fifo_full, NULL), }; +/** + * Lookup the sensor trigger data by name + * + * @param name The name of the trigger + * @return < 0 on error + * @return >= 0 if found + */ +static int sensor_trigger_name_lookup(const char *name) +{ + for (int i = 0; i < ARRAY_SIZE(sensor_trigger_table); ++i) { + if (strcmp(name, sensor_trigger_table[i].name) == 0) { + return i; + } + } + return -1; +} + enum dynamic_command_context { NONE, CTX_GET, CTX_ATTR_GET_SET, + CTX_STREAM_ON_OFF, }; static enum dynamic_command_context current_cmd_ctx = NONE; @@ -163,6 +219,7 @@ K_MUTEX_DEFINE(cmd_get_mutex); static enum sensor_channel iodev_sensor_shell_channels[SENSOR_CHAN_ALL]; static struct sensor_read_config iodev_sensor_shell_read_config = { .sensor = NULL, + .is_streaming = false, .channels = iodev_sensor_shell_channels, .count = 0, .max = ARRAY_SIZE(iodev_sensor_shell_channels), @@ -234,17 +291,18 @@ static int parse_sensor_value(const char *val_str, struct sensor_value *out) return 0; } -struct sensor_shell_processing_context { - const struct device *dev; - const struct shell *sh; -}; - -static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len, - void *userdata) +void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len, void *userdata) { struct sensor_shell_processing_context *ctx = userdata; const struct sensor_decoder_api *decoder; uint8_t decoded_buffer[128]; + struct { + uint64_t base_timestamp_ns; + int count; + uint64_t timestamp_delta; + int64_t values[3]; + int8_t shift; + } accumulator_buffer; int rc; ARG_UNUSED(buf_len); @@ -260,6 +318,17 @@ static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t return; } + for (int trigger = 0; decoder->has_trigger != NULL && trigger < SENSOR_TRIG_COMMON_COUNT; + ++trigger) { + if (!decoder->has_trigger(buf, trigger)) { + continue; + } + shell_info(ctx->sh, "Trigger (%d / %s) detected", trigger, + (sensor_trigger_table[trigger].name == NULL + ? "UNKNOWN" + : sensor_trigger_table[trigger].name)); + } + for (int channel = 0; channel < SENSOR_CHAN_ALL; ++channel) { uint32_t fit = 0; size_t base_size; @@ -292,6 +361,7 @@ static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t while (decoder->get_frame_count(buf, channel, channel_idx, &frame_count) == 0) { fit = 0; + memset(&accumulator_buffer, 0, sizeof(accumulator_buffer)); while (decoder->decode(buf, channel, channel_idx, &fit, 1, decoded_buffer) > 0) { @@ -303,41 +373,127 @@ static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t struct sensor_three_axis_data *data = (struct sensor_three_axis_data *)decoded_buffer; - shell_info(ctx->sh, - "channel idx=%d %s shift=%d " - "value=%" PRIsensor_three_axis_data, - channel, sensor_channel_name[channel], - data->shift, - PRIsensor_three_axis_data_arg(*data, 0)); + if (accumulator_buffer.count == 0) { + accumulator_buffer.base_timestamp_ns = + data->header.base_timestamp_ns; + } + accumulator_buffer.count++; + accumulator_buffer.shift = data->shift; + accumulator_buffer.timestamp_delta += + data->readings[0].timestamp_delta; + accumulator_buffer.values[0] += data->readings[0].values[0]; + accumulator_buffer.values[1] += data->readings[0].values[1]; + accumulator_buffer.values[2] += data->readings[0].values[2]; break; } case SENSOR_CHAN_PROX: { struct sensor_byte_data *data = (struct sensor_byte_data *)decoded_buffer; - shell_info(ctx->sh, - "channel idx=%d %s value=%" PRIsensor_byte_data( - is_near), - channel, sensor_channel_name[channel], - PRIsensor_byte_data_arg(*data, 0, is_near)); + if (accumulator_buffer.count == 0) { + accumulator_buffer.base_timestamp_ns = + data->header.base_timestamp_ns; + } + accumulator_buffer.count++; + accumulator_buffer.timestamp_delta += + data->readings[0].timestamp_delta; + accumulator_buffer.values[0] += data->readings[0].is_near; break; } default: { struct sensor_q31_data *data = (struct sensor_q31_data *)decoded_buffer; - shell_info(ctx->sh, - "channel idx=%d %s shift=%d " - "value=%" PRIsensor_q31_data, - channel, - (channel >= ARRAY_SIZE(sensor_channel_name)) - ? "" - : sensor_channel_name[channel], - data->shift, PRIsensor_q31_data_arg(*data, 0)); + if (accumulator_buffer.count == 0) { + accumulator_buffer.base_timestamp_ns = + data->header.base_timestamp_ns; + } + accumulator_buffer.count++; + accumulator_buffer.shift = data->shift; + accumulator_buffer.timestamp_delta += + data->readings[0].timestamp_delta; + accumulator_buffer.values[0] += data->readings[0].value; break; } } } + + /* Print the accumulated value average */ + switch (channel) { + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_MAGN_XYZ: + case SENSOR_CHAN_POS_DX: { + struct sensor_three_axis_data *data = + (struct sensor_three_axis_data *)decoded_buffer; + + data->header.base_timestamp_ns = + accumulator_buffer.base_timestamp_ns; + data->header.reading_count = 1; + data->shift = accumulator_buffer.shift; + data->readings[0].timestamp_delta = + (uint32_t)(accumulator_buffer.timestamp_delta / + accumulator_buffer.count); + data->readings[0].values[0] = (q31_t)(accumulator_buffer.values[0] / + accumulator_buffer.count); + data->readings[0].values[1] = (q31_t)(accumulator_buffer.values[1] / + accumulator_buffer.count); + data->readings[0].values[2] = (q31_t)(accumulator_buffer.values[2] / + accumulator_buffer.count); + shell_info(ctx->sh, + "channel idx=%d %s shift=%d num_samples=%d " + "value=%" PRIsensor_three_axis_data, + channel, sensor_channel_name[channel], + data->shift, accumulator_buffer.count, + PRIsensor_three_axis_data_arg(*data, 0)); + break; + } + case SENSOR_CHAN_PROX: { + struct sensor_byte_data *data = + (struct sensor_byte_data *)decoded_buffer; + + data->header.base_timestamp_ns = + accumulator_buffer.base_timestamp_ns; + data->header.reading_count = 1; + data->readings[0].timestamp_delta = + (uint32_t)(accumulator_buffer.timestamp_delta / + accumulator_buffer.count); + data->readings[0].is_near = + accumulator_buffer.values[0] / accumulator_buffer.count; + + shell_info(ctx->sh, + "channel idx=%d %s num_samples=%d " + "value=%" PRIsensor_byte_data(is_near), + channel, sensor_channel_name[channel], + accumulator_buffer.count, + PRIsensor_byte_data_arg(*data, 0, is_near)); + break; + } + default: { + struct sensor_q31_data *data = + (struct sensor_q31_data *)decoded_buffer; + + data->header.base_timestamp_ns = + accumulator_buffer.base_timestamp_ns; + data->header.reading_count = 1; + data->shift = accumulator_buffer.shift; + data->readings[0].timestamp_delta = + (uint32_t)(accumulator_buffer.timestamp_delta / + accumulator_buffer.count); + data->readings[0].value = (q31_t)(accumulator_buffer.values[0] / + accumulator_buffer.count); + + shell_info(ctx->sh, + "channel idx=%d %s shift=%d num_samples=%d " + "value=%" PRIsensor_q31_data, + channel, + (channel >= ARRAY_SIZE(sensor_channel_name)) + ? "" + : sensor_channel_name[channel], + data->shift, accumulator_buffer.count, + PRIsensor_q31_data_arg(*data, 0)); + } + } ++channel_idx; } } @@ -345,6 +501,7 @@ static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[]) { + static struct sensor_shell_processing_context ctx; const struct device *dev; int count = 0; int err; @@ -392,21 +549,27 @@ static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[]) iodev_sensor_shell_read_config.sensor = dev; iodev_sensor_shell_read_config.count = count; - struct sensor_shell_processing_context ctx = { - .dev = dev, - .sh = sh, - }; + ctx.dev = dev; + ctx.sh = sh; err = sensor_read(&iodev_sensor_shell_read, &sensor_read_rtio, &ctx); if (err < 0) { shell_error(sh, "Failed to read sensor: %d", err); } - sensor_processing_with_callback(&sensor_read_rtio, sensor_shell_processing_callback); + if (!IS_ENABLED(CONFIG_SENSOR_SHELL_STREAM)) { + /* + * Streaming enables a thread that polls the RTIO context, so if it's enabled, we + * don't need a blocking read here. + */ + sensor_processing_with_callback(&sensor_read_rtio, + sensor_shell_processing_callback); + } k_mutex_unlock(&cmd_get_mutex); return 0; } + static int cmd_sensor_attr_set(const struct shell *shell_ptr, size_t argc, char *argv[]) { const struct device *dev; @@ -517,9 +680,37 @@ static int cmd_sensor_attr_get(const struct shell *shell_ptr, size_t argc, char } static void channel_name_get(size_t idx, struct shell_static_entry *entry); - SHELL_DYNAMIC_CMD_CREATE(dsub_channel_name, channel_name_get); +static void attribute_name_get(size_t idx, struct shell_static_entry *entry); +SHELL_DYNAMIC_CMD_CREATE(dsub_attribute_name, attribute_name_get); + +static void channel_name_get(size_t idx, struct shell_static_entry *entry) +{ + int cnt = 0; + + entry->syntax = NULL; + entry->handler = NULL; + entry->help = NULL; + if (current_cmd_ctx == CTX_GET) { + entry->subcmd = &dsub_channel_name; + } else if (current_cmd_ctx == CTX_ATTR_GET_SET) { + entry->subcmd = &dsub_attribute_name; + } else { + entry->subcmd = NULL; + } + + for (int i = 0; i < ARRAY_SIZE(sensor_channel_name); i++) { + if (sensor_channel_name[i] != NULL) { + if (cnt == idx) { + entry->syntax = sensor_channel_name[i]; + break; + } + cnt++; + } + } +} + static void attribute_name_get(size_t idx, struct shell_static_entry *entry) { int cnt = 0; @@ -529,7 +720,7 @@ static void attribute_name_get(size_t idx, struct shell_static_entry *entry) entry->help = NULL; entry->subcmd = &dsub_channel_name; - for (int i = 0; i < SENSOR_ATTR_COMMON_COUNT; i++) { + for (int i = 0; i < ARRAY_SIZE(sensor_attribute_name); i++) { if (sensor_attribute_name[i] != NULL) { if (cnt == idx) { entry->syntax = sensor_attribute_name[i]; @@ -539,27 +730,46 @@ static void attribute_name_get(size_t idx, struct shell_static_entry *entry) } } } -SHELL_DYNAMIC_CMD_CREATE(dsub_attribute_name, attribute_name_get); -static void channel_name_get(size_t idx, struct shell_static_entry *entry) +static void trigger_opt_get_for_stream(size_t idx, struct shell_static_entry *entry); +SHELL_DYNAMIC_CMD_CREATE(dsub_trigger_opt_get_for_stream, trigger_opt_get_for_stream); + +static void trigger_opt_get_for_stream(size_t idx, struct shell_static_entry *entry) +{ + entry->syntax = NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; + + switch (idx) { + case SENSOR_STREAM_DATA_INCLUDE: + entry->syntax = "incl"; + break; + case SENSOR_STREAM_DATA_DROP: + entry->syntax = "drop"; + break; + case SENSOR_STREAM_DATA_NOP: + entry->syntax = "nop"; + break; + } +} + +static void trigger_name_get_for_stream(size_t idx, struct shell_static_entry *entry); +SHELL_DYNAMIC_CMD_CREATE(dsub_trigger_name_for_stream, trigger_name_get_for_stream); + +static void trigger_name_get_for_stream(size_t idx, struct shell_static_entry *entry) { int cnt = 0; entry->syntax = NULL; entry->handler = NULL; entry->help = NULL; - if (current_cmd_ctx == CTX_GET) { - entry->subcmd = &dsub_channel_name; - } else if (current_cmd_ctx == CTX_ATTR_GET_SET) { - entry->subcmd = &dsub_attribute_name; - } else { - entry->subcmd = NULL; - } + entry->subcmd = &dsub_trigger_opt_get_for_stream; - for (int i = 0; i < SENSOR_CHAN_ALL; i++) { - if (sensor_channel_name[i] != NULL) { + for (int i = 0; i < ARRAY_SIZE(sensor_trigger_table); i++) { + if (sensor_trigger_table[i].name != NULL) { if (cnt == idx) { - entry->syntax = sensor_channel_name[i]; + entry->syntax = sensor_trigger_table[i].name; break; } cnt++; @@ -567,6 +777,22 @@ static void channel_name_get(size_t idx, struct shell_static_entry *entry) } } +static void stream_on_off(size_t idx, struct shell_static_entry *entry) +{ + entry->syntax = NULL; + entry->handler = NULL; + entry->help = NULL; + + if (idx == 0) { + entry->syntax = "on"; + entry->subcmd = &dsub_trigger_name_for_stream; + } else if (idx == 1) { + entry->syntax = "off"; + entry->subcmd = NULL; + } +} +SHELL_DYNAMIC_CMD_CREATE(dsub_stream_on_off, stream_on_off); + static void device_name_get(size_t idx, struct shell_static_entry *entry); SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get); @@ -603,7 +829,7 @@ static void trigger_name_get(size_t idx, struct shell_static_entry *entry) entry->help = NULL; entry->subcmd = NULL; - for (int i = 0; i < SENSOR_TRIG_COMMON_COUNT; i++) { + for (int i = 0; i < ARRAY_SIZE(sensor_trigger_table); i++) { if (sensor_trigger_table[i].name != NULL) { if (cnt == idx) { entry->syntax = sensor_trigger_table[i].name; @@ -649,6 +875,18 @@ static void device_name_get_for_trigger(size_t idx, struct shell_static_entry *e SHELL_DYNAMIC_CMD_CREATE(dsub_trigger, device_name_get_for_trigger); +static void device_name_get_for_stream(size_t idx, struct shell_static_entry *entry) +{ + const struct device *dev = shell_device_lookup(idx, NULL); + + current_cmd_ctx = CTX_STREAM_ON_OFF; + entry->syntax = (dev != NULL) ? dev->name : NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = &dsub_stream_on_off; +} +SHELL_DYNAMIC_CMD_CREATE(dsub_device_name_for_stream, device_name_get_for_stream); + static int cmd_get_sensor_info(const struct shell *sh, size_t argc, char **argv) { ARG_UNUSED(argc); @@ -671,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"); @@ -708,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. */ @@ -726,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; @@ -738,7 +988,7 @@ static void data_ready_trigger_handler(const struct device *sensor, static int cmd_trig_sensor(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; - enum sensor_trigger_type trigger; + int trigger; int err; if (argc < 4) { @@ -754,23 +1004,45 @@ static int cmd_trig_sensor(const struct shell *sh, size_t argc, char **argv) } /* Map the trigger string to an enum value */ - for (trigger = 0; trigger < ARRAY_SIZE(sensor_trigger_table); trigger++) { - if (strcmp(argv[3], sensor_trigger_table[trigger].name) == 0) { - break; - } - } - if (trigger >= SENSOR_TRIG_COMMON_COUNT || sensor_trigger_table[trigger].handler == NULL) { + trigger = sensor_trigger_name_lookup(argv[3]); + if (trigger < 0 || sensor_trigger_table[trigger].handler == NULL) { shell_error(sh, "Unsupported trigger type (%s)", argv[3]); return -ENOTSUP; } /* 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; @@ -792,6 +1064,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_sensor, cmd_sensor_attr_set, 2, 255), SHELL_CMD_ARG(attr_get, &dsub_device_name_for_attr, SENSOR_ATTR_GET_HELP, cmd_sensor_attr_get, 2, 255), + SHELL_COND_CMD(CONFIG_SENSOR_SHELL_STREAM, stream, &dsub_device_name_for_stream, + SENSOR_STREAM_HELP, cmd_sensor_stream), SHELL_COND_CMD(CONFIG_SENSOR_INFO, info, NULL, SENSOR_INFO_HELP, cmd_get_sensor_info), SHELL_CMD_ARG(trig, &dsub_trigger, SENSOR_TRIG_HELP, cmd_trig_sensor, diff --git a/drivers/sensor/sensor_shell.h b/drivers/sensor/sensor_shell.h new file mode 100644 index 000000000000000..cfc8b2489db3cfc --- /dev/null +++ b/drivers/sensor/sensor_shell.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_SENSOR_SHELL_H +#define ZEPHYR_DRIVERS_SENSOR_SENSOR_SHELL_H + +#include +#include +#include +#include + +struct sensor_shell_processing_context { + const struct device *dev; + const struct shell *sh; +}; + +extern struct rtio sensor_read_rtio; + +int cmd_sensor_stream(const struct shell *shell_ptr, size_t argc, char *argv[]); + +void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len, void *userdata); + +#endif /* ZEPHYR_DRIVERS_SENSOR_SENSOR_SHELL_H */ diff --git a/drivers/sensor/sensor_shell_stream.c b/drivers/sensor/sensor_shell_stream.c new file mode 100644 index 000000000000000..ab3b835aa103865 --- /dev/null +++ b/drivers/sensor/sensor_shell_stream.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +#include "sensor_shell.h" + +/* Create a single common config for streaming */ +static struct sensor_stream_trigger iodev_sensor_shell_trigger; +static struct sensor_read_config iodev_sensor_shell_stream_config = { + .sensor = NULL, + .is_streaming = true, + .triggers = &iodev_sensor_shell_trigger, + .count = 0, + .max = 1, +}; +RTIO_IODEV_DEFINE(iodev_sensor_shell_stream, &__sensor_iodev_api, + &iodev_sensor_shell_stream_config); + +static void sensor_shell_processing_entry_point(void *a, void *b, void *c) +{ + ARG_UNUSED(a); + ARG_UNUSED(b); + ARG_UNUSED(c); + + while (true) { + sensor_processing_with_callback(&sensor_read_rtio, + sensor_shell_processing_callback); + } +} +K_THREAD_DEFINE(sensor_shell_processing_tid, CONFIG_SENSOR_SHELL_THREAD_STACK_SIZE, + sensor_shell_processing_entry_point, NULL, NULL, NULL, 0, 0, 0); + +int cmd_sensor_stream(const struct shell *shell_ptr, size_t argc, char *argv[]) +{ + static struct rtio_sqe *current_streaming_handle; + static struct sensor_shell_processing_context ctx; + const struct device *dev = device_get_binding(argv[1]); + + if (argc != 5 && argc != 3) { + shell_error(shell_ptr, "Wrong number of arguments (%zu)", argc); + return -EINVAL; + } + + if (dev == NULL) { + shell_error(shell_ptr, "Device unknown (%s)", argv[1]); + return -ENODEV; + } + + if (current_streaming_handle != NULL) { + shell_info(shell_ptr, "Disabling existing stream"); + rtio_sqe_cancel(current_streaming_handle); + } + + if (strcmp("off", argv[2]) == 0) { + return 0; + } + + if (strcmp("on", argv[2]) != 0) { + shell_error(shell_ptr, "Unknown streaming operation (%s)", argv[2]); + return -EINVAL; + } + + if (strcmp("double_tap", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_DOUBLE_TAP; + } else if (strcmp("data_ready", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_DATA_READY; + } else if (strcmp("delta", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_DELTA; + } else if (strcmp("freefall", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_FREEFALL; + } else if (strcmp("motion", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_MOTION; + } else if (strcmp("near_far", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_NEAR_FAR; + } else if (strcmp("stationary", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_STATIONARY; + } else if (strcmp("threshold", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_THRESHOLD; + } else if (strcmp("fifo_wm", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_FIFO_WATERMARK; + } else if (strcmp("fifo_full", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_FIFO_FULL; + } else if (strcmp("tap", argv[3]) == 0) { + iodev_sensor_shell_trigger.trigger = SENSOR_TRIG_TAP; + } else { + shell_error(shell_ptr, "Invalid trigger (%s)", argv[3]); + return -EINVAL; + } + + if (strcmp("incl", argv[4]) == 0) { + iodev_sensor_shell_trigger.opt = SENSOR_STREAM_DATA_INCLUDE; + } else if (strcmp("drop", argv[4]) == 0) { + iodev_sensor_shell_trigger.opt = SENSOR_STREAM_DATA_DROP; + } else if (strcmp("nop", argv[4]) == 0) { + iodev_sensor_shell_trigger.opt = SENSOR_STREAM_DATA_NOP; + } else { + shell_error(shell_ptr, "Unknown trigger op (%s)", argv[4]); + return -EINVAL; + } + + shell_print(shell_ptr, "Enabling stream..."); + iodev_sensor_shell_stream_config.sensor = dev; + + iodev_sensor_shell_stream_config.count = 1; + + ctx.dev = dev; + ctx.sh = shell_ptr; + + int rc = sensor_stream(&iodev_sensor_shell_stream, &sensor_read_rtio, &ctx, + ¤t_streaming_handle); + + if (rc != 0) { + shell_error(shell_ptr, "Failed to start stream"); + } + return rc; +} diff --git a/drivers/sensor/sht3xd/sht3xd_trigger.c b/drivers/sensor/sht3xd/sht3xd_trigger.c index 03b2bffaea406bb..b6b398c5166b363 100644 --- a/drivers/sensor/sht3xd/sht3xd_trigger.c +++ b/drivers/sensor/sht3xd/sht3xd_trigger.c @@ -162,8 +162,13 @@ static void sht3xd_thread_cb(const struct device *dev) } #ifdef CONFIG_SHT3XD_TRIGGER_OWN_THREAD -static void sht3xd_thread(struct sht3xd_data *data) +static void sht3xd_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct sht3xd_data *data = p1; + while (1) { k_sem_take(&data->gpio_sem, K_FOREVER); sht3xd_thread_cb(data->dev); @@ -238,7 +243,7 @@ int sht3xd_init_interrupt(const struct device *dev) k_thread_create(&data->thread, data->thread_stack, CONFIG_SHT3XD_THREAD_STACK_SIZE, - (k_thread_entry_t)sht3xd_thread, data, + sht3xd_thread, data, NULL, NULL, K_PRIO_COOP(CONFIG_SHT3XD_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_SHT3XD_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/sm351lt/sm351lt.c b/drivers/sensor/sm351lt/sm351lt.c index 0663079ca894275..7ec832531522705 100644 --- a/drivers/sensor/sm351lt/sm351lt.c +++ b/drivers/sensor/sm351lt/sm351lt.c @@ -212,7 +212,7 @@ static int sm351lt_init(const struct device *dev) k_thread_create(&data->thread, data->thread_stack, CONFIG_SM351LT_THREAD_STACK_SIZE, - (k_thread_entry_t)sm351lt_thread, data, NULL, + sm351lt_thread, data, NULL, NULL, K_PRIO_COOP(CONFIG_SM351LT_THREAD_PRIORITY), 0, K_NO_WAIT); diff --git a/drivers/sensor/stm32_temp/stm32_temp.c b/drivers/sensor/stm32_temp/stm32_temp.c index 7ad72490e913426..5e594b0fe0ce2aa 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 10c035baacf9335..8379670fab380bd 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 4dcb8324076c17e..3532d2aeddd769b 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/stts751/Kconfig b/drivers/sensor/stts751/Kconfig index d048e117e109e12..d4bb8eeb7001c5e 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/stts751/stts751_trigger.c b/drivers/sensor/stts751/stts751_trigger.c index ec463370c561515..5d827d4f1b142a5 100644 --- a/drivers/sensor/stts751/stts751_trigger.c +++ b/drivers/sensor/stts751/stts751_trigger.c @@ -96,8 +96,13 @@ static void stts751_gpio_callback(const struct device *dev, } #ifdef CONFIG_STTS751_TRIGGER_OWN_THREAD -static void stts751_thread(struct stts751_data *stts751) +static void stts751_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct stts751_data *stts751 = p1; + while (1) { k_sem_take(&stts751->gpio_sem, K_FOREVER); stts751_handle_interrupt(stts751->dev); @@ -131,7 +136,7 @@ int stts751_init_interrupt(const struct device *dev) k_thread_create(&stts751->thread, stts751->thread_stack, CONFIG_STTS751_THREAD_STACK_SIZE, - (k_thread_entry_t)stts751_thread, stts751, + stts751_thread, stts751, NULL, NULL, K_PRIO_COOP(CONFIG_STTS751_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_STTS751_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/sx9500/sx9500_trigger.c b/drivers/sensor/sx9500/sx9500_trigger.c index 127291b2a9195f9..146e6753ef94a7f 100644 --- a/drivers/sensor/sx9500/sx9500_trigger.c +++ b/drivers/sensor/sx9500/sx9500_trigger.c @@ -98,8 +98,13 @@ static void sx9500_gpio_cb(const struct device *port, k_sem_give(&data->sem); } -static void sx9500_thread_main(struct sx9500_data *data) +static void sx9500_thread_main(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct sx9500_data *data = p1; + while (1) { k_sem_take(&data->sem, K_FOREVER); sx9500_gpio_thread_cb(data->dev); @@ -170,7 +175,7 @@ int sx9500_setup_interrupt(const struct device *dev) #ifdef CONFIG_SX9500_TRIGGER_OWN_THREAD k_thread_create(&sx9500_thread, sx9500_thread_stack, CONFIG_SX9500_THREAD_STACK_SIZE, - (k_thread_entry_t)sx9500_thread_main, data, 0, NULL, + sx9500_thread_main, data, 0, NULL, K_PRIO_COOP(CONFIG_SX9500_THREAD_PRIORITY), 0, K_NO_WAIT); #endif diff --git a/drivers/sensor/tcn75a/tcn75a_trigger.c b/drivers/sensor/tcn75a/tcn75a_trigger.c index 90f6932a9e046d9..12635eb00c22f65 100644 --- a/drivers/sensor/tcn75a/tcn75a_trigger.c +++ b/drivers/sensor/tcn75a/tcn75a_trigger.c @@ -149,8 +149,13 @@ static void tcn75a_gpio_callback(const struct device *dev, struct gpio_callback } #ifdef CONFIG_TCN75A_TRIGGER_OWN_THREAD -static void tcn75a_thread_main(struct tcn75a_data *data) +static void tcn75a_thread_main(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct tcn75a_data *data = p1; + while (true) { k_sem_take(&data->trig_sem, K_FOREVER); tcn75a_handle_int(data->dev); @@ -193,7 +198,7 @@ int tcn75a_trigger_init(const struct device *dev) #if defined(CONFIG_TCN75A_TRIGGER_OWN_THREAD) k_sem_init(&data->trig_sem, 0, K_SEM_MAX_LIMIT); k_thread_create(&data->thread, data->thread_stack, CONFIG_TCN75A_THREAD_STACK_SIZE, - (k_thread_entry_t)tcn75a_thread_main, data, NULL, NULL, + tcn75a_thread_main, data, NULL, NULL, K_PRIO_COOP(CONFIG_TCN75A_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_TCN75A_TRIGGER_GLOBAL_THREAD) data->work.handler = tcn75a_work_handler; diff --git a/drivers/sensor/tmp007/tmp007_trigger.c b/drivers/sensor/tmp007/tmp007_trigger.c index d123a68aabc70d2..a3eb0b073033761 100644 --- a/drivers/sensor/tmp007/tmp007_trigger.c +++ b/drivers/sensor/tmp007/tmp007_trigger.c @@ -105,8 +105,13 @@ static void tmp007_thread_cb(const struct device *dev) } #ifdef CONFIG_TMP007_TRIGGER_OWN_THREAD -static void tmp007_thread(struct tmp007_data *drv_data) +static void tmp007_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct tmp007_data *drv_data = p1; + while (1) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); tmp007_thread_cb(drv_data->dev); @@ -185,7 +190,7 @@ int tmp007_init_interrupt(const struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_TMP007_THREAD_STACK_SIZE, - (k_thread_entry_t)tmp007_thread, drv_data, + tmp007_thread, drv_data, NULL, NULL, K_PRIO_COOP(CONFIG_TMP007_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_TMP007_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/tsl2540/tsl2540.c b/drivers/sensor/tsl2540/tsl2540.c index fb3060d136ed437..98516d5f29644f7 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/tsl2540/tsl2540_trigger.c b/drivers/sensor/tsl2540/tsl2540_trigger.c index c383186e77c196b..3251c3a45c93af2 100644 --- a/drivers/sensor/tsl2540/tsl2540_trigger.c +++ b/drivers/sensor/tsl2540/tsl2540_trigger.c @@ -81,8 +81,13 @@ static void tsl2540_process_int(const struct device *dev) } #ifdef CONFIG_TSL2540_TRIGGER_OWN_THREAD -static void tsl2540_thread_main(struct tsl2540_data *data) +static void tsl2540_thread_main(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct tsl2540_data *data = p1; + while (true) { k_sem_take(&data->trig_sem, K_FOREVER); tsl2540_process_int(data->dev); @@ -189,7 +194,7 @@ int tsl2540_trigger_init(const struct device *dev) #if defined(CONFIG_TSL2540_TRIGGER_OWN_THREAD) k_sem_init(&data->trig_sem, 0, K_SEM_MAX_LIMIT); k_thread_create(&data->thread, data->thread_stack, CONFIG_TSL2540_THREAD_STACK_SIZE, - (k_thread_entry_t)tsl2540_thread_main, data, NULL, NULL, + tsl2540_thread_main, data, NULL, NULL, K_PRIO_COOP(CONFIG_TSL2540_THREAD_PRIORITY), 0, K_NO_WAIT); k_thread_name_set(&data->thread, "TSL2540 trigger"); #elif defined(CONFIG_TSL2540_TRIGGER_GLOBAL_THREAD) diff --git a/drivers/sensor/tsl2561/CMakeLists.txt b/drivers/sensor/tsl2561/CMakeLists.txt new file mode 100644 index 000000000000000..7c2d251b1507dec --- /dev/null +++ b/drivers/sensor/tsl2561/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(tsl2561.c) diff --git a/drivers/sensor/tsl2561/Kconfig b/drivers/sensor/tsl2561/Kconfig new file mode 100644 index 000000000000000..e5b975bad3477d0 --- /dev/null +++ b/drivers/sensor/tsl2561/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Gustavo Silva +# SPDX-License-Identifier: Apache-2.0 + +config TSL2561 + bool "OSRAM-AMS TSL2561 light sensor" + default y + depends on DT_HAS_AMS_TSL2561_ENABLED + select I2C + help + Enable driver for TSL2561 sensor. diff --git a/drivers/sensor/tsl2561/tsl2561.c b/drivers/sensor/tsl2561/tsl2561.c new file mode 100644 index 000000000000000..0e5c0209b6b194f --- /dev/null +++ b/drivers/sensor/tsl2561/tsl2561.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2023, Gustavo Silva + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ams_tsl2561 + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(TSL2561, CONFIG_SENSOR_LOG_LEVEL); + +#define TSL2561_CHIP_ID 0x05 + +#define TSL2561_GAIN_1X 0x00 +#define TSL2561_GAIN_16X 0x01 + +#define TSL2561_INTEGRATION_13MS 0x00 +#define TSL2561_INTEGRATION_101MS 0x01 +#define TSL2561_INTEGRATION_402MS 0x02 + +/* Register set */ +#define TSL2561_REG_CONTROL 0x00 +#define TSL2561_REG_TIMING 0x01 +#define TSL2561_REG_THRESHLOWLOW 0x02 +#define TSL2561_REG_THRESHLOWHIGH 0x03 +#define TSL2561_REG_THRESHHIGHLOW 0x04 +#define TSL2561_REG_THRESHHIGHHIGH 0x05 +#define TSL2561_REG_INTERRUPT 0x06 +#define TSL2561_REG_ID 0x0A +#define TSL2561_REG_DATA0LOW 0x0C +#define TSL2561_REG_DATA0HIGH 0x0D +#define TSL2561_REG_DATA1LOW 0x0E +#define TSL2561_REG_DATA1HIGH 0x0F + +/* Command register fields */ +#define TSL2561_COMMAND_CMD BIT(7) +#define TSL2561_COMMAND_WORD BIT(5) + +/* Control register fields */ +#define TSL2561_CONTROL_POWER_UP 0x03 +#define TSL2561_CONTROL_POWER_DOWN 0x00 + +/* Timing register fields */ +#define TSL2561_TIMING_GAIN BIT(4) +#define TSL2561_TIMING_INTEG GENMASK(1, 0) + +/* ID register part number mask */ +#define TSL2561_ID_PARTNO GENMASK(7, 4) + +/* Lux calculation constants */ +#define TSL2561_LUX_SCALE 14U +#define TSL2561_RATIO_SCALE 9U +#define TSL2561_CH_SCALE 10U +#define TSL2561_CHSCALE_TINT0 0x7517 +#define TSL2561_CHSCALE_TINT1 0x0FE7 + +#define TSL2561_LUX_K1T 0X0040 /* 0.125 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B1T 0X01F2 /* 0.0304 * 2^LUX_SCALE */ +#define TSL2561_LUX_M1T 0X01BE /* 0.0272 * 2^LUX_SCALE */ +#define TSL2561_LUX_K2T 0X0080 /* 0.250 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B2T 0X0214 /* 0.0325 * 2^LUX_SCALE */ +#define TSL2561_LUX_M2T 0X02D1 /* 0.0440 * 2^LUX_SCALE */ +#define TSL2561_LUX_K3T 0X00C0 /* 0.375 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B3T 0X023F /* 0.0351 * 2^LUX_SCALE */ +#define TSL2561_LUX_M3T 0X037B /* 0.0544 * 2^LUX_SCALE */ +#define TSL2561_LUX_K4T 0X0100 /* 0.50 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B4T 0X0270 /* 0.0381 * 2^LUX_SCALE */ +#define TSL2561_LUX_M4T 0X03FE /* 0.0624 * 2^LUX_SCALE */ +#define TSL2561_LUX_K5T 0X0138 /* 0.61 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B5T 0X016F /* 0.0224 * 2^LUX_SCALE */ +#define TSL2561_LUX_M5T 0X01FC /* 0.0310 * 2^LUX_SCALE */ +#define TSL2561_LUX_K6T 0X019A /* 0.80 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B6T 0X00D2 /* 0.0128 * 2^LUX_SCALE */ +#define TSL2561_LUX_M6T 0X00FB /* 0.0153 * 2^LUX_SCALE */ +#define TSL2561_LUX_K7T 0X029A /* 1.3 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B7T 0X0018 /* 0.00146 * 2^LUX_SCALE */ +#define TSL2561_LUX_M7T 0X0012 /* 0.00112 * 2^LUX_SCALE */ +#define TSL2561_LUX_K8T 0X029A /* 1.3 * 2^RATIO_SCALE */ +#define TSL2561_LUX_B8T 0X0000 /* 0.000 * 2^LUX_SCALE */ +#define TSL2561_LUX_M8T 0X0000 /* 0.000 * 2^LUX_SCALE */ + +struct tsl2561_config { + struct i2c_dt_spec i2c; + uint16_t integration_time; + uint8_t gain; +}; + +struct tsl2561_data { + uint16_t ch0; + uint16_t ch1; + uint32_t ch_scale; +}; + +static int tsl2561_reg_read(const struct device *dev, uint8_t reg, uint8_t *buf, uint8_t size) +{ + int ret; + const struct tsl2561_config *config = dev->config; + uint8_t cmd = (TSL2561_COMMAND_CMD | TSL2561_COMMAND_WORD | reg); + + ret = i2c_write_read_dt(&config->i2c, &cmd, 1U, buf, size); + if (ret < 0) { + LOG_ERR("Failed reading register 0x%02x", reg); + return ret; + } + + return 0; +} + +static int tsl2561_reg_write(const struct device *dev, uint8_t reg, uint8_t val) +{ + int ret; + const struct tsl2561_config *config = dev->config; + uint8_t buf[2]; + + buf[0] = (TSL2561_COMMAND_CMD | TSL2561_COMMAND_WORD | reg); + buf[1] = val; + + ret = i2c_write_dt(&config->i2c, buf, 2U); + if (ret < 0) { + LOG_ERR("Failed writing register 0x%02x", reg); + return ret; + } + + return 0; +} + +static int tsl2561_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + const struct tsl2561_config *config = dev->config; + struct tsl2561_data *data = dev->data; + uint8_t bytes[2]; + int ret; + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_LIGHT) { + LOG_ERR("Unsupported sensor channel"); + return -ENOTSUP; + } + + ret = tsl2561_reg_write(dev, TSL2561_REG_CONTROL, TSL2561_CONTROL_POWER_UP); + if (ret < 0) { + LOG_ERR("Failed to power up device"); + return ret; + } + + /* Short sleep after power up. Not in the datasheet, but found by trial and error */ + k_msleep(5); + + k_msleep(config->integration_time); + + /* Read data register's lower and upper bytes consecutively */ + ret = tsl2561_reg_read(dev, TSL2561_REG_DATA0LOW, bytes, 2U); + if (ret < 0) { + LOG_ERR("Failed reading channel0 data"); + return ret; + } + data->ch0 = bytes[1] << 8 | bytes[0]; + + ret = tsl2561_reg_read(dev, TSL2561_REG_DATA1LOW, bytes, 2U); + if (ret < 0) { + LOG_ERR("Failed reading channel1 data"); + return ret; + } + data->ch1 = bytes[1] << 8 | bytes[0]; + + ret = tsl2561_reg_write(dev, TSL2561_REG_CONTROL, TSL2561_CONTROL_POWER_DOWN); + if (ret < 0) { + LOG_ERR("Failed to power down device"); + return ret; + } + + LOG_DBG("channel0: 0x%x; channel1: 0x%x", data->ch0, data->ch1); + + return 0; +} + +static int tsl2561_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct tsl2561_data *data = dev->data; + uint32_t channel0; + uint32_t channel1; + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_LIGHT) { + return -ENOTSUP; + } + + channel0 = (data->ch0 * data->ch_scale) >> TSL2561_CH_SCALE; + channel1 = (data->ch1 * data->ch_scale) >> TSL2561_CH_SCALE; + + uint32_t ratio1 = 0; + + if (channel0 != 0) { + ratio1 = (channel1 << (TSL2561_RATIO_SCALE + 1)) / channel0; + } + + /* Round the ratio value */ + uint32_t ratio = (ratio1 + 1) >> 1; + + uint32_t b = 0; + uint32_t m = 0; + + if (ratio <= TSL2561_LUX_K1T) { + b = TSL2561_LUX_B1T; + m = TSL2561_LUX_M1T; + } else if (ratio <= TSL2561_LUX_K2T) { + b = TSL2561_LUX_B2T; + m = TSL2561_LUX_M2T; + } else if (ratio <= TSL2561_LUX_K3T) { + b = TSL2561_LUX_B3T; + m = TSL2561_LUX_M3T; + } else if (ratio <= TSL2561_LUX_K4T) { + b = TSL2561_LUX_B4T; + m = TSL2561_LUX_M4T; + } else if (ratio <= TSL2561_LUX_K5T) { + b = TSL2561_LUX_B5T; + m = TSL2561_LUX_M5T; + } else if (ratio <= TSL2561_LUX_K6T) { + b = TSL2561_LUX_B6T; + m = TSL2561_LUX_M6T; + } else if (ratio <= TSL2561_LUX_K7T) { + b = TSL2561_LUX_B7T; + m = TSL2561_LUX_M7T; + } else if (ratio > TSL2561_LUX_K8T) { + b = TSL2561_LUX_B8T; + m = TSL2561_LUX_M8T; + } + + int32_t tmp = ((channel0 * b) - (channel1 * m)); + + /* Round LSB (2^(LUX_SCALE−1)) */ + tmp += (1 << (TSL2561_LUX_SCALE - 1)); + + /* Strip off fractional portion */ + val->val1 = tmp >> TSL2561_LUX_SCALE; + + val->val2 = 0; + + return 0; +} + +static const struct sensor_driver_api tsl2561_driver_api = { + .sample_fetch = tsl2561_sample_fetch, + .channel_get = tsl2561_channel_get +}; + +static int tsl2561_sensor_setup(const struct device *dev) +{ + const struct tsl2561_config *config = dev->config; + struct tsl2561_data *data = dev->data; + uint8_t timing_reg; + uint8_t chip_id; + uint8_t tmp; + int ret; + + ret = tsl2561_reg_read(dev, TSL2561_REG_ID, &chip_id, 1U); + if (ret < 0) { + LOG_ERR("Failed reading chip ID"); + return ret; + } + + if (FIELD_GET(TSL2561_ID_PARTNO, chip_id) != TSL2561_CHIP_ID) { + LOG_ERR("Chip ID is invalid! Device @%02x is not TSL2561!", config->i2c.addr); + return -EIO; + } + + switch (config->integration_time) { + case 13: + tmp = TSL2561_INTEGRATION_13MS; + data->ch_scale = TSL2561_CHSCALE_TINT0; + break; + case 101: + tmp = TSL2561_INTEGRATION_101MS; + data->ch_scale = TSL2561_CHSCALE_TINT1; + break; + case 402: + tmp = TSL2561_INTEGRATION_402MS; + data->ch_scale = (1 << TSL2561_CH_SCALE); + break; + default: + LOG_ERR("Invalid integration time"); + return -EINVAL; + } + + timing_reg = TSL2561_TIMING_INTEG & tmp; + + switch (config->gain) { + case 1: + tmp = TSL2561_GAIN_1X; + data->ch_scale = data->ch_scale << 4; + break; + case 16: + tmp = TSL2561_GAIN_16X; + break; + default: + LOG_ERR("Invalid ADC gain"); + return -EINVAL; + } + + timing_reg |= FIELD_PREP(TSL2561_TIMING_GAIN, tmp); + + ret = tsl2561_reg_write(dev, TSL2561_REG_TIMING, timing_reg); + if (ret < 0) { + LOG_ERR("Failed setting timing register"); + return ret; + } + + return 0; +} + +static int tsl2561_init(const struct device *dev) +{ + const struct tsl2561_config *config = dev->config; + int ret; + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("I2C dev %s not ready", config->i2c.bus->name); + return -ENODEV; + } + + ret = tsl2561_sensor_setup(dev); + if (ret < 0) { + LOG_ERR("Failed to configure device"); + return ret; + } + + return 0; +} + +#define TSL2561_INIT_INST(n) \ + static struct tsl2561_data tsl2561_data_##n; \ + static const struct tsl2561_config tsl2561_config_##n = { \ + .i2c = I2C_DT_SPEC_INST_GET(n), \ + .integration_time = DT_INST_PROP(n, integration_time), \ + .gain = DT_INST_PROP(n, gain)}; \ + SENSOR_DEVICE_DT_INST_DEFINE(n, tsl2561_init, NULL, &tsl2561_data_##n, \ + &tsl2561_config_##n, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &tsl2561_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(TSL2561_INIT_INST) diff --git a/drivers/sensor/vcnl4040/Kconfig b/drivers/sensor/vcnl4040/Kconfig index 5973316ca6a643e..a4e6be8d715bf38 100644 --- a/drivers/sensor/vcnl4040/Kconfig +++ b/drivers/sensor/vcnl4040/Kconfig @@ -21,7 +21,7 @@ config VCNL4040_ENABLE_ALS config VCNL4040_TRIGGER bool -choice +choice VCNL4040_TRIGGER prompt "Trigger mode" default VCNL4040_TRIGGER_NONE help diff --git a/drivers/sensor/vcnl4040/vcnl4040_trigger.c b/drivers/sensor/vcnl4040/vcnl4040_trigger.c index f47d70d0b392ee1..f2680b0b8befe89 100644 --- a/drivers/sensor/vcnl4040/vcnl4040_trigger.c +++ b/drivers/sensor/vcnl4040/vcnl4040_trigger.c @@ -86,8 +86,13 @@ static void vcnl4040_handle_int(const struct device *dev) } #ifdef CONFIG_VCNL4040_TRIGGER_OWN_THREAD -static void vcnl4040_thread_main(struct vcnl4040_data *data) +static void vcnl4040_thread_main(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct vcnl4040_data *data = p1; + while (true) { k_sem_take(&data->trig_sem, K_FOREVER); vcnl4040_handle_int(data->dev); @@ -266,7 +271,7 @@ int vcnl4040_trigger_init(const struct device *dev) k_sem_init(&data->trig_sem, 0, K_SEM_MAX_LIMIT); k_thread_create(&data->thread, data->thread_stack, CONFIG_VCNL4040_THREAD_STACK_SIZE, - (k_thread_entry_t)vcnl4040_thread_main, + vcnl4040_thread_main, data, NULL, NULL, K_PRIO_COOP(CONFIG_VCNL4040_THREAD_PRIORITY), 0, K_NO_WAIT); diff --git a/drivers/sensor/vl53l0x/Kconfig b/drivers/sensor/vl53l0x/Kconfig index 936ef923c8720d0..246962a257127eb 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 0865ff795496c8f..99a69ae727647f4 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/sensor/wsen_hids/wsen_hids_trigger.c b/drivers/sensor/wsen_hids/wsen_hids_trigger.c index 2de3b04c821dacc..e8c9472f5cd2c7a 100644 --- a/drivers/sensor/wsen_hids/wsen_hids_trigger.c +++ b/drivers/sensor/wsen_hids/wsen_hids_trigger.c @@ -89,8 +89,13 @@ static void hids_drdy_callback(const struct device *dev, struct gpio_callback *c } #ifdef CONFIG_WSEN_HIDS_TRIGGER_OWN_THREAD -static void hids_thread(struct hids_data *data) +static void hids_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct hids_data *data = p1; + while (true) { k_sem_take(&data->drdy_sem, K_FOREVER); hids_process_drdy_interrupt(data->dev); @@ -151,7 +156,7 @@ int hids_init_interrupt(const struct device *dev) k_sem_init(&data->drdy_sem, 0, K_SEM_MAX_LIMIT); k_thread_create(&data->thread, data->thread_stack, CONFIG_WSEN_HIDS_THREAD_STACK_SIZE, - (k_thread_entry_t)hids_thread, data, NULL, NULL, + hids_thread, data, NULL, NULL, K_PRIO_COOP(CONFIG_WSEN_HIDS_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_WSEN_HIDS_TRIGGER_GLOBAL_THREAD) data->work.handler = hids_work_cb; diff --git a/drivers/sensor/wsen_pads/wsen_pads_trigger.c b/drivers/sensor/wsen_pads/wsen_pads_trigger.c index a00fae8de1687f8..13394e23d9ad568 100644 --- a/drivers/sensor/wsen_pads/wsen_pads_trigger.c +++ b/drivers/sensor/wsen_pads/wsen_pads_trigger.c @@ -112,8 +112,13 @@ static void pads_drdy_callback(const struct device *dev, struct gpio_callback *c } #ifdef CONFIG_WSEN_PADS_TRIGGER_OWN_THREAD -static void pads_thread(struct pads_data *data) +static void pads_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct pads_data *data = p1; + while (true) { k_sem_take(&data->drdy_sem, K_FOREVER); pads_process_drdy_interrupt(data->dev); @@ -168,7 +173,7 @@ int pads_init_interrupt(const struct device *dev) k_sem_init(&data->drdy_sem, 0, K_SEM_MAX_LIMIT); k_thread_create(&data->thread, data->thread_stack, CONFIG_WSEN_PADS_THREAD_STACK_SIZE, - (k_thread_entry_t)pads_thread, data, NULL, NULL, + pads_thread, data, NULL, NULL, K_PRIO_COOP(CONFIG_WSEN_PADS_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_WSEN_PADS_TRIGGER_GLOBAL_THREAD) data->work.handler = pads_work_cb; diff --git a/drivers/sensor/wsen_tids/wsen_tids_trigger.c b/drivers/sensor/wsen_tids/wsen_tids_trigger.c index 9b7837d2a9a59de..d2ed4d91fefce68 100644 --- a/drivers/sensor/wsen_tids/wsen_tids_trigger.c +++ b/drivers/sensor/wsen_tids/wsen_tids_trigger.c @@ -118,8 +118,13 @@ static void tids_threshold_callback(const struct device *dev, struct gpio_callba } #ifdef CONFIG_WSEN_TIDS_TRIGGER_OWN_THREAD -static void tids_thread(struct tids_data *tids) +static void tids_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct tids_data *tids = p1; + while (true) { k_sem_take(&tids->threshold_sem, K_FOREVER); tids_process_threshold_interrupt(tids->dev); @@ -226,7 +231,7 @@ int tids_init_interrupt(const struct device *dev) k_sem_init(&data->threshold_sem, 0, K_SEM_MAX_LIMIT); k_thread_create(&data->thread, data->thread_stack, CONFIG_WSEN_TIDS_THREAD_STACK_SIZE, - (k_thread_entry_t)tids_thread, data, NULL, NULL, + tids_thread, data, NULL, NULL, K_PRIO_COOP(CONFIG_WSEN_TIDS_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_WSEN_TIDS_TRIGGER_GLOBAL_THREAD) data->work.handler = tids_work_cb; diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 7066ed177b320ee..075f61917042240 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -27,7 +27,13 @@ zephyr_library_sources_ifdef(CONFIG_UART_MSP432P4XX uart_msp432p4xx.c) zephyr_library_sources_ifdef(CONFIG_UART_MSPM0G3XXX uart_mspm0g3xxx.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,6 +72,9 @@ zephyr_library_sources_ifdef(CONFIG_UART_NUMAKER uart_numaker.c) 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_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) @@ -90,3 +99,5 @@ if(CONFIG_UART_NATIVE_TTY) 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 fd662d33b536c8a..567d81367e8047b 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -125,6 +125,29 @@ config UART_PIPE data (as contrary to console UART driver) and all aspects of received protocol data are handled by application provided callback. +config UART_ASYNC_RX_HELPER + bool "Helper for UART asynchronous reception" + help + Module implements handling of reception of variable length data using + Asynchronous UART API. It can be used in cases where received data processing + 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" @@ -245,4 +268,10 @@ source "drivers/serial/Kconfig.sedi" source "drivers/serial/Kconfig.bcm2711" +source "drivers/serial/Kconfig.intel_lw" + +source "drivers/serial/Kconfig.renesas_ra" + +source "drivers/serial/Kconfig.rzt2m" + endif # SERIAL diff --git a/drivers/serial/Kconfig.emul b/drivers/serial/Kconfig.emul index 2b48335b7576581..e61130a13c77e2f 100644 --- a/drivers/serial/Kconfig.emul +++ b/drivers/serial/Kconfig.emul @@ -12,3 +12,15 @@ config UART_EMUL select EXPERIMENTAL help Enable the emulated UART driver. + +if UART_EMUL + +config UART_EMUL_WORK_Q_STACK_SIZE + int "UART emulator work queue stack size" + default 2048 + +config UART_EMUL_WORK_Q_PRIORITY + int "UART emulator work queue thread priority" + default 1 + +endif # UART_EMUL diff --git a/drivers/serial/Kconfig.intel_lw b/drivers/serial/Kconfig.intel_lw new file mode 100644 index 000000000000000..478af03cf8120d4 --- /dev/null +++ b/drivers/serial/Kconfig.intel_lw @@ -0,0 +1,30 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +menuconfig UART_INTEL_LW + bool "Intel Lightweight UART driver" + depends on DT_HAS_INTEL_LW_UART_ENABLED + select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT + help + Enable the Intel Lightweight UART driver, that can be built into Intel NiosV CPU designs. + +if UART_INTEL_LW + +config UART_INTEL_LW_EOP + bool "Include end of packet register" + depends on UART_DRV_CMD && UART_INTERRUPT_DRIVEN + help + Use driver command CMD_ENABLE_EOP and CMD_DISABLE_EOP to use the feature. + +config UART_INTEL_LW_AUTO_LINE_CTRL_POLL + bool "Auto set RTS signal during poll out" + depends on UART_LINE_CTRL + help + Assert RTS before polling out a character, + and deassert RTS after the character is polled out. + Please note that this is not suitable, when polling out several characters. + Please use uart_drv_cmd with CMD_POLL_ASSERT_RTS before polling out. + Then use CMD_POLL_DEASSERT_RTS to resume normal operation after polling. + +endif # UART_INTEL_LW diff --git a/drivers/serial/Kconfig.it8xxx2 b/drivers/serial/Kconfig.it8xxx2 index 0a7a59ce08df492..f89874fef412e58 100644 --- a/drivers/serial/Kconfig.it8xxx2 +++ b/drivers/serial/Kconfig.it8xxx2 @@ -4,6 +4,7 @@ config UART_ITE_IT8XXX2 bool "ITE IT8XXX2 UART driver" default y + select UART_NS16550_ITE_HIGH_SPEED_BUADRATE depends on DT_HAS_ITE_IT8XXX2_UART_ENABLED help IT8XXX2 uses shared ns16550.c driver which does not diff --git a/drivers/serial/Kconfig.native_posix b/drivers/serial/Kconfig.native_posix index 39acf155f9bddb0..3af6601b5c742a0 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 1775b598c355f73..8995b6b9fbfa0f5 100644 --- a/drivers/serial/Kconfig.nrfx +++ b/drivers/serial/Kconfig.nrfx @@ -25,302 +25,71 @@ 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 + # NRF54L15 need new UARTE driver + depends on !SOC_SERIES_NRF54LX + # 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 in RAM, because EasyDMA in UARTE peripherals can only transfer data from RAM. -# ----------------- port 0 ----------------- if HAS_HW_NRF_UART0 || HAS_HW_NRF_UARTE0 +nrfx_uart_num = 0 +rsource "Kconfig.nrfx_uart_instance" +endif -config UART_0_ENHANCED_POLL_OUT - bool "Efficient poll out on port 0" - default y - depends on HAS_HW_NRF_UARTE0 - help - When enabled, polling out does not trigger interrupt which stops TX. - Feature uses a PPI channel. - -config UART_0_INTERRUPT_DRIVEN - bool "Interrupt support on port 0" - depends on UART_INTERRUPT_DRIVEN - default y - help - This option enables UART interrupt support on port 0. - -config UART_0_ASYNC - bool "Asynchronous API support on port 0" - depends on UART_ASYNC_API && !UART_0_INTERRUPT_DRIVEN - default y - help - This option enables UART Asynchronous API support on port 0. - -config UART_0_NRF_PARITY_BIT - bool "Parity bit" - help - Enable parity bit. - -config UART_0_NRF_TX_BUFFER_SIZE - int "Size of RAM buffer" - depends on HAS_HW_NRF_UARTE0 - range 1 65535 - default 32 - help - Size of the transmit buffer for API function: fifo_fill. - This value is limited by range of TXD.MAXCNT register for - particular SoC. - -config UART_0_NRF_HW_ASYNC - bool "Use hardware RX byte counting" - depends on HAS_HW_NRF_UARTE0 - depends on UART_ASYNC_API - help - If default driver uses interrupts to count incoming bytes, it is possible - that with higher speeds and/or high cpu load some data can be lost. - It is recommended to use hardware byte counting in such scenarios. - Hardware RX byte counting requires timer instance and one PPI channel - -config UART_0_NRF_ASYNC_LOW_POWER - bool "Low power mode" - depends on HAS_HW_NRF_UARTE0 - depends on UART_ASYNC_API - 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 - power consumption. It is only feasible if receiver is not always on. - -config UART_0_NRF_HW_ASYNC_TIMER - int "Timer instance" - depends on UART_0_NRF_HW_ASYNC - -config UART_0_GPIO_MANAGEMENT - bool "GPIO management on port 0" - depends on PM_DEVICE - default y - help - If enabled, the driver will configure the GPIOs used by the uart to - their default configuration when device is powered down. The GPIOs - will be configured back to correct state when UART is powered up. - -endif # HAS_HW_NRF_UART0 || HAS_HW_NRF_UARTE0 - -# ----------------- port 1 ----------------- if HAS_HW_NRF_UARTE1 +nrfx_uart_num = 1 +rsource "Kconfig.nrfx_uart_instance" +endif -config UART_1_INTERRUPT_DRIVEN - bool "Interrupt support on port 1" - depends on UART_INTERRUPT_DRIVEN - default y - help - This option enables UART interrupt support on port 1. - -config UART_1_ASYNC - bool "Asynchronous API support on port 1" - depends on UART_ASYNC_API && !UART_1_INTERRUPT_DRIVEN - default y - help - This option enables UART Asynchronous API support on port 1. - -config UART_1_ENHANCED_POLL_OUT - bool "Efficient poll out on port 1" - default y - help - When enabled, polling out does not trigger interrupt which stops TX. - Feature uses a PPI channel. - -config UART_1_NRF_PARITY_BIT - bool "Parity bit" - help - Enable parity bit. - -config UART_1_NRF_TX_BUFFER_SIZE - int "Size of RAM buffer" - depends on UART_INTERRUPT_DRIVEN - range 1 65535 - default 32 - help - Size of the transmit buffer for API function: fifo_fill. - This value is limited by range of TXD.MAXCNT register for - particular SoC. - -config UART_1_NRF_HW_ASYNC - bool "Use hardware RX byte counting" - depends on UART_1_ASYNC - help - If default driver uses interrupts to count incoming bytes, it is possible - that with higher speeds and/or high cpu load some data can be lost. - It is recommended to use hardware byte counting in such scenarios. - Hardware RX byte counting requires timer instance and one PPI channel - -config UART_1_NRF_ASYNC_LOW_POWER - bool "Low power mode" - depends on UART_ASYNC_API - 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 - power consumption. It is only feasible if receiver is not always on. - -config UART_1_NRF_HW_ASYNC_TIMER - int "Timer instance" - depends on UART_1_NRF_HW_ASYNC - -config UART_1_GPIO_MANAGEMENT - bool "GPIO management on port 1" - depends on PM_DEVICE - default y - help - If enabled, the driver will configure the GPIOs used by the uart to - their default configuration when device is powered down. The GPIOs - will be configured back to correct state when UART is powered up. - -endif # HAS_HW_NRF_UARTE1 - -# ----------------- port 2 ----------------- if HAS_HW_NRF_UARTE2 +nrfx_uart_num = 2 +rsource "Kconfig.nrfx_uart_instance" +endif -config UART_2_INTERRUPT_DRIVEN - bool "Interrupt support on port 2" - depends on UART_INTERRUPT_DRIVEN - default y - help - This option enables UART interrupt support on port 2. - -config UART_2_ASYNC - bool "Asynchronous API support on port 2" - depends on UART_ASYNC_API && !UART_2_INTERRUPT_DRIVEN - default y - help - This option enables UART Asynchronous API support on port 2. - -config UART_2_ENHANCED_POLL_OUT - bool "Efficient poll out on port 2" - default y - help - When enabled, polling out does not trigger interrupt which stops TX. - Feature uses a PPI channel. - -config UART_2_NRF_PARITY_BIT - bool "Parity bit" - help - Enable parity bit. - -config UART_2_NRF_TX_BUFFER_SIZE - int "Size of RAM buffer" - range 1 65535 - default 32 - help - Size of the transmit buffer for API function: fifo_fill. - This value is limited by range of TXD.MAXCNT register for - particular SoC. - -config UART_2_NRF_HW_ASYNC - bool "Use hardware RX byte counting" - depends on UART_2_ASYNC - help - If default driver uses interrupts to count incoming bytes, it is possible - that with higher speeds and/or high cpu load some data can be lost. - It is recommended to use hardware byte counting in such scenarios. - Hardware RX byte counting requires timer instance and one PPI channel - -config UART_2_NRF_ASYNC_LOW_POWER - bool "Low power mode" - depends on UART_ASYNC_API - 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 - power consumption. It is only feasible if receiver is not always on. - -config UART_2_NRF_HW_ASYNC_TIMER - int "Timer instance" - depends on UART_2_NRF_HW_ASYNC - -config UART_2_GPIO_MANAGEMENT - bool "GPIO management on port 2" - depends on PM_DEVICE - default y - help - If enabled, the driver will configure the GPIOs used by the uart to - their default configuration when device is powered down. The GPIOs - will be configured back to correct state when UART is powered up. - -endif # HAS_HW_NRF_UARTE2 - -# ----------------- port 3 ----------------- if HAS_HW_NRF_UARTE3 - -config UART_3_INTERRUPT_DRIVEN - bool "Interrupt support on port 3" - depends on UART_INTERRUPT_DRIVEN - default y - help - This option enables UART interrupt support on port 3. - -config UART_3_ASYNC - bool "Asynchronous API support on port 3" - depends on UART_ASYNC_API && !UART_3_INTERRUPT_DRIVEN - default y - help - This option enables UART Asynchronous API support on port 3. - -config UART_3_ENHANCED_POLL_OUT - bool "Efficient poll out on port 3" - default y - help - When enabled, polling out does not trigger interrupt which stops TX. - Feature uses a PPI channel. - -config UART_3_NRF_PARITY_BIT - bool "Parity bit" - help - Enable parity bit. - -config UART_3_NRF_TX_BUFFER_SIZE - int "Size of RAM buffer" - range 1 65535 - default 32 - help - Size of the transmit buffer for API function: fifo_fill. - This value is limited by range of TXD.MAXCNT register for - particular SoC. - -config UART_3_NRF_HW_ASYNC - bool "Use hardware RX byte counting" - depends on UART_3_ASYNC - help - If default driver uses interrupts to count incoming bytes, it is possible - that with higher speeds and/or high cpu load some data can be lost. - It is recommended to use hardware byte counting in such scenarios. - Hardware RX byte counting requires timer instance and one PPI channel - -config UART_3_NRF_ASYNC_LOW_POWER - bool "Low power mode" - depends on UART_ASYNC_API - 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 - power consumption. It is only feasible if receiver is not always on. - -config UART_3_NRF_HW_ASYNC_TIMER - int "Timer instance" - depends on UART_3_NRF_HW_ASYNC - -config UART_3_GPIO_MANAGEMENT - bool "GPIO management on port 3" - depends on PM_DEVICE - default y - help - If enabled, the driver will configure the GPIOs used by the uart to - their default configuration when device is powered down. The GPIOs - will be configured back to correct state when UART is powered up. - -endif # HAS_HW_NRF_UARTE3 - +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 config NRFX_TIMER0 default y @@ -357,23 +126,4 @@ config NRFX_TIMER4 || UART_2_NRF_HW_ASYNC_TIMER = 4 \ || UART_3_NRF_HW_ASYNC_TIMER = 4 - -config UARTE_NRF_HW_ASYNC - def_bool y - depends on UART_0_NRF_HW_ASYNC \ - || UART_1_NRF_HW_ASYNC \ - || UART_2_NRF_HW_ASYNC \ - || UART_3_NRF_HW_ASYNC - select NRFX_PPI if HAS_HW_NRF_PPI - select NRFX_DPPI if HAS_HW_NRF_DPPIC - -config UART_ENHANCED_POLL_OUT - def_bool y - depends on UART_0_ENHANCED_POLL_OUT \ - || UART_1_ENHANCED_POLL_OUT \ - || UART_2_ENHANCED_POLL_OUT \ - || UART_3_ENHANCED_POLL_OUT - select NRFX_PPI if HAS_HW_NRF_PPI - select NRFX_DPPI if HAS_HW_NRF_DPPIC - endif # UART_NRFX diff --git a/drivers/serial/Kconfig.nrfx_uart_instance b/drivers/serial/Kconfig.nrfx_uart_instance new file mode 100644 index 000000000000000..718631a4d096e32 --- /dev/null +++ b/drivers/serial/Kconfig.nrfx_uart_instance @@ -0,0 +1,121 @@ +#nRF UART(E) instance configuration + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +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). + +config UART_$(nrfx_uart_num)_ASYNC + bool "Asynchronous API support on port $(nrfx_uart_num)" + depends on UART_ASYNC_API && !UART_$(nrfx_uart_num)_INTERRUPT_DRIVEN + default y + help + This option enables UART Asynchronous API support on port $(nrfx_uart_num). + +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) + 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 + Enable parity bit. + +config UART_$(nrfx_uart_num)_NRF_TX_BUFFER_SIZE + int "Size of RAM buffer" + depends on HAS_HW_NRF_UARTE$(nrfx_uart_num) + depends on UART_NRFX_UARTE_LEGACY_SHIM + range 1 65535 + default 32 + help + Size of the transmit buffer for API function: fifo_fill. + This value is limited by range of TXD.MAXCNT register for + particular SoC. + +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 + If default driver uses interrupts to count incoming bytes, it is possible + that with higher speeds and/or high cpu load some data can be lost. + It is recommended to use hardware byte counting in such scenarios. + Hardware RX byte counting requires timer instance and one PPI channel. + +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 + power consumption. It is only feasible if receiver is not always on. + +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 + default y + help + If enabled, the driver will configure the GPIOs used by the uart to + their default configuration when device is powered down. The GPIOs + will be configured back to correct state when UART is powered up. diff --git a/drivers/serial/Kconfig.ns16550 b/drivers/serial/Kconfig.ns16550 index 90c2904604429ff..fd7f1156a14e727 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 @@ -77,6 +74,12 @@ config UART_NS16550_TI_K3 Texas Instruments K3 SoCs by enabling a vendor specific extended register set. +config UART_NS16550_ITE_HIGH_SPEED_BUADRATE + bool "IT8XXX2 specific baud rate configuration" + help + Enable IT8XXX2 specific baud rate configuration. + This applies to high-speed baud rate configuration. + menu "NS16550 Workarounds" config UART_NS16550_WA_ISR_REENABLE_INTERRUPT diff --git a/drivers/serial/Kconfig.renesas_ra b/drivers/serial/Kconfig.renesas_ra new file mode 100644 index 000000000000000..14311f27fe4aa12 --- /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.rzt2m b/drivers/serial/Kconfig.rzt2m new file mode 100644 index 000000000000000..2561499a5b5fd6c --- /dev/null +++ b/drivers/serial/Kconfig.rzt2m @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config UART_RZT2M + bool "Renesas RZ/T2M UART Driver" + default y + depends on DT_HAS_RENESAS_RZT2M_UART_ENABLED + select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT + select PINCTRL + help + Enable Renesas RZ/T2M UART Driver. diff --git a/drivers/serial/Kconfig.stm32 b/drivers/serial/Kconfig.stm32 index c6aa6051993e9da..75d0e22c157ce4c 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 471e5eb72694452..02492e7483fceb6 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_rx.c b/drivers/serial/uart_async_rx.c new file mode 100644 index 000000000000000..68e17691c3efad6 --- /dev/null +++ b/drivers/serial/uart_async_rx.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +static uint8_t inc(struct uart_async_rx *rx_data, uint8_t val) +{ + return (val + 1) & (rx_data->config->buf_cnt - 1); +} + +static struct uart_async_rx_buf *get_buf(struct uart_async_rx *rx_data, uint8_t idx) +{ + uint8_t *p = rx_data->config->buffer; + + p += idx * (rx_data->buf_len + sizeof(struct uart_async_rx_buf)); + + return (struct uart_async_rx_buf *)p; +} + +uint8_t *uart_async_rx_buf_req(struct uart_async_rx *rx_data) +{ + uint8_t *data = NULL; + + if (rx_data->free_buf_cnt != 0) { + struct uart_async_rx_buf *buf = get_buf(rx_data, rx_data->drv_buf_idx); + + data = buf->buffer; + rx_data->drv_buf_idx = inc(rx_data, rx_data->drv_buf_idx); + + atomic_dec(&rx_data->free_buf_cnt); + } + + return data; +} + +void uart_async_rx_on_rdy(struct uart_async_rx *rx_data, uint8_t *buffer, size_t length) +{ + /* Cannot use CONTAINER_OF because validation fails due to type mismatch: + * uint8_t * vs uint8_t []. + */ + struct uart_async_rx_buf *rx_buf = + (struct uart_async_rx_buf *)(buffer - offsetof(struct uart_async_rx_buf, buffer)); + + rx_buf->wr_idx += length; + __ASSERT_NO_MSG(rx_buf->wr_idx <= rx_data->buf_len); + + atomic_add(&rx_data->pending_bytes, length); +} + +static void buf_reset(struct uart_async_rx_buf *buf) +{ + buf->rd_idx = 0; + buf->wr_idx = 0; + buf->completed = 0; +} +static void usr_rx_buf_release(struct uart_async_rx *rx_data, struct uart_async_rx_buf *buf) +{ + buf_reset(buf); + rx_data->rd_buf_idx = inc(rx_data, rx_data->rd_buf_idx); + atomic_inc(&rx_data->free_buf_cnt); + __ASSERT_NO_MSG(rx_data->free_buf_cnt <= rx_data->config->buf_cnt); +} + +void uart_async_rx_on_buf_rel(struct uart_async_rx *rx_data, uint8_t *buffer) +{ + /* Cannot use CONTAINER_OF because validation fails due to type mismatch: + * uint8_t * vs uint8_t []. + */ + struct uart_async_rx_buf *rx_buf = + (struct uart_async_rx_buf *)(buffer - offsetof(struct uart_async_rx_buf, buffer)); + + rx_buf->completed = 1; + rx_data->wr_buf_idx = inc(rx_data, rx_data->wr_buf_idx); +} + +size_t uart_async_rx_data_claim(struct uart_async_rx *rx_data, uint8_t **data, size_t length) +{ + struct uart_async_rx_buf *buf; + int rem; + + if ((rx_data->pending_bytes == 0) || (length == 0)) { + return 0; + } + + do { + buf = get_buf(rx_data, rx_data->rd_buf_idx); + if ((buf->rd_idx == buf->wr_idx) && (buf->completed == 1)) { + usr_rx_buf_release(rx_data, buf); + } else { + break; + } + } while (1); + + *data = &buf->buffer[buf->rd_idx]; + rem = buf->wr_idx - buf->rd_idx; + + return MIN(length, rem); +} + +void uart_async_rx_data_consume(struct uart_async_rx *rx_data, size_t length) +{ + struct uart_async_rx_buf *buf = get_buf(rx_data, rx_data->rd_buf_idx); + + buf->rd_idx += length; + + atomic_sub(&rx_data->pending_bytes, length); + + __ASSERT_NO_MSG(buf->rd_idx <= buf->wr_idx); +} + +void uart_async_rx_reset(struct uart_async_rx *rx_data) +{ + rx_data->free_buf_cnt = rx_data->config->buf_cnt; + for (uint8_t i = 0; i < rx_data->config->buf_cnt; i++) { + buf_reset(get_buf(rx_data, i)); + } +} + +int uart_async_rx_init(struct uart_async_rx *rx_data, + const struct uart_async_rx_config *config) +{ + __ASSERT_NO_MSG(config->length / config->buf_cnt <= UINT8_MAX); + memset(rx_data, 0, sizeof(*rx_data)); + rx_data->config = config; + rx_data->buf_len = (config->length / config->buf_cnt) - UART_ASYNC_RX_BUF_OVERHEAD; + uart_async_rx_reset(rx_data); + + return 0; +} diff --git a/drivers/serial/uart_async_to_irq.c b/drivers/serial/uart_async_to_irq.c new file mode 100644 index 000000000000000..209e8d4f2053d25 --- /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 cb2d7ebd19049b8..e2502f4fd9b0e69 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 70c8e5d62208f3b..d9e1769df5f571c 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_emul.c b/drivers/serial/uart_emul.c index 55c726f96b01bc1..645c888e5392b36 100644 --- a/drivers/serial/uart_emul.c +++ b/drivers/serial/uart_emul.c @@ -19,6 +19,7 @@ LOG_MODULE_REGISTER(uart_emul, CONFIG_UART_LOG_LEVEL); struct uart_emul_config { bool loopback; + size_t latch_buffer_size; }; struct uart_emul_work { @@ -29,6 +30,7 @@ struct uart_emul_work { /* Device run time data */ struct uart_emul_data { struct uart_config cfg; + int errors; struct ring_buf *rx_rb; struct k_spinlock rx_lock; @@ -41,12 +43,35 @@ struct uart_emul_data { #ifdef CONFIG_UART_INTERRUPT_DRIVEN bool rx_irq_en; + bool tx_irq_en; struct uart_emul_work irq_work; uart_irq_callback_user_data_t irq_cb; void *irq_cb_udata; #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ }; +/* + * Define local thread to emulate different thread priorities. + * + * A UART driver may call back from within a thread with higher or lower priority + * than the thread calling the UART API. This can hide potential concurrency issues, + * especially if the thread priorities are the same, or even using the same thread + * in case the system work queue. + */ +K_THREAD_STACK_DEFINE(uart_emul_stack_area, CONFIG_UART_EMUL_WORK_Q_STACK_SIZE); +struct k_work_q uart_emul_work_q; + +int uart_emul_init_work_q(void) +{ + k_work_queue_init(&uart_emul_work_q); + k_work_queue_start(&uart_emul_work_q, uart_emul_stack_area, + K_THREAD_STACK_SIZEOF(uart_emul_stack_area), + CONFIG_UART_EMUL_WORK_Q_PRIORITY, NULL); + return 0; +} + +SYS_INIT(uart_emul_init_work_q, POST_KERNEL, 0); + static int uart_emul_poll_in(const struct device *dev, unsigned char *p_char) { struct uart_emul_data *drv_data = dev->data; @@ -92,7 +117,11 @@ static void uart_emul_poll_out(const struct device *dev, unsigned char out_char) static int uart_emul_err_check(const struct device *dev) { - return 0; + struct uart_emul_data *drv_data = dev->data; + int errors = drv_data->errors; + + drv_data->errors = 0; + return errors; } #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE @@ -114,21 +143,55 @@ static int uart_emul_config_get(const struct device *dev, struct uart_config *cf #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ #ifdef CONFIG_UART_INTERRUPT_DRIVEN -static int uart_emul_fifo_read(const struct device *dev, uint8_t *rx_data, int size) +static int uart_emul_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size) { int ret; struct uart_emul_data *data = dev->data; + const struct uart_emul_config *config = dev->config; + uint32_t put_size = MIN(config->latch_buffer_size, size); + + K_SPINLOCK(&data->tx_lock) { + ret = ring_buf_put(data->tx_rb, tx_data, put_size); + } + + if (config->loopback) { + uart_emul_put_rx_data(dev, (uint8_t *)tx_data, put_size); + } + if (data->tx_data_ready_cb) { + data->tx_data_ready_cb(dev, ring_buf_size_get(data->tx_rb), data->user_data); + } + + return ret; +} + +static int uart_emul_fifo_read(const struct device *dev, uint8_t *rx_data, int size) +{ + struct uart_emul_data *data = dev->data; + const struct uart_emul_config *config = dev->config; + uint32_t bytes_to_read; K_SPINLOCK(&data->rx_lock) { - ret = MIN(size, ring_buf_size_get(data->rx_rb)); - size = ret; + bytes_to_read = MIN(config->latch_buffer_size, ring_buf_size_get(data->rx_rb)); + ring_buf_get(data->rx_rb, rx_data, bytes_to_read); + } - for (int n = 0; size > 0; size -= n, rx_data += n) { - n = ring_buf_get(data->rx_rb, rx_data, size); + return bytes_to_read; +} + +static int uart_emul_irq_tx_ready(const struct device *dev) +{ + bool ready = false; + struct uart_emul_data *data = dev->data; + + K_SPINLOCK(&data->tx_lock) { + if (!data->tx_irq_en) { + K_SPINLOCK_BREAK; } + + ready = ring_buf_space_get(data->tx_rb) > 0; } - return ret; + return ready; } static int uart_emul_irq_rx_ready(const struct device *dev) @@ -163,6 +226,14 @@ static void uart_emul_irq_handler(struct k_work *work) while (true) { bool have_work = false; + K_SPINLOCK(&data->tx_lock) { + if (!data->tx_irq_en) { + K_SPINLOCK_BREAK; + } + + have_work = have_work || ring_buf_space_get(data->tx_rb) > 0; + } + K_SPINLOCK(&data->rx_lock) { if (!data->rx_irq_en) { K_SPINLOCK_BREAK; @@ -181,14 +252,22 @@ static void uart_emul_irq_handler(struct k_work *work) static int uart_emul_irq_is_pending(const struct device *dev) { - bool rx_pending; + return uart_emul_irq_tx_ready(dev) || uart_emul_irq_rx_ready(dev); +} + +static void uart_emul_irq_tx_enable(const struct device *dev) +{ + bool submit_irq_work; struct uart_emul_data *const data = dev->data; - K_SPINLOCK(&data->rx_lock) { - rx_pending = !ring_buf_is_empty(data->rx_rb); + K_SPINLOCK(&data->tx_lock) { + data->tx_irq_en = true; + submit_irq_work = ring_buf_space_get(data->tx_rb) > 0; } - return rx_pending; + if (submit_irq_work) { + (void)k_work_submit_to_queue(&uart_emul_work_q, &data->irq_work.work); + } } static void uart_emul_irq_rx_enable(const struct device *dev) @@ -202,7 +281,16 @@ static void uart_emul_irq_rx_enable(const struct device *dev) } if (submit_irq_work) { - (void)k_work_submit(&data->irq_work.work); + (void)k_work_submit_to_queue(&uart_emul_work_q, &data->irq_work.work); + } +} + +static void uart_emul_irq_tx_disable(const struct device *dev) +{ + struct uart_emul_data *const data = dev->data; + + K_SPINLOCK(&data->tx_lock) { + data->tx_irq_en = false; } } @@ -215,6 +303,18 @@ static void uart_emul_irq_rx_disable(const struct device *dev) } } +static int uart_emul_irq_tx_complete(const struct device *dev) +{ + bool tx_complete = false; + struct uart_emul_data *const data = dev->data; + + K_SPINLOCK(&data->tx_lock) { + tx_complete = ring_buf_is_empty(data->tx_rb); + } + + return tx_complete; +} + static void uart_emul_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb, void *user_data) { @@ -239,10 +339,15 @@ static const struct uart_driver_api uart_emul_api = { #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ .err_check = uart_emul_err_check, #ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = uart_emul_fifo_fill, .fifo_read = uart_emul_fifo_read, + .irq_tx_enable = uart_emul_irq_tx_enable, .irq_rx_enable = uart_emul_irq_rx_enable, + .irq_tx_disable = uart_emul_irq_tx_disable, .irq_rx_disable = uart_emul_irq_rx_disable, + .irq_tx_ready = uart_emul_irq_tx_ready, .irq_rx_ready = uart_emul_irq_rx_ready, + .irq_tx_complete = uart_emul_irq_tx_complete, .irq_callback_set = uart_emul_irq_callback_set, .irq_update = uart_emul_irq_update, .irq_is_pending = uart_emul_irq_is_pending, @@ -271,9 +376,13 @@ uint32_t uart_emul_put_rx_data(const struct device *dev, uint8_t *data, size_t s IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, (irq_en = drv_data->rx_irq_en;)); } + if (count < size) { + uart_emul_set_errors(dev, UART_ERROR_OVERRUN); + } + IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, ( if (count > 0 && irq_en && !empty) { - (void)k_work_submit(&drv_data->irq_work.work); + (void)k_work_submit_to_queue(&uart_emul_work_q, &drv_data->irq_work.work); } )) @@ -318,6 +427,13 @@ uint32_t uart_emul_flush_tx_data(const struct device *dev) return count; } +void uart_emul_set_errors(const struct device *dev, int errors) +{ + struct uart_emul_data *drv_data = dev->data; + + drv_data->errors |= errors; +} + #define UART_EMUL_RX_FIFO_SIZE(inst) (DT_INST_PROP(inst, rx_fifo_size)) #define UART_EMUL_TX_FIFO_SIZE(inst) (DT_INST_PROP(inst, tx_fifo_size)) @@ -333,6 +449,7 @@ uint32_t uart_emul_flush_tx_data(const struct device *dev) \ static struct uart_emul_config uart_emul_cfg_##inst = { \ .loopback = DT_INST_PROP(inst, loopback), \ + .latch_buffer_size = DT_INST_PROP(inst, latch_buffer_size), \ }; \ static struct uart_emul_data uart_emul_data_##inst = { \ .rx_rb = &uart_emul_##inst##_rx_rb, \ diff --git a/drivers/serial/uart_esp32.c b/drivers/serial/uart_esp32.c index 6608d91a44ade37..be5d2487e137115 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_handlers.c b/drivers/serial/uart_handlers.c index 1dd4dd78f10460f..954592aca28b737 100644 --- a/drivers/serial/uart_handlers.c +++ b/drivers/serial/uart_handlers.c @@ -5,19 +5,19 @@ */ #include -#include +#include #define UART_SIMPLE(op_) \ static inline int z_vrfy_uart_##op_(const struct device *dev) \ { \ - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, op_)); \ + K_OOPS(K_SYSCALL_DRIVER_UART(dev, op_)); \ return z_impl_uart_ ## op_(dev); \ } #define UART_SIMPLE_VOID(op_) \ static inline void z_vrfy_uart_##op_(const struct device *dev) \ { \ - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, op_)); \ + K_OOPS(K_SYSCALL_DRIVER_UART(dev, op_)); \ z_impl_uart_ ## op_(dev); \ } @@ -27,8 +27,8 @@ UART_SIMPLE(err_check) static inline int z_vrfy_uart_poll_in(const struct device *dev, unsigned char *p_char) { - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, poll_in)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(p_char, sizeof(unsigned char))); + K_OOPS(K_SYSCALL_DRIVER_UART(dev, poll_in)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(p_char, sizeof(unsigned char))); return z_impl_uart_poll_in(dev, p_char); } #include @@ -36,8 +36,8 @@ static inline int z_vrfy_uart_poll_in(const struct device *dev, static inline int z_vrfy_uart_poll_in_u16(const struct device *dev, uint16_t *p_u16) { - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, poll_in)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(p_u16, sizeof(uint16_t))); + K_OOPS(K_SYSCALL_DRIVER_UART(dev, poll_in)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(p_u16, sizeof(uint16_t))); return z_impl_uart_poll_in_u16(dev, p_u16); } #include @@ -45,7 +45,7 @@ static inline int z_vrfy_uart_poll_in_u16(const struct device *dev, static inline void z_vrfy_uart_poll_out(const struct device *dev, unsigned char out_char) { - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, poll_out)); + K_OOPS(K_SYSCALL_DRIVER_UART(dev, poll_out)); z_impl_uart_poll_out((const struct device *)dev, out_char); } #include @@ -53,7 +53,7 @@ static inline void z_vrfy_uart_poll_out(const struct device *dev, static inline void z_vrfy_uart_poll_out_u16(const struct device *dev, uint16_t out_u16) { - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, poll_out)); + K_OOPS(K_SYSCALL_DRIVER_UART(dev, poll_out)); z_impl_uart_poll_out_u16((const struct device *)dev, out_u16); } #include @@ -62,8 +62,8 @@ static inline void z_vrfy_uart_poll_out_u16(const struct device *dev, static inline int z_vrfy_uart_config_get(const struct device *dev, struct uart_config *cfg) { - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, config_get)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(cfg, sizeof(struct uart_config))); + K_OOPS(K_SYSCALL_DRIVER_UART(dev, config_get)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(cfg, sizeof(struct uart_config))); return z_impl_uart_config_get(dev, cfg); } @@ -72,8 +72,8 @@ static inline int z_vrfy_uart_config_get(const struct device *dev, static inline int z_vrfy_uart_configure(const struct device *dev, const struct uart_config *cfg) { - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, config_get)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(cfg, sizeof(struct uart_config))); + K_OOPS(K_SYSCALL_DRIVER_UART(dev, config_get)); + K_OOPS(K_SYSCALL_MEMORY_READ(cfg, sizeof(struct uart_config))); return z_impl_uart_configure(dev, cfg); } @@ -90,8 +90,8 @@ static inline int z_vrfy_uart_configure(const struct device *dev, static inline int z_vrfy_uart_tx(const struct device *dev, const uint8_t *buf, size_t len, int32_t timeout) { - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, tx)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(buf, len)); + K_OOPS(K_SYSCALL_DRIVER_UART(dev, tx)); + K_OOPS(K_SYSCALL_MEMORY_READ(buf, len)); return z_impl_uart_tx(dev, buf, len, timeout); } #include @@ -101,8 +101,8 @@ static inline int z_vrfy_uart_tx_u16(const struct device *dev, const uint16_t *buf, size_t len, int32_t timeout) { - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, tx)); - Z_OOPS(Z_SYSCALL_MEMORY_ARRAY_READ(buf, len, sizeof(uint16_t))); + K_OOPS(K_SYSCALL_DRIVER_UART(dev, tx)); + K_OOPS(K_SYSCALL_MEMORY_ARRAY_READ(buf, len, sizeof(uint16_t))); return z_impl_uart_tx_u16(dev, buf, len, timeout); } #include @@ -115,8 +115,8 @@ static inline int z_vrfy_uart_rx_enable(const struct device *dev, uint8_t *buf, size_t len, int32_t timeout) { - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, rx_enable)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(buf, len)); + K_OOPS(K_SYSCALL_DRIVER_UART(dev, rx_enable)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(buf, len)); return z_impl_uart_rx_enable(dev, buf, len, timeout); } #include @@ -126,8 +126,8 @@ static inline int z_vrfy_uart_rx_enable_u16(const struct device *dev, uint16_t *buf, size_t len, int32_t timeout) { - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, rx_enable)); - Z_OOPS(Z_SYSCALL_MEMORY_ARRAY_WRITE(buf, len, sizeof(uint16_t))); + K_OOPS(K_SYSCALL_DRIVER_UART(dev, rx_enable)); + K_OOPS(K_SYSCALL_MEMORY_ARRAY_WRITE(buf, len, sizeof(uint16_t))); return z_impl_uart_rx_enable_u16(dev, buf, len, timeout); } #include @@ -160,7 +160,7 @@ UART_SIMPLE(irq_update) static inline int z_vrfy_uart_line_ctrl_set(const struct device *dev, uint32_t ctrl, uint32_t val) { - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, line_ctrl_set)); + K_OOPS(K_SYSCALL_DRIVER_UART(dev, line_ctrl_set)); return z_impl_uart_line_ctrl_set((const struct device *)dev, ctrl, val); } @@ -169,8 +169,8 @@ static inline int z_vrfy_uart_line_ctrl_set(const struct device *dev, static inline int z_vrfy_uart_line_ctrl_get(const struct device *dev, uint32_t ctrl, uint32_t *val) { - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, line_ctrl_get)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(val, sizeof(uint32_t))); + K_OOPS(K_SYSCALL_DRIVER_UART(dev, line_ctrl_get)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(val, sizeof(uint32_t))); return z_impl_uart_line_ctrl_get((const struct device *)dev, ctrl, (uint32_t *)val); } @@ -181,7 +181,7 @@ static inline int z_vrfy_uart_line_ctrl_get(const struct device *dev, static inline int z_vrfy_uart_drv_cmd(const struct device *dev, uint32_t cmd, uint32_t p) { - Z_OOPS(Z_SYSCALL_DRIVER_UART(dev, drv_cmd)); + K_OOPS(K_SYSCALL_DRIVER_UART(dev, drv_cmd)); return z_impl_uart_drv_cmd((const struct device *)dev, cmd, p); } #include diff --git a/drivers/serial/uart_hostlink.c b/drivers/serial/uart_hostlink.c index a129c67d30fb847..396422b6e190390 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 d60289565a80862..97e411a93063f2f 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_intel_lw.c b/drivers/serial/uart_intel_lw.c new file mode 100644 index 000000000000000..9b2a877fbdc3dbf --- /dev/null +++ b/drivers/serial/uart_intel_lw.c @@ -0,0 +1,1025 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief UART driver for Intel FPGA UART Core IP + * Reference : Embedded Peripherals IP User Guide (22.3 and above): 55. + * Lightweight UART Core + */ + +#define DT_DRV_COMPAT intel_lw_uart +#include +#include + +#include + +/* register offsets */ +#define INTEL_LW_UART_OFFSET (0x4) + +#define INTEL_LW_UART_RXDATA_REG_OFFSET (0 * INTEL_LW_UART_OFFSET) +#define INTEL_LW_UART_TXDATA_REG_OFFSET (1 * INTEL_LW_UART_OFFSET) +#define INTEL_LW_UART_STATUS_REG_OFFSET (2 * INTEL_LW_UART_OFFSET) +#define INTEL_LW_UART_CONTROL_REG_OFFSET (3 * INTEL_LW_UART_OFFSET) +#define INTEL_LW_UART_DIVISOR_REG_OFFSET (4 * INTEL_LW_UART_OFFSET) +#define INTEL_LW_UART_EOP_REG_OFFSET (5 * INTEL_LW_UART_OFFSET) + +/*status register mask */ +#define INTEL_LW_UART_STATUS_PE_MSK (0x1) +#define INTEL_LW_UART_STATUS_FE_MSK (0x2) +#define INTEL_LW_UART_STATUS_BRK_MSK (0x4) +#define INTEL_LW_UART_STATUS_ROE_MSK (0x8) +#define INTEL_LW_UART_STATUS_TOE_MSK (0x10) +#define INTEL_LW_UART_STATUS_TMT_MSK (0x20) +#define INTEL_LW_UART_STATUS_TRDY_MSK (0x40) +#define INTEL_LW_UART_STATUS_RRDY_MSK (0x80) +#define INTEL_LW_UART_STATUS_DCTS_MSK (0x400) +#define INTEL_LW_UART_STATUS_CTS_MSK (0x800) +#define INTEL_LW_UART_STATUS_E_MSK (0x100) +#define INTEL_LW_UART_STATUS_EOP_MSK (0x1000) + +/* control register mask */ +#define INTEL_LW_UART_CONTROL_TMT_MSK (0x20) +#define INTEL_LW_UART_CONTROL_TRDY_MSK (0x40) +#define INTEL_LW_UART_CONTROL_RRDY_MSK (0x80) +#define INTEL_LW_UART_CONTROL_E_MSK (0x100) +#define INTEL_LW_UART_CONTROL_TRBK_MSK (0x200) +#define INTEL_LW_UART_CONTROL_DCTS_MSK (0x400) +#define INTEL_LW_UART_CONTROL_RTS_MSK (0x800) +#define INTEL_LW_UART_CONTROL_EOP_MSK (0x1000) + +/* defined values */ +#define UART_INTEL_LW_NO_ERROR (0u) +#define INTEL_LW_UART_CLEAR_STATUS_VAL (0u) +#define INTEL_LW_UART_PENDING_MASK (INTEL_LW_UART_STATUS_RRDY_MSK | \ + INTEL_LW_UART_STATUS_TRDY_MSK | INTEL_LW_UART_STATUS_E_MSK \ + | INTEL_LW_UART_STATUS_EOP_MSK) + +/***********************/ +/* configuration flags */ +/* + * The value INTEL_LW_UART_FB is a value set in the devices flag field to + * indicate that the device has a fixed baud rate; i.e. if this flag is set + * software can not control the baud rate of the device. + */ +#define INTEL_LW_UART_FB 0x1 + +/* + * The value INTEL_LW_UART_FC is a value set in the device flag field to + * indicate the the device is using flow control, i.e. the driver must + * throttle on transmit if the nCTS pin is low. + */ +#define INTEL_LW_UART_FC 0x2 + +/* end of configuration flags */ +/******************************/ + +/* device data */ +struct uart_intel_lw_device_data { + struct uart_config uart_cfg; /* stores uart config from device tree*/ + struct k_spinlock lock; + uint32_t status_act; /* stores value of status register. */ +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_user_data_t cb; /**< Callback function pointer */ + void *cb_data; /**< Callback function arg */ +#ifdef CONFIG_UART_INTEL_LW_EOP + uint8_t set_eop_cb; + uart_irq_callback_user_data_t cb_eop; /**< Callback function pointer */ + void *cb_data_eop; /**< Callback function arg */ +#endif /* CONFIG_UART_INTEL_LW_EOP */ + uint32_t control_val; /* stores value to set control register. */ +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +}; + +/* + * device config: + * stores data that cannot be changed during run time. + */ +struct uart_intel_lw_device_config { + mm_reg_t base; + uint32_t flags; /* refer to configuration flags */ +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_config_func_t irq_config_func; + unsigned int irq_num; +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +}; + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +/** + * function prototypes + */ +static int uart_intel_lw_irq_update(const struct device *dev); +static int uart_intel_lw_irq_tx_ready(const struct device *dev); +static int uart_intel_lw_irq_rx_ready(const struct device *dev); +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +/** + * @brief Poll the device for input. + * + * This is a non-blocking function. + * + * This driver supports interrupt driven api. + * Polling for data under normal operation, might cause unexpected behaviour. + * If users wish to poll in for data, please ensure that the data is not retrieved + * in interrupt. + * + * If UART_LINE_CTRL is enabled, please do not disable the hardware + * interrupt for this uart device, as the flow control is handled in uart_intel_lw_dcts_isr. + * + * @param dev UART device instance + * @param p_char Pointer to character + * + * @return 0 if a character arrived, -1 if input buffer is empty. + * -EINVAL if p_char is null pointer + */ +static int uart_intel_lw_poll_in(const struct device *dev, unsigned char *p_char) +{ + const struct uart_intel_lw_device_config *config = dev->config; + struct uart_intel_lw_device_data *data = dev->data; + int ret_val = -1; + uint32_t status; + + /* generate fatal error if CONFIG_ASSERT is enabled. */ + __ASSERT(p_char != NULL, "p_char is null pointer!"); + + /* Stop, if p_char is null pointer */ + if (p_char == NULL) { + return -EINVAL; + } + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + /* check if received character is ready.*/ + status = sys_read32(config->base + INTEL_LW_UART_STATUS_REG_OFFSET); + if (status & INTEL_LW_UART_STATUS_RRDY_MSK) { + /* got a character */ + *p_char = sys_read32(config->base + INTEL_LW_UART_RXDATA_REG_OFFSET); + ret_val = 0; + } + + k_spin_unlock(&data->lock, key); + + return ret_val; +} + +/** + * @brief Output a character in polled mode. + * + * This function will block until transmitter is ready. + * Then, a character will be transmitted. + * + * This driver supports interrupt driven api. + * Polling for data under normal operation, might cause unexpected behaviour. + * If users wish to poll out data, please ensure that the data is not transmitted + * in interrupt. + * + * If UART_LINE_CTRL is enabled and users wish to poll out only 1 character, + * please enable UART_INTEL_LW_AUTO_LINE_CTRL_POLL. Please note that this might + * be inefficient, in case of polling out several characters. Instead of using + * UART_INTEL_LW_AUTO_LINE_CTRL_POLL, please consider using the api: uart_drv_cmd + * with CMD_POLL_ASSERT_RTS before polling out. Then use CMD_POLL_DEASSERT_RTS to + * resume normal operation after all characters are polled out. + * + * Please do not set CMD_TRBK_EN, when polling out data. + * + * @param dev UART device instance + * @param c Character to send + */ +static void uart_intel_lw_poll_out(const struct device *dev, unsigned char c) +{ + const struct uart_intel_lw_device_config *config = dev->config; + struct uart_intel_lw_device_data *data = dev->data; + uint32_t status; + bool tx_is_free = false; + bool poll_out_done = false; + k_spinlock_key_t key; + + /* wait until uart is free to transmit.*/ + do { + key = k_spin_lock(&data->lock); + + if (tx_is_free == false) { + status = sys_read32(config->base + INTEL_LW_UART_STATUS_REG_OFFSET); + + /* wait until there is space in fifo. */ + if (status & INTEL_LW_UART_STATUS_TRDY_MSK) { +#ifdef CONFIG_UART_INTEL_LW_AUTO_LINE_CTRL_POLL + data->control_val |= INTEL_LW_UART_CONTROL_RTS_MSK; + sys_write32(data->control_val, config->base + + INTEL_LW_UART_CONTROL_REG_OFFSET); +#endif + sys_write32(c, config->base + INTEL_LW_UART_TXDATA_REG_OFFSET); + tx_is_free = true; + } + } else { + status = sys_read32(config->base + INTEL_LW_UART_STATUS_REG_OFFSET); + + /* wait until fifo data is shifted out. */ + if (status & INTEL_LW_UART_STATUS_TMT_MSK) { +#ifdef CONFIG_UART_INTEL_LW_AUTO_LINE_CTRL_POLL + data->control_val &= ~INTEL_LW_UART_CONTROL_RTS_MSK; + sys_write32(data->control_val, config->base + + INTEL_LW_UART_CONTROL_REG_OFFSET); +#endif + poll_out_done = true; + } + } + + k_spin_unlock(&data->lock, key); + } while (!poll_out_done); +} + +/** + * @brief Initialise an instance of the driver + * + * This function initialise the interrupt configuration for the driver. + * + * @param dev UART device instance + * + * @return 0 to indicate success. + */ +static int uart_intel_lw_init(const struct device *dev) +{ +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + struct uart_intel_lw_device_data *data = dev->data; + const struct uart_intel_lw_device_config *config = dev->config; + /* clear status to ensure, that interrupts are not triggered due to old status. */ + sys_write32(INTEL_LW_UART_CLEAR_STATUS_VAL, config->base + + INTEL_LW_UART_STATUS_REG_OFFSET); + + /* + * Enable hardware interrupt. + * The corresponding csr from IP still needs to be set, + * so that the IP generates interrupt signal. + */ + config->irq_config_func(dev); + +#ifdef CONFIG_UART_LINE_CTRL + /* Enable DCTS interrupt. */ + data->control_val = INTEL_LW_UART_CONTROL_DCTS_MSK; +#endif /* CONFIG_UART_LINE_CTRL */ + + sys_write32(data->control_val, config->base + INTEL_LW_UART_CONTROL_REG_OFFSET); + +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + + return 0; +} + +/** + * @brief Check if an error was received + * If error is received, it will be mapped to uart_rx_stop_reason. + * This function should be called after irq_update. + * If interrupt driven API is not enabled, + * this function will read and clear the status register. + * + * @param dev UART device struct + * + * @return UART_ERROR_OVERRUN, UART_ERROR_PARITY, UART_ERROR_FRAMING, + * UART_BREAK if an error was detected, 0 otherwise. + */ +static int uart_intel_lw_err_check(const struct device *dev) +{ + struct uart_intel_lw_device_data *data = dev->data; + int err = UART_INTEL_LW_NO_ERROR; + +#ifndef CONFIG_UART_INTERRUPT_DRIVEN + const struct uart_intel_lw_device_config *config = dev->config; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + data->status_act = sys_read32(config->base + INTEL_LW_UART_STATUS_REG_OFFSET); +#endif + + if (data->status_act & INTEL_LW_UART_STATUS_E_MSK) { + if (data->status_act & INTEL_LW_UART_STATUS_PE_MSK) { + err |= UART_ERROR_PARITY; + } + + if (data->status_act & INTEL_LW_UART_STATUS_FE_MSK) { + err |= UART_ERROR_FRAMING; + } + + if (data->status_act & INTEL_LW_UART_STATUS_BRK_MSK) { + err |= UART_BREAK; + } + + if (data->status_act & INTEL_LW_UART_STATUS_ROE_MSK) { + err |= UART_ERROR_OVERRUN; + } + } + +#ifndef CONFIG_UART_INTERRUPT_DRIVEN + /* clear status */ + sys_write32(INTEL_LW_UART_CLEAR_STATUS_VAL, config->base + + INTEL_LW_UART_STATUS_REG_OFFSET); + k_spin_unlock(&data->lock, key); +#endif + + return err; +} + +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE +/*** + * @brief helper function to check, if the configuration is support. + * The only parameter that can be changed during runtime is the baudrate. + * + * @param cfg_stored The original configuration. + * @param cfg_in The input configuration. + * @return true if parameter other than baudrate remains the same. otherwise, false. + */ +static bool uart_intel_lw_check_configuration(const struct uart_config *cfg_stored, + const struct uart_config *cfg_in) +{ + bool ret_val = false; + + if ((cfg_stored->parity == cfg_in->parity) + && (cfg_stored->stop_bits == cfg_in->stop_bits) + && (cfg_stored->data_bits == cfg_in->data_bits) + && (cfg_stored->flow_ctrl == cfg_in->flow_ctrl)) { + ret_val = true; + } + + return ret_val; +} + +/** + * @brief Set UART configuration using data from *cfg_in. + * + * @param dev UART Device struct + * @param cfg_in The input configuration. + * + * @return 0 if success, -ENOTSUP, if input from cfg_in is not configurable. + * -EINVAL if cfg_in is null pointer + */ +static int uart_intel_lw_configure(const struct device *dev, + const struct uart_config *cfg_in) +{ + const struct uart_intel_lw_device_config *config = dev->config; + struct uart_intel_lw_device_data * const data = dev->data; + struct uart_config * const cfg_stored = &data->uart_cfg; + uint32_t divisor_val; + int ret_val; + + /* generate fatal error if CONFIG_ASSERT is enabled. */ + __ASSERT(cfg_in != NULL, "cfg_in is null pointer!"); + + /* Stop, if cfg_in is null pointer */ + if (cfg_in == NULL) { + return -EINVAL; + } + + /* check if configuration is supported. */ + if (uart_intel_lw_check_configuration(cfg_stored, cfg_in) + && !(config->flags & INTEL_LW_UART_FB)) { + /* parameter is valid, just return ok if baudrate is the same. */ + if (cfg_stored->baudrate != cfg_in->baudrate) { + /* calculate and set baudrate. */ + divisor_val = (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC/cfg_in->baudrate) - 1; + sys_write32(divisor_val, config->base + INTEL_LW_UART_DIVISOR_REG_OFFSET); + + /* update stored data. */ + cfg_stored->baudrate = cfg_in->baudrate; + } + + ret_val = 0; + } else { + /* return not supported */ + ret_val = -ENOTSUP; + } + + return ret_val; +} +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ + +/** + * @brief Get UART configuration and stores in *cfg_out. + * + * @param dev UART Device struct + * @param cfg_out The output configuration. + * + * @return 0 if success. + * -EINVAL if cfg_out is null pointer + */ +static int uart_intel_lw_config_get(const struct device *dev, + struct uart_config *cfg_out) +{ + const struct uart_intel_lw_device_data *data = dev->data; + + /* generate fatal error if CONFIG_ASSERT is enabled. */ + __ASSERT(cfg_out != NULL, "cfg_out is null pointer!"); + + /* Stop, if cfg_out is null pointer */ + if (cfg_out == NULL) { + return -EINVAL; + } + + *cfg_out = data->uart_cfg; + return 0; +} + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +/** + * @brief Fill FIFO with data + * This function is expected to be called from UART interrupt handler (ISR), + * if uart_irq_tx_ready() returns true. This function does not block! + * + * @param dev UART device struct + * @param tx_data Data to transmit + * @param size Number of bytes to send + * + * @return Number of bytes sent + */ +static int uart_intel_lw_fifo_fill(const struct device *dev, + const uint8_t *tx_data, + int size) +{ + const struct uart_intel_lw_device_config *config = dev->config; + struct uart_intel_lw_device_data *data = dev->data; + int ret_val = 0; + k_spinlock_key_t key; + + /* generate fatal error if CONFIG_ASSERT is enabled. */ + __ASSERT(tx_data != NULL, "tx_data is null pointer!"); + + /* Stop, if tx_data is null pointer */ + if (tx_data == NULL) { + return 0; + } + + /* Stop, if transmit break is set */ + if (data->control_val & INTEL_LW_UART_CONTROL_TRBK_MSK) { + return 0; + } + + do { + if (data->status_act & INTEL_LW_UART_STATUS_TRDY_MSK) { + key = k_spin_lock(&data->lock); + sys_write32(tx_data[ret_val++], config->base + + INTEL_LW_UART_TXDATA_REG_OFFSET); + data->status_act = sys_read32(config->base + + INTEL_LW_UART_STATUS_REG_OFFSET); + k_spin_unlock(&data->lock, key); + } else { + /* stop because tx fifo is full! */ + break; + } + } while ((size - ret_val) > 0); + + return ret_val; +} + +/** + * @brief Read data from FIFO + * This function is expected to be called from UART interrupt handler (ISR), + * if uart_irq_rx_ready() returns true. + * + * @param dev UART device struct + * @param rx_data Data container + * @param size Container size + * + * @return Number of bytes read + */ +static int uart_intel_lw_fifo_read(const struct device *dev, uint8_t *rx_data, + const int size) +{ + const struct uart_intel_lw_device_config *config = dev->config; + struct uart_intel_lw_device_data *data = dev->data; + int ret_val = 0; + k_spinlock_key_t key; + + /* generate fatal error if CONFIG_ASSERT is enabled. */ + __ASSERT(rx_data != NULL, "rx_data is null pointer!"); + + /* Stop, if rx_data is null pointer */ + if (rx_data == NULL) { + return 0; + } + + do { + if (data->status_act & INTEL_LW_UART_STATUS_RRDY_MSK) { + key = k_spin_lock(&data->lock); + rx_data[ret_val++] = sys_read32(config->base + + INTEL_LW_UART_RXDATA_REG_OFFSET); + data->status_act = sys_read32(config->base + + INTEL_LW_UART_STATUS_REG_OFFSET); + + k_spin_unlock(&data->lock, key); + } else { + break; + } + } while ((size - ret_val) > 0); + + return ret_val; +} + +/** + * @brief Enable TX interrupt + * + * @param dev UART device struct + */ +static void uart_intel_lw_irq_tx_enable(const struct device *dev) +{ + struct uart_intel_lw_device_data *data = dev->data; + const struct uart_intel_lw_device_config *config = dev->config; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + data->control_val |= INTEL_LW_UART_CONTROL_TRDY_MSK; + +#ifdef CONFIG_UART_LINE_CTRL + /* also enable RTS, if flow control is enabled. */ + data->control_val |= INTEL_LW_UART_CONTROL_RTS_MSK; +#endif + + sys_write32(data->control_val, config->base + INTEL_LW_UART_CONTROL_REG_OFFSET); + + k_spin_unlock(&data->lock, key); +} + +/** + * @brief Disable TX interrupt + * + * @param dev UART device struct + */ +static void uart_intel_lw_irq_tx_disable(const struct device *dev) +{ + struct uart_intel_lw_device_data *data = dev->data; + const struct uart_intel_lw_device_config *config = dev->config; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + data->control_val &= ~INTEL_LW_UART_CONTROL_TRDY_MSK; + +#ifdef CONFIG_UART_LINE_CTRL + /* also disable RTS, if flow control is enabled. */ + data->control_val &= ~INTEL_LW_UART_CONTROL_RTS_MSK; +#endif + + sys_write32(data->control_val, config->base + INTEL_LW_UART_CONTROL_REG_OFFSET); + + k_spin_unlock(&data->lock, key); +} + +/** + * @brief Check if UART TX buffer can accept a new char. + * + * @param dev UART device struct + * + * @return 1 if TX interrupt is enabled and at least one char can be written to UART. + * 0 if device is not ready to write a new byte. + */ +static int uart_intel_lw_irq_tx_ready(const struct device *dev) +{ + struct uart_intel_lw_device_data *data = dev->data; + int ret_val = 0; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + /* if TX interrupt is enabled */ + if (data->control_val & INTEL_LW_UART_CONTROL_TRDY_MSK) { + /* IP core does not have fifo. Wait until tx data is completely shifted. */ + if (data->status_act & INTEL_LW_UART_STATUS_TMT_MSK) { + ret_val = 1; + } + } + +#ifdef CONFIG_UART_LINE_CTRL + /* if flow control is enabled, set tx not ready, if CTS is low. */ + if ((data->status_act & INTEL_LW_UART_STATUS_CTS_MSK) == 0) { + ret_val = 0; + } + +#endif /* CONFIG_UART_LINE_CTRL */ + + k_spin_unlock(&data->lock, key); + + return ret_val; +} + +/** + * @brief Check if nothing remains to be transmitted + * + * @param dev UART device struct + * + * @return 1 if nothing remains to be transmitted, 0 otherwise + */ +static int uart_intel_lw_irq_tx_complete(const struct device *dev) +{ + struct uart_intel_lw_device_data *data = dev->data; + int ret_val = 0; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (data->status_act & INTEL_LW_UART_STATUS_TMT_MSK) { + ret_val = 1; + } + + k_spin_unlock(&data->lock, key); + + return ret_val; +} + +/** + * @brief Enable RX interrupt in + * + * @param dev UART device struct + */ +static void uart_intel_lw_irq_rx_enable(const struct device *dev) +{ + struct uart_intel_lw_device_data *data = dev->data; + const struct uart_intel_lw_device_config *config = dev->config; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + data->control_val |= INTEL_LW_UART_CONTROL_RRDY_MSK; + sys_write32(data->control_val, config->base + INTEL_LW_UART_CONTROL_REG_OFFSET); + + k_spin_unlock(&data->lock, key); +} + +/** + * @brief Disable RX interrupt + * + * @param dev UART device struct + */ +static void uart_intel_lw_irq_rx_disable(const struct device *dev) +{ + struct uart_intel_lw_device_data *data = dev->data; + const struct uart_intel_lw_device_config *config = dev->config; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + data->control_val &= ~INTEL_LW_UART_CONTROL_RRDY_MSK; + sys_write32(data->control_val, config->base + INTEL_LW_UART_CONTROL_REG_OFFSET); + + k_spin_unlock(&data->lock, key); +} + +/** + * @brief Check if Rx IRQ has been raised + * + * @param dev UART device struct + * + * @return 1 if an IRQ is ready, 0 otherwise + */ +static int uart_intel_lw_irq_rx_ready(const struct device *dev) +{ + struct uart_intel_lw_device_data *data = dev->data; + int ret_val = 0; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + /* if RX interrupt is enabled */ + if (data->control_val & INTEL_LW_UART_CONTROL_RRDY_MSK) { + /* check for space in rx data register */ + if (data->status_act & INTEL_LW_UART_STATUS_RRDY_MSK) { + ret_val = 1; + } + } + + k_spin_unlock(&data->lock, key); + + return ret_val; +} + +/** + * @brief This function will cache the status register. + * + * @param dev UART device struct + * + * @return 1 for success. + */ +static int uart_intel_lw_irq_update(const struct device *dev) +{ + struct uart_intel_lw_device_data *data = dev->data; + const struct uart_intel_lw_device_config *config = dev->config; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + data->status_act = sys_read32(config->base + INTEL_LW_UART_STATUS_REG_OFFSET); + + k_spin_unlock(&data->lock, key); + + return 1; +} + +/** + * @brief Check if any IRQ is pending + * + * @param dev UART device struct + * + * @return 1 if an IRQ is pending, 0 otherwise + */ +static int uart_intel_lw_irq_is_pending(const struct device *dev) +{ + struct uart_intel_lw_device_data *data = dev->data; + int ret_val = 0; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (data->status_act & data->control_val & INTEL_LW_UART_PENDING_MASK) { + ret_val = 1; + } + + k_spin_unlock(&data->lock, key); + + return ret_val; +} + +/** + * @brief Set the callback function pointer for IRQ. + * + * @param dev UART device struct + * @param cb Callback function pointer. + * @param cb_data Data to pass to callback function. + */ +static void uart_intel_lw_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, + void *cb_data) +{ + struct uart_intel_lw_device_data *data = dev->data; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + +#ifdef CONFIG_UART_INTEL_LW_EOP + if (data->set_eop_cb) { + data->cb_eop = cb; + data->cb_data_eop = cb_data; + data->set_eop_cb = 0; + } else { + data->cb = cb; + data->cb_data = cb_data; + } +#else + data->cb = cb; + data->cb_data = cb_data; +#endif /* CONFIG_UART_INTEL_LW_EOP */ + + k_spin_unlock(&data->lock, key); +} + +#ifdef CONFIG_UART_LINE_CTRL +/** + * @brief DCTS Interrupt service routine. + * + * Handles assertion and deassettion of CTS/RTS stignal + * + * @param dev Pointer to UART device struct + */ +static void uart_intel_lw_dcts_isr(const struct device *dev) +{ + struct uart_intel_lw_device_data *data = dev->data; + const struct uart_intel_lw_device_config *config = dev->config; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + /* Assume that user follows zephyr requirement and update status in their call back. */ + if (data->status_act & INTEL_LW_UART_STATUS_CTS_MSK) { + + /* Assert RTS to inform other UART. */ + data->control_val |= INTEL_LW_UART_CONTROL_RTS_MSK; + sys_write32(data->control_val, config->base + + INTEL_LW_UART_CONTROL_REG_OFFSET); + } else { + /* other UART deasserts RTS */ + if (data->status_act & INTEL_LW_UART_STATUS_TMT_MSK) { + /* only deasserts if not transmitting. */ + data->control_val &= ~INTEL_LW_UART_CONTROL_RTS_MSK; + sys_write32(data->control_val, config->base + + INTEL_LW_UART_CONTROL_REG_OFFSET); + } + } + + k_spin_unlock(&data->lock, key); +} +#endif /* CONFIG_UART_LINE_CTRL */ + +/** + * @brief Interrupt service routine. + * + * This simply calls the callback function, if one exists. + * + * @param dev Pointer to UART device struct + * + */ +static void uart_intel_lw_isr(const struct device *dev) +{ + struct uart_intel_lw_device_data *data = dev->data; + const struct uart_intel_lw_device_config *config = dev->config; + + uart_irq_callback_user_data_t callback = data->cb; + + if (callback) { + callback(dev, data->cb_data); + } + + /* Post ISR */ +#if CONFIG_UART_INTEL_LW_EOP + data->status_act = sys_read32(config->base + INTEL_LW_UART_STATUS_REG_OFFSET); + if (data->status_act & INTEL_LW_UART_STATUS_EOP_MSK) { + callback = data->cb_eop; + if (callback) { + callback(dev, data->cb_data_eop); + } + } +#endif /* CONFIG_UART_INTEL_LW_EOP */ + +#ifdef CONFIG_UART_LINE_CTRL + data->status_act = sys_read32(config->base + INTEL_LW_UART_STATUS_REG_OFFSET); + /* handles RTS/CTS signal */ + if (data->status_act & INTEL_LW_UART_STATUS_DCTS_MSK) { + uart_intel_lw_dcts_isr(dev); + } +#endif + + /* clear status after all interrupts are handled. */ + sys_write32(INTEL_LW_UART_CLEAR_STATUS_VAL, config->base + + INTEL_LW_UART_STATUS_REG_OFFSET); +} + +#ifdef CONFIG_UART_DRV_CMD +/** + * @brief Send extra command to driver + * + * @param dev UART device struct + * @param cmd Command to driver + * @param p Parameter to the command + * + * @return 0 if successful, failed otherwise + */ +static int uart_intel_lw_drv_cmd(const struct device *dev, uint32_t cmd, + uint32_t p) +{ + struct uart_intel_lw_device_data *data = dev->data; + const struct uart_intel_lw_device_config *config = dev->config; + + int ret_val = -ENOTSUP; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + switch (cmd) { +#if CONFIG_UART_INTEL_LW_EOP + case CMD_ENABLE_EOP: + /* enable EOP interrupt */ + data->control_val |= INTEL_LW_UART_CONTROL_EOP_MSK; + sys_write32(data->control_val, config->base + + INTEL_LW_UART_CONTROL_REG_OFFSET); + + /* set EOP character */ + sys_write32((uint8_t) p, config->base + INTEL_LW_UART_EOP_REG_OFFSET); + + /* after this, user needs to call uart_irq_callback_set + * to set data->cb_eop and data->cb_data_eop! + */ + data->set_eop_cb = 1; + ret_val = 0; + break; + + case CMD_DISABLE_EOP: + /* disable EOP interrupt */ + data->control_val &= ~INTEL_LW_UART_CONTROL_EOP_MSK; + sys_write32(data->control_val, config->base + + INTEL_LW_UART_CONTROL_REG_OFFSET); + + /* clear call back */ + data->cb_eop = NULL; + data->cb_data_eop = NULL; + ret_val = 0; + break; +#endif /* CONFIG_UART_INTEL_LW_EOP */ + + case CMD_TRBK_EN: + /* enable transmit break */ + data->control_val |= INTEL_LW_UART_CONTROL_TRBK_MSK; + sys_write32(data->control_val, config->base + + INTEL_LW_UART_CONTROL_REG_OFFSET); + ret_val = 0; + break; + + case CMD_TRBK_DIS: + /* disable transmit break */ + data->control_val &= ~INTEL_LW_UART_CONTROL_TRBK_MSK; + sys_write32(data->control_val, config->base + + INTEL_LW_UART_CONTROL_REG_OFFSET); + ret_val = 0; + break; + + case CMD_POLL_ASSERT_RTS: + /* assert RTS */ + data->control_val |= INTEL_LW_UART_CONTROL_RTS_MSK; + sys_write32(data->control_val, config->base + + INTEL_LW_UART_CONTROL_REG_OFFSET); + ret_val = 0; + break; + + case CMD_POLL_DEASSERT_RTS: + /* deassert RTS */ + data->control_val &= ~INTEL_LW_UART_CONTROL_RTS_MSK; + sys_write32(data->control_val, config->base + + INTEL_LW_UART_CONTROL_REG_OFFSET); + ret_val = 0; + break; + + default: + ret_val = -ENOTSUP; + break; + }; + + k_spin_unlock(&data->lock, key); + + return ret_val; +} + +#endif /* CONFIG_UART_DRV_CMD */ + +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +static const struct uart_driver_api uart_intel_lw_driver_api = { + .poll_in = uart_intel_lw_poll_in, + .poll_out = uart_intel_lw_poll_out, + .err_check = uart_intel_lw_err_check, +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE + .configure = uart_intel_lw_configure, +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ + .config_get = uart_intel_lw_config_get, + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = uart_intel_lw_fifo_fill, + .fifo_read = uart_intel_lw_fifo_read, + .irq_tx_enable = uart_intel_lw_irq_tx_enable, + .irq_tx_disable = uart_intel_lw_irq_tx_disable, + .irq_tx_ready = uart_intel_lw_irq_tx_ready, + .irq_tx_complete = uart_intel_lw_irq_tx_complete, + .irq_rx_enable = uart_intel_lw_irq_rx_enable, + .irq_rx_disable = uart_intel_lw_irq_rx_disable, + .irq_rx_ready = uart_intel_lw_irq_rx_ready, + .irq_is_pending = uart_intel_lw_irq_is_pending, + .irq_update = uart_intel_lw_irq_update, + .irq_callback_set = uart_intel_lw_irq_callback_set, +#endif + +#ifdef CONFIG_UART_DRV_CMD + .drv_cmd = uart_intel_lw_drv_cmd, +#endif +}; + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + +#define UART_INTEL_LW_IRQ_CONFIG_FUNC(n) \ + static void uart_intel_lw_irq_config_func_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + uart_intel_lw_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + } + +#define UART_INTEL_LW_IRQ_CONFIG_INIT(n) \ + .irq_config_func = uart_intel_lw_irq_config_func_##n, \ + .irq_num = DT_INST_IRQN(n), + +#else + +#define UART_INTEL_LW_IRQ_CONFIG_FUNC(n) +#define UART_INTEL_LW_IRQ_CONFIG_INIT(n) + +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +#define UART_INTEL_LW_DEVICE_INIT(n) \ +UART_INTEL_LW_IRQ_CONFIG_FUNC(n) \ +static struct uart_intel_lw_device_data uart_intel_lw_dev_data_##n = { \ + .uart_cfg = \ + { \ + .baudrate = DT_INST_PROP(n, current_speed), \ + .parity = DT_INST_ENUM_IDX_OR(n, parity, \ + UART_CFG_PARITY_NONE), \ + .stop_bits = DT_INST_ENUM_IDX_OR(n, stop_bits, \ + UART_CFG_STOP_BITS_1), \ + .data_bits = DT_INST_ENUM_IDX_OR(n, data_bits, \ + UART_CFG_DATA_BITS_8), \ + .flow_ctrl = DT_INST_PROP(n, hw_flow_control) ? \ + UART_CFG_FLOW_CTRL_RTS_CTS : \ + UART_CFG_FLOW_CTRL_NONE, \ + }, \ +}; \ + \ +static const struct uart_intel_lw_device_config uart_intel_lw_dev_cfg_##n = { \ + .base = DT_INST_REG_ADDR(n), \ + .flags = ((DT_INST_PROP(n, fixed_baudrate)?INTEL_LW_UART_FB:0) \ + |(DT_INST_PROP(n, hw_flow_control)?INTEL_LW_UART_FC:0)),\ + UART_INTEL_LW_IRQ_CONFIG_INIT(n) \ +}; \ + \ +DEVICE_DT_INST_DEFINE(n, \ + uart_intel_lw_init, \ + NULL, \ + &uart_intel_lw_dev_data_##n, \ + &uart_intel_lw_dev_cfg_##n, \ + PRE_KERNEL_1, \ + CONFIG_SERIAL_INIT_PRIORITY, \ + &uart_intel_lw_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(UART_INTEL_LW_DEVICE_INIT) diff --git a/drivers/serial/uart_liteuart.c b/drivers/serial/uart_liteuart.c index 073d565770efe93..fe5e2580d088048 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) @@ -273,8 +275,8 @@ static void liteuart_uart_irq_handler(const struct device *dev) data->callback(dev, data->cb_data); } - /* clear events */ - litex_write8(UART_EV_TX | UART_EV_RX, UART_EV_PENDING_ADDR); + /* Clear RX events, TX events still needed to enqueue the next transfer */ + litex_write8(UART_EV_RX, UART_EV_PENDING_ADDR); irq_unlock(key); } diff --git a/drivers/serial/uart_mchp_xec.c b/drivers/serial/uart_mchp_xec.c index 12143a2d20b58d0..603a00656adec60 100644 --- a/drivers/serial/uart_mchp_xec.c +++ b/drivers/serial/uart_mchp_xec.c @@ -219,7 +219,7 @@ struct uart_xec_dev_data { static const struct uart_driver_api uart_xec_driver_api; -#ifdef CONFIG_PM_DEVICE +#if defined(CONFIG_PM_DEVICE) && defined(CONFIG_UART_CONSOLE_INPUT_EXPIRED) static void uart_xec_pm_policy_state_lock_get(enum uart_xec_pm_policy_state_flag flag) { if (atomic_test_and_set_bit(pm_policy_state_flag, flag) == 0) { @@ -644,7 +644,7 @@ static int uart_xec_fifo_fill(const struct device *dev, const uint8_t *tx_data, k_spinlock_key_t key = k_spin_lock(&dev_data->lock); for (i = 0; (i < size) && (regs->LSR & LSR_THRE) != 0; i++) { -#ifdef CONFIG_PM_DEVICE +#if defined(CONFIG_PM_DEVICE) && defined(CONFIG_UART_CONSOLE_INPUT_EXPIRED) uart_xec_pm_policy_state_lock_get(UART_XEC_PM_POLICY_STATE_TX_FLAG); #endif regs->RTXB = tx_data[i]; @@ -933,7 +933,7 @@ static void uart_xec_isr(const struct device *dev) dev_data->cb(dev, dev_data->cb_data); } -#ifdef CONFIG_PM_DEVICE +#if defined(CONFIG_PM_DEVICE) && defined(CONFIG_UART_CONSOLE_INPUT_EXPIRED) if (uart_xec_irq_tx_complete(dev)) { uart_xec_pm_policy_state_lock_put(UART_XEC_PM_POLICY_STATE_TX_FLAG); } diff --git a/drivers/serial/uart_mcux_lpuart.c b/drivers/serial/uart_mcux_lpuart.c index e46d8d7360774fd..3c2f318f90eebc5 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 24dbf3af370a0e6..bf35b4cf6563dec 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 51348423cc98754..7c44ccf68cc827f 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 22f2b0e539fab73..5f6de6e0cbe218f 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 547d1f46efb4260..5c14b18060e4b67 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 017efa6a2e563bc..099a4f55937f40d 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -65,6 +65,16 @@ LOG_MODULE_REGISTER(uart_nrfx_uarte, CONFIG_UART_LOG_LEVEL); #define UARTE_ANY_ASYNC 1 #endif +#if defined(CONFIG_UART_0_NRF_HW_ASYNC) || defined(CONFIG_UART_1_NRF_HW_ASYNC) || \ + defined(CONFIG_UART_2_NRF_HW_ASYNC) || defined(CONFIG_UART_3_NRF_HW_ASYNC) +#define UARTE_HW_ASYNC 1 +#endif + +#if defined(CONFIG_UART_0_ENHANCED_POLL_OUT) || defined(CONFIG_UART_1_ENHANCED_POLL_OUT) || \ + defined(CONFIG_UART_2_ENHANCED_POLL_OUT) || defined(CONFIG_UART_3_ENHANCED_POLL_OUT) +#define UARTE_ENHANCED_POLL_OUT 1 +#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. @@ -205,7 +215,7 @@ static void endtx_isr(const struct device *dev) * * @param arg Argument to ISR. */ -static void uarte_nrfx_isr_int(void *arg) +static void uarte_nrfx_isr_int(const void *arg) { const struct device *dev = arg; const struct uarte_nrfx_config *config = dev->config; @@ -474,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(); @@ -498,7 +512,7 @@ static int wait_tx_ready(const struct device *dev) * where static inline fails on linking. */ #define HW_RX_COUNTING_ENABLED(data) \ - (IS_ENABLED(CONFIG_UARTE_NRF_HW_ASYNC) ? data->async->hw_rx_counting : false) + (IS_ENABLED(UARTE_HW_ASYNC) ? data->async->hw_rx_counting : false) #endif /* UARTE_ANY_ASYNC */ @@ -844,15 +858,7 @@ static int uarte_nrfx_rx_enable(const struct device *dev, uint8_t *buf, } data->async->rx_timeout = timeout; - /* Set minimum interval to 3 RTC ticks. 3 is used due to RTC limitation - * which cannot set timeout for next tick. Assuming delay in processing - * 3 instead of 2 is used. Note that lower value would work in a similar - * way but timeouts would always occur later than expected, most likely - * after ~3 ticks. - */ - data->async->rx_timeout_slab = - MAX(timeout / RX_TIMEOUT_DIV, - NRFX_CEIL_DIV(3 * 1000000, CONFIG_SYS_CLOCK_TICKS_PER_SEC)); + data->async->rx_timeout_slab = timeout / RX_TIMEOUT_DIV; data->async->rx_buf = buf; data->async->rx_buf_len = len; @@ -1376,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; @@ -1499,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); @@ -1743,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; @@ -1753,7 +1766,7 @@ static int uarte_instance_init(const struct device *dev, return err; } - if (IS_ENABLED(CONFIG_UART_ENHANCED_POLL_OUT) && + if (IS_ENABLED(UARTE_ENHANCED_POLL_OUT) && cfg->flags & UARTE_CFG_FLAG_PPI_ENDTX) { err = endtx_stoptx_ppi_init(uarte, data); if (err < 0) { @@ -1916,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); @@ -1981,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 000000000000000..65bfeccdafdb725 --- /dev/null +++ b/drivers/serial/uart_nrfx_uarte2.c @@ -0,0 +1,1037 @@ +/* + * 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 +#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 c3f74b30dd5a901..bf07240c0cef522 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,8 +257,72 @@ 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 +/* Register definitions (ITE_IT8XXX2) */ +#define REG_ECSPMR 0x08 /* EC Serial port mode reg */ + +/* Fields for ITE IT8XXX2 UART module */ +#define ECSPMR_ECHS 0x02 /* EC high speed select */ + +/* IT8XXX2 UART high speed baud rate settings */ +#define UART_BAUDRATE_115200 115200 +#define UART_BAUDRATE_230400 230400 +#define UART_BAUDRATE_460800 460800 +#define IT8XXX2_230400_DIVISOR 32770 +#define IT8XXX2_460800_DIVISOR 32769 + +#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 { @@ -292,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, @@ -341,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) { @@ -395,6 +482,50 @@ static inline uintptr_t get_port(const struct device *dev) return port; } +static uint32_t get_uart_burdrate_divisor(const struct device *dev, + uint32_t baud_rate, + uint32_t pclk) +{ + ARG_UNUSED(dev); + /* + * calculate baud rate divisor. a variant of + * (uint32_t)(pclk / (16.0 * baud_rate) + 0.5) + */ + return ((pclk + (baud_rate << 3)) / baud_rate) >> 4; +} + +#ifdef CONFIG_UART_NS16550_ITE_HIGH_SPEED_BUADRATE +static uint32_t get_ite_uart_burdrate_divisor(const struct device *dev, + uint32_t baud_rate, + uint32_t pclk) +{ + const struct uart_ns16550_device_config * const dev_cfg = dev->config; + uint32_t divisor = 0; + + if (baud_rate > UART_BAUDRATE_115200) { + /* Baud rate divisor for high speed */ + if (baud_rate == UART_BAUDRATE_230400) { + divisor = IT8XXX2_230400_DIVISOR; + } else if (baud_rate == UART_BAUDRATE_460800) { + divisor = IT8XXX2_460800_DIVISOR; + } + /* + * This bit indicates that the supported baud rate of + * UART1/UART2 can be up to 230.4k and 460.8k. + * Other bits are reserved and have no setting, so we + * directly write the ECSPMR register. + */ + ns16550_outbyte(dev_cfg, ECSPMR(dev), ECSPMR_ECHS); + } else { + divisor = get_uart_burdrate_divisor(dev, baud_rate, pclk); + /* Set ECSPMR register as default */ + ns16550_outbyte(dev_cfg, ECSPMR(dev), 0); + } + + return divisor; +} +#endif + static void set_baud_rate(const struct device *dev, uint32_t baud_rate, uint32_t pclk) { struct uart_ns16550_dev_data * const dev_data = dev->data; @@ -403,13 +534,11 @@ static void set_baud_rate(const struct device *dev, uint32_t baud_rate, uint32_t uint8_t lcr_cache; if ((baud_rate != 0U) && (pclk != 0U)) { - /* - * calculate baud rate divisor. a variant of - * (uint32_t)(pclk / (16.0 * baud_rate) + 0.5) - */ - divisor = ((pclk + (baud_rate << 3)) - / baud_rate) >> 4; - +#ifdef CONFIG_UART_NS16550_ITE_HIGH_SPEED_BUADRATE + divisor = get_ite_uart_burdrate_divisor(dev, baud_rate, pclk); +#else + divisor = get_uart_burdrate_divisor(dev, baud_rate, pclk); +#endif /* set the DLAB to access the baud rate divisor registers */ lcr_cache = ns16550_inbyte(dev_cfg, LCR(dev)); ns16550_outbyte(dev_cfg, LCR(dev), LCR_DLAB | lcr_cache); @@ -630,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 * @@ -670,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) */ { @@ -682,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; @@ -1096,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; @@ -1198,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, @@ -1226,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 @@ -1297,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), \ @@ -1312,8 +1925,8 @@ static const struct uart_driver_api uart_ns16550_driver_api = { IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pcp), \ (.pcp = DT_INST_PROP_OR(n, pcp, 0),)) \ .reg_interval = (1 << DT_INST_PROP(n, reg_shift)), \ - IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \ - (.pincfg = PINCTRL_DT_DEV_CONFIG_GET(DT_DRV_INST(n)),)) \ + IF_ENABLED(CONFIG_PINCTRL, \ + (.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),)) \ IF_ENABLED(DT_INST_NODE_HAS_PROP(n, resets), \ (.reset_spec = RESET_DT_SPEC_INST_GET(n),)) @@ -1327,12 +1940,12 @@ 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); \ - IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \ - (PINCTRL_DT_INST_DEFINE(n))); \ + IF_ENABLED(CONFIG_PINCTRL, (PINCTRL_DT_INST_DEFINE(n))); \ static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_##n = { \ COND_CODE_1(DT_INST_PROP_OR(n, io_mapped, 0), \ (.port = DT_INST_REG_ADDR(n),), \ @@ -1354,8 +1967,7 @@ static const struct uart_driver_api uart_ns16550_driver_api = { #define UART_NS16550_DEVICE_PCIE_INIT(n) \ UART_NS16550_PCIE_IRQ_FUNC_DECLARE(n); \ DEVICE_PCIE_INST_DECLARE(n); \ - IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \ - (PINCTRL_DT_INST_DEFINE(n))); \ + IF_ENABLED(CONFIG_PINCTRL, (PINCTRL_DT_INST_DEFINE(n))); \ static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_##n = { \ UART_NS16550_COMMON_DEV_CFG_INITIALIZER(n) \ DEV_CONFIG_PCIE_IRQ_FUNC_INIT(n) \ @@ -1366,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_nxp_s32_linflexd.c b/drivers/serial/uart_nxp_s32_linflexd.c index fe1c6c51f8659c8..4fa6badb7963363 100644 --- a/drivers/serial/uart_nxp_s32_linflexd.c +++ b/drivers/serial/uart_nxp_s32_linflexd.c @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_linflexd + +#include #include #include #include @@ -243,45 +246,54 @@ static void uart_nxp_s32_irq_callback_set(const struct device *dev, data->cb_data = cb_data; } -/** - * @brief Interrupt service routine. - * - * This simply calls the callback function, if one exists. - * - * Note: s32 UART Tx interrupts when ready to send; Rx interrupts when char - * received. - * - * @param arg Argument to ISR. - * - * @return N/A - */ - void uart_nxp_s32_isr(const struct device *dev) { + const struct uart_nxp_s32_config *config = dev->config; + + Linflexd_Uart_Ip_IRQHandler(config->instance); +} + +static void uart_nxp_s32_event_handler(const uint8 instance, + Linflexd_Uart_Ip_EventType event, + void *user_data) +{ + const struct device *dev = (const struct device *)user_data; + const struct uart_nxp_s32_config *config = dev->config; struct uart_nxp_s32_data *data = dev->data; + struct uart_nxp_s32_int *int_data = &(data->int_data); + Linflexd_Uart_Ip_StatusType status; - if (data->callback) { - data->callback(dev, data->cb_data); + if (event == LINFLEXD_UART_IP_EVENT_END_TRANSFER) { + /* + * Check the previous UART transmit has finished + * because Rx may also trigger this event + */ + status = Linflexd_Uart_Ip_GetTransmitStatus(config->instance, NULL); + if (status != LINFLEXD_UART_IP_STATUS_BUSY) { + int_data->tx_fifo_busy = false; + if (data->callback) { + data->callback(dev, data->cb_data); + } + } + } else if (event == LINFLEXD_UART_IP_EVENT_RX_FULL) { + int_data->rx_fifo_busy = false; + if (data->callback) { + data->callback(dev, data->cb_data); + } + } else if (event == LINFLEXD_UART_IP_EVENT_ERROR) { + if (data->callback) { + data->callback(dev, data->cb_data); + } + } else { + /* Other events are not used */ } } + #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ -/** - * @brief Initialize UART channel - * - * This routine is called to reset the chip in a quiescent state. - * It is assumed that this function is called only once per UART. - * - * @param dev UART device struct - * - * @return 0 - */ static int uart_nxp_s32_init(const struct device *dev) { const struct uart_nxp_s32_config *config = dev->config; - struct uart_nxp_s32_data *data = dev->data; - static uint8_t state_idx; - uint8_t key; int err; err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); @@ -289,24 +301,7 @@ static int uart_nxp_s32_init(const struct device *dev) return err; } - key = irq_lock(); - - /* Initialize UART with default configuration */ - data->hw_cfg.BaudRate = 115200; - data->hw_cfg.BaudRateMantissa = 26U; - data->hw_cfg.BaudRateFractionalDivisor = 1U; - data->hw_cfg.ParityCheck = false; - data->hw_cfg.ParityType = LINFLEXD_UART_IP_PARITY_EVEN; - data->hw_cfg.StopBitsCount = LINFLEXD_UART_IP_ONE_STOP_BIT; - data->hw_cfg.WordLength = LINFLEXD_UART_IP_8_BITS; - data->hw_cfg.TransferType = LINFLEXD_UART_IP_USING_INTERRUPTS; - data->hw_cfg.Callback = s32_uart_callback; - data->hw_cfg.CallbackParam = NULL; - data->hw_cfg.StateStruct = &Linflexd_Uart_Ip_apStateStructure[state_idx++]; - - Linflexd_Uart_Ip_Init(config->instance, &data->hw_cfg); - - irq_unlock(key); + Linflexd_Uart_Ip_Init(config->instance, &config->hw_cfg); return 0; } @@ -334,207 +329,63 @@ static const struct uart_driver_api uart_nxp_s32_driver_api = { }; -#define UART_NXP_S32_NODE(n) DT_NODELABEL(uart##n) - -#if defined(CONFIG_UART_INTERRUPT_DRIVEN) -#define UART_NXP_S32_INTERRUPT_DEFINE(n, isr_handler, parameter) \ - do { \ - IRQ_CONNECT(DT_IRQN(UART_NXP_S32_NODE(n)), \ - DT_IRQ(UART_NXP_S32_NODE(n), priority), \ - isr_handler, \ - parameter, \ - DT_IRQ(UART_NXP_S32_NODE(n), flags)); \ - \ - irq_enable(DT_IRQN(UART_NXP_S32_NODE(n))); \ +#define UART_NXP_S32_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_LINFLEX_##i##_BASE) ? i : 0) + +#define UART_NXP_S32_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET LINFLEXD_INSTANCE_COUNT, UART_NXP_S32_HW_INSTANCE_CHECK, (|), n) + +#define UART_NXP_S32_INTERRUPT_DEFINE(n) \ + do { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ + uart_nxp_s32_isr, DEVICE_DT_INST_GET(n), \ + DT_INST_IRQ(n, flags)); \ + irq_enable(DT_INST_IRQN(n)); \ } while (0) -#else -#define UART_NXP_S32_INTERRUPT_DEFINE(n, isr_handler, parameter) -#endif +#define UART_NXP_S32_HW_CONFIG(n) \ + { \ + .BaudRate = 115200, \ + .BaudRateMantissa = 26U, \ + .BaudRateDivisor = 16U, \ + .BaudRateFractionalDivisor = 1U, \ + .ParityCheck = false, \ + .ParityType = LINFLEXD_UART_IP_PARITY_EVEN, \ + .StopBitsCount = LINFLEXD_UART_IP_ONE_STOP_BIT, \ + .WordLength = LINFLEXD_UART_IP_8_BITS, \ + .TransferType = LINFLEXD_UART_IP_USING_INTERRUPTS, \ + .StateStruct = &Linflexd_Uart_Ip_apStateStructure[n], \ + IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, ( \ + .Callback = uart_nxp_s32_event_handler, \ + .CallbackParam = (void *)DEVICE_DT_INST_GET(n), \ + )) \ + } #define UART_NXP_S32_INIT_DEVICE(n) \ - PINCTRL_DT_DEFINE(UART_NXP_S32_NODE(n)); \ - static struct uart_nxp_s32_data uart_nxp_s32_data_##n; \ + PINCTRL_DT_INST_DEFINE(n); \ + IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, \ + (static struct uart_nxp_s32_data uart_nxp_s32_data_##n;)) \ static const struct uart_nxp_s32_config uart_nxp_s32_config_##n = { \ - .instance = n, \ - .base = (LINFLEXD_Type *)DT_REG_ADDR(UART_NXP_S32_NODE(n)), \ - .pincfg = PINCTRL_DT_DEV_CONFIG_GET(UART_NXP_S32_NODE(n)), \ + .instance = UART_NXP_S32_HW_INSTANCE(n), \ + .base = (LINFLEXD_Type *)DT_INST_REG_ADDR(n), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .hw_cfg = UART_NXP_S32_HW_CONFIG(n), \ }; \ static int uart_nxp_s32_init_##n(const struct device *dev) \ { \ - UART_NXP_S32_INTERRUPT_DEFINE(n, Linflexd_Uart_Ip_IRQHandler, n);\ + IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, \ + (UART_NXP_S32_INTERRUPT_DEFINE(n);)) \ \ return uart_nxp_s32_init(dev); \ } \ - DEVICE_DT_DEFINE(UART_NXP_S32_NODE(n), \ + DEVICE_DT_INST_DEFINE(n, \ &uart_nxp_s32_init_##n, \ NULL, \ - &uart_nxp_s32_data_##n, \ + COND_CODE_1(CONFIG_UART_INTERRUPT_DRIVEN, \ + (&uart_nxp_s32_data_##n), (NULL)), \ &uart_nxp_s32_config_##n, \ PRE_KERNEL_1, \ CONFIG_SERIAL_INIT_PRIORITY, \ &uart_nxp_s32_driver_api); -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(0), okay) -UART_NXP_S32_INIT_DEVICE(0) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(1), okay) -UART_NXP_S32_INIT_DEVICE(1) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(2), okay) -UART_NXP_S32_INIT_DEVICE(2) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(3), okay) -UART_NXP_S32_INIT_DEVICE(3) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(4), okay) -UART_NXP_S32_INIT_DEVICE(4) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(5), okay) -UART_NXP_S32_INIT_DEVICE(5) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(6), okay) -UART_NXP_S32_INIT_DEVICE(6) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(7), okay) -UART_NXP_S32_INIT_DEVICE(7) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(8), okay) -UART_NXP_S32_INIT_DEVICE(8) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(9), okay) -UART_NXP_S32_INIT_DEVICE(9) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(10), okay) -UART_NXP_S32_INIT_DEVICE(10) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(11), okay) -UART_NXP_S32_INIT_DEVICE(11) -#endif - -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(12), okay) -UART_NXP_S32_INIT_DEVICE(12) -#endif - -#ifdef CONFIG_UART_INTERRUPT_DRIVEN -static void s32_uart_device_event(const struct device *dev, Linflexd_Uart_Ip_EventType event, - void *user_data) -{ - const struct uart_nxp_s32_config *config = dev->config; - struct uart_nxp_s32_data *data = dev->data; - struct uart_nxp_s32_int *int_data = &(data->int_data); - Linflexd_Uart_Ip_StatusType status; - - ARG_UNUSED(user_data); - - if (event == LINFLEXD_UART_IP_EVENT_END_TRANSFER) { - /* - * Check the previous UART transmit has finished - * because Rx may also trigger this event - */ - status = Linflexd_Uart_Ip_GetTransmitStatus(config->instance, NULL); - if (status != LINFLEXD_UART_IP_STATUS_BUSY) { - int_data->tx_fifo_busy = false; - uart_nxp_s32_isr(dev); - } - } else if (event == LINFLEXD_UART_IP_EVENT_RX_FULL) { - int_data->rx_fifo_busy = false; - uart_nxp_s32_isr(dev); - } else if (event == LINFLEXD_UART_IP_EVENT_ERROR) { - uart_nxp_s32_isr(dev); - } else { - /* Other events are not used */ - } -} - -void s32_uart_callback(const uint8 instance, Linflexd_Uart_Ip_EventType event, void *user_data) -{ - const struct device *dev; - - switch (instance) { -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(0), okay) - case 0: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(0)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(1), okay) - case 1: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(1)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(2), okay) - case 2: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(2)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(3), okay) - case 3: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(3)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(4), okay) - case 4: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(4)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(5), okay) - case 5: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(5)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(6), okay) - case 6: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(6)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(7), okay) - case 7: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(7)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(8), okay) - case 8: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(8)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(9), okay) - case 9: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(9)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(10), okay) - case 10: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(10)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(11), okay) - case 11: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(11)); - break; -#endif -#if DT_NODE_HAS_STATUS(UART_NXP_S32_NODE(12), okay) - case 12: - dev = DEVICE_DT_GET(UART_NXP_S32_NODE(12)); - break; -#endif - default: - dev = NULL; - break; - } - - if (dev != NULL) { - s32_uart_device_event(dev, event, user_data); - } -} -#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +DT_INST_FOREACH_STATUS_OKAY(UART_NXP_S32_INIT_DEVICE) diff --git a/drivers/serial/uart_nxp_s32_linflexd.h b/drivers/serial/uart_nxp_s32_linflexd.h index ce5180c26c190f2..997cd1e9112cfdb 100644 --- a/drivers/serial/uart_nxp_s32_linflexd.h +++ b/drivers/serial/uart_nxp_s32_linflexd.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 NXP + * Copyright 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,7 @@ struct uart_nxp_s32_config { uint32_t instance; LINFLEXD_Type *base; const struct pinctrl_dev_config *pincfg; + Linflexd_Uart_Ip_UserConfigType hw_cfg; }; #ifdef CONFIG_UART_INTERRUPT_DRIVEN @@ -23,16 +24,13 @@ struct uart_nxp_s32_int { }; #endif -struct uart_nxp_s32_data { - Linflexd_Uart_Ip_UserConfigType hw_cfg; - #ifdef CONFIG_UART_INTERRUPT_DRIVEN +struct uart_nxp_s32_data { struct uart_nxp_s32_int int_data; uart_irq_callback_user_data_t callback; void *cb_data; -#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ - }; +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ extern Linflexd_Uart_Ip_StateStructureType Linflexd_Uart_Ip_apStateStructure[LINFLEXD_UART_IP_NUMBER_OF_INSTANCES]; diff --git a/drivers/serial/uart_opentitan.c b/drivers/serial/uart_opentitan.c index a762d75dac0c416..0d27c7a3d04107f 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 2223cbed5773f92..470e0e35a9530b0 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 c4397ff6d85025e..47899d2ebb8df0b 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_rcar.c b/drivers/serial/uart_rcar.c index b8011244a4694c8..081d2d489590755 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 000000000000000..f9c1607bfca9746 --- /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_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 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 9eb820d6224f3da..a423c94cc9c58a2 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 new file mode 100644 index 000000000000000..0e40ff787122d0f --- /dev/null +++ b/drivers/serial/uart_rzt2m.c @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "uart_rzt2m.h" +#include "zephyr/spinlock.h" +#include "zephyr/sys/printk.h" +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT renesas_rzt2m_uart + +LOG_MODULE_REGISTER(uart_renesas_rzt2m, CONFIG_UART_LOG_LEVEL); + +struct rzt2m_device_config { + mm_reg_t base; + const struct pinctrl_dev_config *pin_config; + uart_irq_config_func_t irq_config_func; +}; + +struct rzt2m_device_data { + struct uart_config uart_cfg; + struct k_spinlock lock; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_user_data_t callback; + void *callback_data; +#endif +}; + +static int rzt2m_poll_in(const struct device *dev, unsigned char *c) +{ + if (!dev || !dev->config || !dev->data) { + return -ENODEV; + } + + const struct rzt2m_device_config *config = dev->config; + struct rzt2m_device_data *data = dev->data; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (FRSR_R(*FRSR(config->base)) == 0) { + k_spin_unlock(&data->lock, key); + return -1; + } + *c = *RDR(config->base) & RDR_MASK_RDAT; + *CFCLR(config->base) |= CFCLR_MASK_RDRFC; + + if (FRSR_R(*FRSR(config->base)) == 0) { + *FFCLR(config->base) |= FFCLR_MASK_DRC; + } + + k_spin_unlock(&data->lock, key); + return 0; +} + +static void rzt2m_poll_out(const struct device *dev, unsigned char c) +{ + if (!dev || !dev->config || !dev->data) { + return; + } + + const struct rzt2m_device_config *config = dev->config; + struct rzt2m_device_data *data = dev->data; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + int fifo_count = FTSR_T(*FTSR(config->base)); + + while (fifo_count == MAX_FIFO_DEPTH) { + fifo_count = FTSR_T(*FTSR(config->base)); + } + + *TDR(config->base) = c; + + /* Clear `Transmit data empty flag`. */ + *CFCLR(config->base) |= CFCLR_MASK_TDREC; + + k_spin_unlock(&data->lock, key); +} + +static int rzt2m_err_check(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + + uint32_t status = *CSR(config->base); + uint32_t retval = 0; + + if (status & CSR_MASK_ORER) { + retval |= UART_ERROR_OVERRUN; + } + if (status & CSR_MASK_FER) { + retval |= UART_ERROR_FRAMING; + } + if (status & CSR_MASK_PER) { + retval |= UART_ERROR_PARITY; + } + + return retval; +} + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +static int uart_rzt2m_irq_tx_ready(const struct device *dev); + +static int rzt2m_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size) +{ + struct rzt2m_device_data *data = dev->data; + const struct rzt2m_device_config *config = dev->config; + int num_tx = 0; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + while ((size - num_tx > 0) && uart_rzt2m_irq_tx_ready(dev)) { + *TDR(config->base) = (uint8_t)tx_data[num_tx++]; + } + + k_spin_unlock(&data->lock, key); + return num_tx; +} + +static int rzt2m_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) +{ + struct rzt2m_device_data *data = dev->data; + const struct rzt2m_device_config *config = dev->config; + int num_rx = 0; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + while (num_rx < size && (FRSR_R(*FRSR(config->base)))) { + rx_data[num_rx++] = *RDR(config->base); + } + *CFCLR(config->base) = CFCLR_MASK_RDRFC; + *FFCLR(config->base) = FFCLR_MASK_DRC; + k_spin_unlock(&data->lock, key); + return num_rx; +} + +static void uart_rzt2m_irq_rx_enable(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + *CCR0(config->base) |= CCR0_MASK_RIE | CCR0_MASK_RE; +} + +static void uart_rzt2m_irq_rx_disable(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + *CCR0(config->base) &= ~CCR0_MASK_RIE; +} + +static void uart_rzt2m_irq_tx_enable(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + /* These bits must be set simultaneously. */ + *CCR0(config->base) |= CCR0_MASK_TE | CCR0_MASK_TIE | CCR0_MASK_TEIE; +} + +static void uart_rzt2m_irq_tx_disable(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + *CCR0(config->base) &= ~(CCR0_MASK_TIE | CCR0_MASK_TEIE); +} + +static int uart_rzt2m_irq_tx_ready(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + + if (FTSR_T(*FTSR(config->base)) == MAX_FIFO_DEPTH || + ((*CCR0(config->base) & CCR0_MASK_TIE) == 0)) { + return 0; + } + + return 1; +} + +static int uart_rzt2m_irq_rx_ready(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + + if (FRSR_R(*FRSR(config->base))) { + return 1; + } + + return 0; +} + +static int uart_rzt2m_irq_is_pending(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + + if ((*CSR(config->base) & (CSR_MASK_RDRF)) || (*FRSR(config->base) & FRSR_MASK_DR)) { + return 1; + } + return 0; +} + +static void uart_rzt2m_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb, + void *cb_data) +{ + struct rzt2m_device_data *data = dev->data; + + data->callback = cb; + data->callback_data = cb_data; +} + +static int uart_rzt2m_irq_update(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + + *CFCLR(config->base) = CFCLR_MASK_RDRFC; + *FFCLR(config->base) = FFCLR_MASK_DRC; + return 1; +} +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +static const struct uart_driver_api rzt2m_uart_api = { + .poll_in = rzt2m_poll_in, + .poll_out = rzt2m_poll_out, + .err_check = rzt2m_err_check, +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = rzt2m_fifo_fill, + .fifo_read = rzt2m_fifo_read, + .irq_rx_enable = uart_rzt2m_irq_rx_enable, + .irq_rx_disable = uart_rzt2m_irq_rx_disable, + .irq_tx_enable = uart_rzt2m_irq_tx_enable, + .irq_tx_disable = uart_rzt2m_irq_tx_disable, + .irq_tx_ready = uart_rzt2m_irq_tx_ready, + .irq_rx_ready = uart_rzt2m_irq_rx_ready, + .irq_is_pending = uart_rzt2m_irq_is_pending, + .irq_callback_set = uart_rzt2m_irq_callback_set, + .irq_update = uart_rzt2m_irq_update, +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +}; + +static int rzt2m_module_start(const struct device *dev) +{ + if (!dev || !dev->config || !dev->data) { + return -ENODEV; + } + + const struct rzt2m_device_config *config = dev->config; + struct rzt2m_device_data *data = dev->data; + int interface_id = BASE_TO_IFACE_ID(config->base); + unsigned int irqkey = irq_lock(); + volatile uint32_t dummy; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (interface_id < 5) { + /* Dummy-read at least one time as stated in 8.3.1 of the User's Manual: Hardware */ + *MSTPCRA &= ~(MSTPCRA_MASK_SCIx(interface_id)); + dummy = *MSTPCRA; + } else { + LOG_ERR("SCI modules in the secure domain on RZT2M are not supported."); + return -ENOTSUP; + } + + /* Dummy-read at least five times as stated in 8.3.1 of the User's Manual: Hardware */ + dummy = *RDR(config->base); + dummy = *RDR(config->base); + dummy = *RDR(config->base); + dummy = *RDR(config->base); + dummy = *RDR(config->base); + + k_spin_unlock(&data->lock, key); + irq_unlock(irqkey); + return 0; +} + +static int rzt2m_uart_init(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; + struct rzt2m_device_data *data = dev->data; + uint32_t baud_setting = 0; + uint32_t baud_settings[] = {CCR2_BAUD_SETTING_9600, CCR2_BAUD_SETTING_115200}; + + rzt2m_unlock_prcrs(PRCRS_GPIO); + rzt2m_unlock_prcrn(PRCRN_PRC1 | PRCRN_PRC2); + + /* The module needs to be started + * to allow any operation on the registers of Serial Communications Interface. + */ + int ret = rzt2m_module_start(dev); + + if (ret) { + return ret; + } + + /* Disable transmitter, receiver, interrupts. */ + *CCR0(config->base) = CCR0_DEFAULT_VALUE; + while (*CCR0(config->base) & (CCR0_MASK_RE | CCR0_MASK_TE)) { + } + + *CCR1(config->base) = CCR1_DEFAULT_VALUE; + *CCR2(config->base) = CCR2_DEFAULT_VALUE; + *CCR3(config->base) = CCR3_DEFAULT_VALUE; + *CCR4(config->base) = CCR4_DEFAULT_VALUE; + + /* Configure pinmuxes */ + ret = pinctrl_apply_state(config->pin_config, PINCTRL_STATE_DEFAULT); + if (ret) { + return ret; + } + + *CFCLR(config->base) = CFCLR_ALL_FLAG_CLEAR; + *FFCLR(config->base) = FFCLR_MASK_DRC; + + /* Use FIFO mode. */ + *CCR3(config->base) |= (CCR3_MASK_FM); + + switch (data->uart_cfg.stop_bits) { + case UART_CFG_STOP_BITS_1: + /* Default value, already set. */ + break; + case UART_CFG_STOP_BITS_2: + *CCR3(config->base) |= CCR3_MASK_STP; + break; + default: + LOG_ERR("Selected bit stop length is not supported: %u.", data->uart_cfg.stop_bits); + return -ENOTSUP; + } + + switch (data->uart_cfg.data_bits) { + case UART_CFG_DATA_BITS_7: + *CCR3(config->base) |= CCR3_CHR_7BIT; + break; + case UART_CFG_DATA_BITS_8: + *CCR3(config->base) |= CCR3_CHR_8BIT; + break; + default: + LOG_ERR("Selected number of data bits is not supported: %u.", + data->uart_cfg.data_bits); + return -ENOTSUP; + } + + if (data->uart_cfg.baudrate > ARRAY_SIZE(baud_settings)) { + LOG_ERR("Selected baudrate variant is not supported: %u.", data->uart_cfg.baudrate); + return -ENOTSUP; + } + baud_setting = baud_settings[data->uart_cfg.baudrate]; + + *CCR2(config->base) &= ~(CCR2_MASK_BAUD_SETTING); + *CCR2(config->base) |= (baud_setting & CCR2_MASK_BAUD_SETTING); + + *CCR1(config->base) |= (CCR1_MASK_NFEN | CCR1_MASK_SPB2DT | CCR1_MASK_SPB2IO); + + switch (data->uart_cfg.parity) { + case UART_CFG_PARITY_NONE: + /* Default value, already set. */ + break; + case UART_CFG_PARITY_EVEN: + *CCR1(config->base) |= CCR1_MASK_PE; + break; + case UART_CFG_PARITY_ODD: + *CCR1(config->base) |= (CCR1_MASK_PE | CCR1_MASK_PM); + break; + default: + LOG_ERR("Unsupported parity: %u", data->uart_cfg.parity); + } + + /* Specify trigger thresholds and clear FIFOs. */ + *FCR(config->base) = FCR_MASK_TFRST | FCR_MASK_RFRST | FCR_TTRG_15 | FCR_RTRG_15; + + /* Enable the clock. */ + *CCR3(config->base) &= ~CCR3_MASK_CKE; + *CCR3(config->base) |= CCR3_CKE_ENABLE; + + /* Clear status flags. */ + *CFCLR(config->base) = CFCLR_ALL_FLAG_CLEAR; + *FFCLR(config->base) = FFCLR_MASK_DRC; + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + config->irq_config_func(dev); +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + + /* Start transmitter and receiver. */ + *CCR0(config->base) |= (CCR0_MASK_TE | CCR0_MASK_RE); + while (!(*CCR0(config->base) & CCR0_MASK_RE)) { + } + while (!(*CCR0(config->base) & CCR0_MASK_TE)) { + } + + rzt2m_lock_prcrs(PRCRS_GPIO); + rzt2m_lock_prcrn(PRCRN_PRC1 | PRCRN_PRC2); + + return 0; +} + +static void uart_rzt2m_isr(const struct device *dev) +{ + const struct rzt2m_device_config *config = dev->config; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + struct rzt2m_device_data *data = dev->data; + + if (data->callback) { + data->callback(dev, data->callback_data); + } +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + + *CFCLR(config->base) = CFCLR_MASK_RDRFC; + *FFCLR(config->base) = FFCLR_MASK_DRC; +} + +#define UART_RZT2M_IRQ_CONNECT(n, irq_name) \ + do { \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, irq_name, irq), \ + DT_INST_IRQ_BY_NAME(n, irq_name, priority), uart_rzt2m_isr, \ + DEVICE_DT_INST_GET(n), DT_INST_IRQ_BY_NAME(n, irq_name, flags)); \ + irq_enable(DT_INST_IRQ_BY_NAME(n, irq_name, irq)); \ + } while (false) + +#define UART_RZT2M_CONFIG_FUNC(n) \ + static void uart##n##_rzt2m_irq_config(const struct device *port) \ + { \ + UART_RZT2M_IRQ_CONNECT(n, rx_err); \ + UART_RZT2M_IRQ_CONNECT(n, rx); \ + UART_RZT2M_IRQ_CONNECT(n, tx); \ + UART_RZT2M_IRQ_CONNECT(n, tx_end); \ + } + +#define UART_RZT2M_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + static struct rzt2m_device_data rzt2m_uart_##n##data = { \ + .uart_cfg = \ + { \ + .baudrate = DT_INST_ENUM_IDX(n, current_speed), \ + .parity = DT_INST_ENUM_IDX_OR(n, parity, UART_CFG_PARITY_NONE), \ + .stop_bits = \ + DT_INST_ENUM_IDX_OR(n, stop_bits, UART_CFG_STOP_BITS_1), \ + .data_bits = \ + DT_INST_ENUM_IDX_OR(n, data_bits, UART_CFG_DATA_BITS_8), \ + }, \ + }; \ + UART_RZT2M_CONFIG_FUNC(n); \ + static const struct rzt2m_device_config rzt2m_uart_##n##_config = { \ + .base = DT_INST_REG_ADDR(n), \ + .irq_config_func = uart##n##_rzt2m_irq_config, \ + .pin_config = PINCTRL_DT_INST_DEV_CONFIG_GET(n)}; \ + DEVICE_DT_INST_DEFINE(n, &rzt2m_uart_init, NULL, &rzt2m_uart_##n##data, \ + &rzt2m_uart_##n##_config, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ + &rzt2m_uart_api); + +DT_INST_FOREACH_STATUS_OKAY(UART_RZT2M_INIT) diff --git a/drivers/serial/uart_rzt2m.h b/drivers/serial/uart_rzt2m.h new file mode 100644 index 000000000000000..829064857b059b8 --- /dev/null +++ b/drivers/serial/uart_rzt2m.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SERIAL_UART_RZT2M_H_ +#define ZEPHYR_DRIVERS_SERIAL_UART_RZT2M_H_ + +#include + +#define MAX_FIFO_DEPTH 16 + +#define RDR(base) ((volatile uint32_t *)(base)) +#define TDR(base) ((volatile uint32_t *)(base + 0x04)) +#define CCR0(base) ((volatile uint32_t *)(base + 0x08)) +#define CCR1(base) ((volatile uint32_t *)(base + 0x0c)) +#define CCR2(base) ((volatile uint32_t *)(base + 0x10)) +#define CCR3(base) ((volatile uint32_t *)(base + 0x14)) +#define CCR4(base) ((volatile uint32_t *)(base + 0x18)) +#define FCR(base) ((volatile uint32_t *)(base + 0x24)) +#define CSR(base) ((volatile uint32_t *)(base + 0x48)) +#define FRSR(base) ((volatile uint32_t *)(base + 0x50)) +#define FTSR(base) ((volatile uint32_t *)(base + 0x54)) +#define CFCLR(base) ((volatile uint32_t *)(base + 0x68)) +#define FFCLR(base) ((volatile uint32_t *)(base + 0x70)) + +#define CCR0_DEFAULT_VALUE 0x0 +#define CCR1_DEFAULT_VALUE 0x00000010 +#define CCR2_DEFAULT_VALUE 0xff00ff04 +#define CCR3_DEFAULT_VALUE 0x00001203 +#define CCR4_DEFAULT_VALUE 0x0 + +#define RDR_MASK_RDAT GENMASK(8, 0) + +#define CCR0_MASK_RE BIT(0) +#define CCR0_MASK_TE BIT(4) +#define CCR0_MASK_DCME BIT(9) +#define CCR0_MASK_IDSEL BIT(10) +#define CCR0_MASK_RIE BIT(16) +#define CCR0_MASK_TIE BIT(20) +#define CCR0_MASK_TEIE BIT(21) +#define CCR0_MASK_SSE BIT(24) + +#define CCR1_MASK_CTSE BIT(0) +#define CCR1_MASK_SPB2DT BIT(4) +#define CCR1_MASK_SPB2IO BIT(5) +#define CCR1_MASK_PE BIT(8) +#define CCR1_MASK_PM BIT(9) +#define CCR1_MASK_NFEN BIT(28) + +#define CCR2_MASK_BGDM BIT(4) +#define CCR2_MASK_ABCS BIT(5) +#define CCR2_MASK_ABCSE BIT(6) +#define CCR2_MASK_BRR GENMASK(15, 8) +#define CCR2_MASK_BRME BIT(16) +#define CCR2_MASK_CKS GENMASK(21, 20) +#define CCR2_MASK_MDDR GENMASK(31, 24) +#define CCR2_MASK_BAUD_SETTING \ + (CCR2_MASK_BRME | CCR2_MASK_ABCSE | CCR2_MASK_ABCS | CCR2_MASK_BGDM | CCR2_MASK_CKS | \ + CCR2_MASK_BRR | CCR2_MASK_MDDR) + +#define CCR3_MASK_STP BIT(14) +#define CCR3_MASK_MP BIT(19) +#define CCR3_MASK_FM BIT(20) +#define CCR3_MASK_CKE (BIT(24) | BIT(25)) +#define CCR3_CKE_ENABLE BIT(24) +#define CCR3_CHR_7BIT (BIT(8) | BIT(9)) +#define CCR3_CHR_8BIT BIT(9) + +#define CCR4_MASK_ASEN BIT(16) +#define CCR4_MASK_ATEN BIT(17) + +#define FCR_MASK_TFRST BIT(15) +#define FCR_MASK_RFRST BIT(23) +#define FCR_MASK_TTRG GENMASK(12, 8) +#define FCR_MASK_RTRG GENMASK(20, 16) +#define FCR_TTRG_15 (15 << 8) +#define FCR_RTRG_15 (15 << 16) + +#define CSR_MASK_ORER BIT(24) +#define CSR_MASK_PER BIT(27) +#define CSR_MASK_FER BIT(28) +#define CSR_MASK_TDRE BIT(29) +#define CSR_MASK_TEND BIT(30) +#define CSR_MASK_RDRF BIT(31) + +#define FRSR_MASK_DR BIT(0) +#define FRSR_R(val) ((val >> 7) & 0x3f) + +#define FTSR_T(val) (val & 0x3f) + +#define CFCLR_MASK_ERSC BIT(4) +#define CFCLR_MASK_DCMFC BIT(16) +#define CFCLR_MASK_DPERC BIT(17) +#define CFCLR_MASK_DFERC BIT(18) +#define CFCLR_MASK_ORERC BIT(24) +#define CFCLR_MASK_MFFC BIT(26) +#define CFCLR_MASK_PERC BIT(27) +#define CFCLR_MASK_FERC BIT(28) +#define CFCLR_MASK_TDREC BIT(29) +#define CFCLR_MASK_RDRFC BIT(31) +#define CFCLR_ALL_FLAG_CLEAR \ + (CFCLR_MASK_ERSC | CFCLR_MASK_DCMFC | CFCLR_MASK_DPERC | CFCLR_MASK_DFERC | \ + CFCLR_MASK_ORERC | CFCLR_MASK_MFFC | CFCLR_MASK_PERC | CFCLR_MASK_FERC | \ + CFCLR_MASK_TDREC | CFCLR_MASK_RDRFC) + +#define FFCLR_MASK_DRC BIT(0) + +#define MSTPCRA (volatile uint32_t *)(0x80280000 + 0x300) +#define MSTPCRA_MASK_SCIx(x) BIT(x + 8) +#define BASE_TO_IFACE_ID(base) ((base & 0x1000000) ? 5 : ((base & 0xff00) >> 10) - 4) + +#define CCR2_MDDR_128 BIT(31) +#define CCR2_CKS_0 0 +#define CCR2_BRME_0 0 +#define CCR2_BRR_243 (0xf3 << 8) +#define CCR2_BRR_39 (0x27 << 8) +#define CCR2_BGDM_1 BIT(4) + +#define CCR2_BAUD_SETTING_9600 (CCR2_MDDR_128 | CCR2_BRR_243) +#define CCR2_BAUD_SETTING_115200 (CCR2_MDDR_128 | CCR2_BRR_39 | CCR2_BGDM_1) + +#endif /* ZEPHYR_DRIVERS_SERIAL_UART_RZT2M_H_ */ diff --git a/drivers/serial/uart_sam.c b/drivers/serial/uart_sam.c index 0173c15b6bc8a14..2c54f6e550a9323 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 ce1f8ef73c70fa4..35931fe5a17a09a 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 6bbecb407cf9c78..74fcc4a50403647 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 9243b10d7e73c82..834012ca3c146e6 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -51,8 +51,7 @@ LOG_MODULE_REGISTER(uart_stm32, CONFIG_UART_LOG_LEVEL); #define STM32_UART_DOMAIN_CLOCK_SUPPORT 0 #endif -#define HAS_LPUART_1 (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpuart1), \ - st_stm32_lpuart, okay)) +#define HAS_LPUART DT_HAS_COMPAT_STATUS_OKAY(st_stm32_lpuart) /* Available everywhere except l1, f1, f2, f4. */ #ifdef USART_CR3_DEM @@ -61,7 +60,7 @@ LOG_MODULE_REGISTER(uart_stm32, CONFIG_UART_LOG_LEVEL); #define HAS_DRIVER_ENABLE 0 #endif -#if HAS_LPUART_1 +#if HAS_LPUART #ifdef USART_PRESC_PRESCALER uint32_t lpuartdiv_calc(const uint64_t clock_rate, const uint16_t presc_idx, const uint32_t baud_rate) @@ -87,7 +86,7 @@ uint32_t lpuartdiv_calc(const uint64_t clock_rate, const uint32_t baud_rate) return (uint32_t)lpuartdiv; } #endif /* USART_PRESC_PRESCALER */ -#endif /* HAS_LPUART_1 */ +#endif /* HAS_LPUART */ #ifdef CONFIG_PM static void uart_stm32_pm_policy_state_lock_get(const struct device *dev) @@ -97,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); + } } } @@ -107,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 */ @@ -135,7 +140,7 @@ static inline void uart_stm32_set_baudrate(const struct device *dev, uint32_t ba } } -#if HAS_LPUART_1 +#if HAS_LPUART if (IS_LPUART_INSTANCE(config->usart)) { uint32_t lpuartdiv; #ifdef USART_PRESC_PRESCALER @@ -178,7 +183,7 @@ static inline void uart_stm32_set_baudrate(const struct device *dev, uint32_t ba __ASSERT(LL_LPUART_ReadReg(config->usart, BRR) < 0x000FFFFFU, "BaudRateReg < 0xFFFF"); } else { -#endif /* HAS_LPUART_1 */ +#endif /* HAS_LPUART */ #ifdef USART_CR1_OVER8 LL_USART_SetOverSampling(config->usart, LL_USART_OVERSAMPLING_16); @@ -196,9 +201,9 @@ static inline void uart_stm32_set_baudrate(const struct device *dev, uint32_t ba __ASSERT(LL_USART_ReadReg(config->usart, BRR) >= 16, "BaudRateReg >= 16"); -#if HAS_LPUART_1 +#if HAS_LPUART } -#endif /* HAS_LPUART_1 */ +#endif /* HAS_LPUART */ } static inline void uart_stm32_set_parity(const struct device *dev, @@ -315,12 +320,12 @@ static inline uint32_t uart_stm32_cfg2ll_stopbits(const struct uart_stm32_config /* Some MCU's don't support 0.5 stop bits */ #ifdef LL_USART_STOPBITS_0_5 case UART_CFG_STOP_BITS_0_5: -#if HAS_LPUART_1 +#if HAS_LPUART if (IS_LPUART_INSTANCE(config->usart)) { /* return the default */ return LL_USART_STOPBITS_1; } -#endif /* HAS_LPUART_1 */ +#endif /* HAS_LPUART */ return LL_USART_STOPBITS_0_5; #endif /* LL_USART_STOPBITS_0_5 */ case UART_CFG_STOP_BITS_1: @@ -328,7 +333,7 @@ static inline uint32_t uart_stm32_cfg2ll_stopbits(const struct uart_stm32_config /* Some MCU's don't support 1.5 stop bits */ #ifdef LL_USART_STOPBITS_1_5 case UART_CFG_STOP_BITS_1_5: -#if HAS_LPUART_1 +#if HAS_LPUART if (IS_LPUART_INSTANCE(config->usart)) { /* return the default */ return LL_USART_STOPBITS_2; @@ -568,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); @@ -1258,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); @@ -1279,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 */ @@ -1310,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); /* @@ -1322,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) @@ -1580,6 +1597,13 @@ static int uart_stm32_async_rx_enable(const struct device *dev, return -EFAULT; } + /* Flush RX data buffer */ +#ifdef USART_SR_RXNE + LL_USART_ClearFlag_RXNE(config->usart); +#else + LL_USART_RequestRxDataFlush(config->usart); +#endif /* USART_SR_RXNE */ + /* Enable RX DMA requests */ uart_stm32_dma_rx_enable(dev); @@ -1617,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); @@ -1895,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 */ @@ -1938,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 @@ -1992,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 @@ -2045,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: @@ -2300,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 ed8e8584cd66d5d..7c6f432a5045193 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 ac87c41bdbfcc26..2b050e74205724b 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/sip_svc/sip_smc_intel_socfpga.c b/drivers/sip_svc/sip_smc_intel_socfpga.c index b4db6d48a86430a..09d351798e312f5 100644 --- a/drivers/sip_svc/sip_smc_intel_socfpga.c +++ b/drivers/sip_svc/sip_smc_intel_socfpga.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include diff --git a/drivers/smbus/CMakeLists.txt b/drivers/smbus/CMakeLists.txt index 13a260681f05a87..b7677a9bf6f49cc 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 b80e1df2dd91f49..74efaae29f17646 100644 --- a/drivers/smbus/Kconfig +++ b/drivers/smbus/Kconfig @@ -12,7 +12,6 @@ if SMBUS config SMBUS_SHELL bool "SMBus Shell" - default y depends on SHELL help Enable SMBus Shell. @@ -78,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 e40fc3d0cb659ab..9452efecf224d2e 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_handlers.c b/drivers/smbus/smbus_handlers.c index 0c97978883080fc..b9c45e76cf76bf2 100644 --- a/drivers/smbus/smbus_handlers.c +++ b/drivers/smbus/smbus_handlers.c @@ -5,13 +5,13 @@ */ #include -#include +#include #include static inline int z_vrfy_smbus_configure(const struct device *dev, uint32_t dev_config) { - Z_OOPS(Z_SYSCALL_DRIVER_SMBUS(dev, configure)); + K_OOPS(K_SYSCALL_DRIVER_SMBUS(dev, configure)); return z_impl_smbus_configure(dev, dev_config); } @@ -20,8 +20,8 @@ static inline int z_vrfy_smbus_configure(const struct device *dev, static inline int z_vrfy_smbus_get_config(const struct device *dev, uint32_t *dev_config) { - Z_OOPS(Z_SYSCALL_DRIVER_SMBUS(dev, get_config)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(dev_config, sizeof(uint32_t))); + K_OOPS(K_SYSCALL_DRIVER_SMBUS(dev, get_config)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(dev_config, sizeof(uint32_t))); return z_impl_smbus_get_config(dev, dev_config); } @@ -30,7 +30,7 @@ static inline int z_vrfy_smbus_get_config(const struct device *dev, static inline int z_vrfy_smbus_quick(const struct device *dev, uint16_t addr, enum smbus_direction rw) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); return z_impl_smbus_quick(dev, addr, rw); } @@ -39,7 +39,7 @@ static inline int z_vrfy_smbus_quick(const struct device *dev, uint16_t addr, static inline int z_vrfy_smbus_byte_write(const struct device *dev, uint16_t addr, uint8_t byte) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); return z_impl_smbus_byte_write(dev, addr, byte); } @@ -48,8 +48,8 @@ static inline int z_vrfy_smbus_byte_write(const struct device *dev, static inline int z_vrfy_smbus_byte_read(const struct device *dev, uint16_t addr, uint8_t *byte) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(byte, sizeof(uint8_t))); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(byte, sizeof(uint8_t))); return z_impl_smbus_byte_read(dev, addr, byte); } @@ -59,7 +59,7 @@ static inline int z_vrfy_smbus_byte_data_write(const struct device *dev, uint16_t addr, uint8_t cmd, uint8_t byte) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); return z_impl_smbus_byte_data_write(dev, addr, cmd, byte); } @@ -69,8 +69,8 @@ static inline int z_vrfy_smbus_byte_data_read(const struct device *dev, uint16_t addr, uint8_t cmd, uint8_t *byte) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(byte, sizeof(uint8_t))); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(byte, sizeof(uint8_t))); return z_impl_smbus_byte_data_read(dev, addr, cmd, byte); } @@ -80,7 +80,7 @@ static inline int z_vrfy_smbus_word_data_write(const struct device *dev, uint16_t addr, uint8_t cmd, uint16_t word) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); return z_impl_smbus_word_data_write(dev, addr, cmd, word); } @@ -90,8 +90,8 @@ static inline int z_vrfy_smbus_word_data_read(const struct device *dev, uint16_t addr, uint8_t cmd, uint16_t *word) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(word, sizeof(uint16_t))); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(word, sizeof(uint16_t))); return z_impl_smbus_word_data_read(dev, addr, cmd, word); } @@ -101,8 +101,8 @@ static inline int z_vrfy_smbus_pcall(const struct device *dev, uint16_t addr, uint8_t cmd, uint16_t send_word, uint16_t *recv_word) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(recv_word, sizeof(uint16_t))); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(recv_word, sizeof(uint16_t))); return z_impl_smbus_pcall(dev, addr, cmd, send_word, recv_word); } @@ -112,8 +112,8 @@ static inline int z_vrfy_smbus_block_write(const struct device *dev, uint16_t addr, uint8_t cmd, uint8_t count, uint8_t *buf) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(buf, count)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + K_OOPS(K_SYSCALL_MEMORY_READ(buf, count)); return z_impl_smbus_block_write(dev, addr, cmd, count, buf); } @@ -123,8 +123,8 @@ static inline int z_vrfy_smbus_block_read(const struct device *dev, uint16_t addr, uint8_t cmd, uint8_t *count, uint8_t *buf) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(count, sizeof(uint8_t))); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(count, sizeof(uint8_t))); return z_impl_smbus_block_read(dev, addr, cmd, count, buf); } @@ -135,46 +135,28 @@ static inline int z_vrfy_smbus_block_pcall(const struct device *dev, uint8_t snd_count, uint8_t *snd_buf, uint8_t *rcv_count, uint8_t *rcv_buf) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(snd_buf, snd_count)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(rcv_count, sizeof(uint8_t))); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + K_OOPS(K_SYSCALL_MEMORY_READ(snd_buf, snd_count)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(rcv_count, sizeof(uint8_t))); return z_impl_smbus_block_pcall(dev, addr, cmd, snd_count, snd_buf, rcv_count, rcv_buf); } #include -static inline int z_vrfy_smbus_smbalert_set_cb(const struct device *dev, - struct smbus_callback *cb) -{ - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); - - return z_impl_smbus_smbalert_set_cb(dev, cb); -} -#include - static inline int z_vrfy_smbus_smbalert_remove_cb(const struct device *dev, struct smbus_callback *cb) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); return z_impl_smbus_smbalert_remove_cb(dev, cb); } #include -static inline int z_vrfy_smbus_host_notify_set_cb(const struct device *dev, - struct smbus_callback *cb) -{ - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); - - return z_impl_smbus_host_notify_set_cb(dev, cb); -} -#include - static inline int z_vrfy_smbus_host_notify_remove_cb(const struct device *dev, struct smbus_callback *cb) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); return z_impl_smbus_host_notify_remove_cb(dev, cb); } diff --git a/drivers/smbus/smbus_stm32.c b/drivers/smbus/smbus_stm32.c new file mode 100644 index 000000000000000..56636cc84bff09f --- /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 000000000000000..5ff3076da9e163f --- /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 0158d2c5a521e38..a4f7ecd0c729211 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 269b28549ebcd1c..eccdc7325de4848 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -49,3 +49,5 @@ 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) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 75f7993ef271467..8618b284b443885 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -135,4 +135,8 @@ source "drivers/spi/Kconfig.rpi_pico" source "drivers/spi/Kconfig.ifx_cat1" +source "drivers/spi/Kconfig.sedi" + +source "drivers/spi/Kconfig.npcx" + endif # SPI diff --git a/drivers/spi/Kconfig.dw b/drivers/spi/Kconfig.dw index 1902d36bc4dca8d..3ebdd54ee932182 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.mcux_lpspi b/drivers/spi/Kconfig.mcux_lpspi index 1b1cc4675fb89a4..bad4191fbdc3791 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 000000000000000..196e85cf02d8cc2 --- /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 a1a2182c2656421..0ee1c03065baf30 100644 --- a/drivers/spi/Kconfig.nrfx +++ b/drivers/spi/Kconfig.nrfx @@ -27,6 +27,21 @@ config SPI_NRFX_SPIM select NRFX_SPIM2 if HAS_HW_NRF_SPIM2 select NRFX_SPIM3 if HAS_HW_NRF_SPIM3 select NRFX_SPIM4 if HAS_HW_NRF_SPIM4 + select NRFX_SPIM00 if HAS_HW_NRF_SPIM00 + select NRFX_SPIM20 if HAS_HW_NRF_SPIM20 + select NRFX_SPIM21 if HAS_HW_NRF_SPIM21 + select NRFX_SPIM22 if HAS_HW_NRF_SPIM22 + select NRFX_SPIM30 if HAS_HW_NRF_SPIM30 + select NRFX_SPIM120 if HAS_HW_NRF_SPIM120 + select NRFX_SPIM121 if HAS_HW_NRF_SPIM121 + select NRFX_SPIM130 if HAS_HW_NRF_SPIM130 + select NRFX_SPIM131 if HAS_HW_NRF_SPIM131 + select NRFX_SPIM132 if HAS_HW_NRF_SPIM132 + select NRFX_SPIM133 if HAS_HW_NRF_SPIM133 + select NRFX_SPIM134 if HAS_HW_NRF_SPIM134 + select NRFX_SPIM135 if HAS_HW_NRF_SPIM135 + select NRFX_SPIM136 if HAS_HW_NRF_SPIM136 + select NRFX_SPIM137 if HAS_HW_NRF_SPIM137 config SPI_NRFX_SPIS def_bool y @@ -39,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 @@ -59,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 6423390a0246125..1a7e0b5916bed46 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.sedi b/drivers/spi/Kconfig.sedi new file mode 100644 index 000000000000000..a9f9ca6c90ac72b --- /dev/null +++ b/drivers/spi/Kconfig.sedi @@ -0,0 +1,14 @@ +# +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +config SPI_SEDI + bool "Intel SEDI SPI driver" + default y + depends on DT_HAS_INTEL_SEDI_SPI_ENABLED + help + This option enables the Intel SEDI SPI driver. + This driver is simply a shim driver built upon the SEDI + bare metal SPI driver in the hal-intel module diff --git a/drivers/spi/Kconfig.stm32 b/drivers/spi/Kconfig.stm32 index 8baa58801926db7..04bc6dabcd2f838 100644 --- a/drivers/spi/Kconfig.stm32 +++ b/drivers/spi/Kconfig.stm32 @@ -32,5 +32,21 @@ config SPI_STM32_USE_HW_SS help Use Slave Select pin instead of software Slave Select. +config SPI_STM32_ERRATA_BUSY + bool + default y + 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 for instance in Errata Sheet 0290 §2.11.2 + +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_STM32_ERRATA_BUSY endif # SPI_STM32 diff --git a/drivers/spi/mspi_ambiq.c b/drivers/spi/mspi_ambiq.c index 03ad8b2c0ac7712..0f24fcdfe4f99d9 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 16614798e327015..61d71e3f5671601 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 87726fd90caa608..3ae422c767300be 100644 --- a/drivers/spi/spi_andes_atcspi200.c +++ b/drivers/spi/spi_andes_atcspi200.c @@ -283,7 +283,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, diff --git a/drivers/spi/spi_b91.c b/drivers/spi/spi_b91.c index bdc580a521f90b6..f3f1202df291178 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 cf6a2973934cbb7..cffd25abd9a0abe 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 e5700863932a277..7126cac00a827b7 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 dd518c9b853ded5..54eeaa1ece140d0 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 9c8f3a6cd70b5f3..d8e89b1ae7f3d7e 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 a6ace4f263f0cfb..0bfed3fc8be3e50 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 7f9ecaf90fb77aa..c5c37a82f21dc8e 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 c223986d8d46094..d07485793b02f48 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_handlers.c b/drivers/spi/spi_handlers.c index 7793d6b8a3a9eab..68b362b5ed285b9 100644 --- a/drivers/spi/spi_handlers.c +++ b/drivers/spi/spi_handlers.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include /* This assumes that bufs and buf_copy are copies from the values passed @@ -23,7 +23,7 @@ static struct spi_buf_set *copy_and_check(struct spi_buf_set *bufs, } /* Validate the array of struct spi_buf instances */ - Z_OOPS(Z_SYSCALL_MEMORY_ARRAY_READ(bufs->buffers, + K_OOPS(K_SYSCALL_MEMORY_ARRAY_READ(bufs->buffers, bufs->count, sizeof(struct spi_buf))); @@ -40,7 +40,7 @@ static struct spi_buf_set *copy_and_check(struct spi_buf_set *bufs, */ const struct spi_buf *buf = &bufs->buffers[i]; - Z_OOPS(Z_SYSCALL_MEMORY(buf->buf, buf->len, writable)); + K_OOPS(K_SYSCALL_MEMORY(buf->buf, buf->len, writable)); } return bufs; @@ -76,17 +76,17 @@ static inline int z_vrfy_spi_transceive(const struct device *dev, struct spi_buf_set rx_bufs_copy; struct spi_config config_copy; - Z_OOPS(Z_SYSCALL_MEMORY_READ(config, sizeof(*config))); - Z_OOPS(Z_SYSCALL_DRIVER_SPI(dev, transceive)); + K_OOPS(K_SYSCALL_MEMORY_READ(config, sizeof(*config))); + K_OOPS(K_SYSCALL_DRIVER_SPI(dev, transceive)); if (tx_bufs) { const struct spi_buf_set *tx = (const struct spi_buf_set *)tx_bufs; - Z_OOPS(Z_SYSCALL_MEMORY_READ(tx_bufs, + K_OOPS(K_SYSCALL_MEMORY_READ(tx_bufs, sizeof(struct spi_buf_set))); memcpy(&tx_bufs_copy, tx, sizeof(tx_bufs_copy)); - Z_OOPS(Z_SYSCALL_VERIFY(tx_bufs_copy.count < 32)); + K_OOPS(K_SYSCALL_VERIFY(tx_bufs_copy.count < 32)); } else { memset(&tx_bufs_copy, 0, sizeof(tx_bufs_copy)); } @@ -95,17 +95,17 @@ static inline int z_vrfy_spi_transceive(const struct device *dev, const struct spi_buf_set *rx = (const struct spi_buf_set *)rx_bufs; - Z_OOPS(Z_SYSCALL_MEMORY_READ(rx_bufs, + K_OOPS(K_SYSCALL_MEMORY_READ(rx_bufs, sizeof(struct spi_buf_set))); memcpy(&rx_bufs_copy, rx, sizeof(rx_bufs_copy)); - Z_OOPS(Z_SYSCALL_VERIFY(rx_bufs_copy.count < 32)); + K_OOPS(K_SYSCALL_VERIFY(rx_bufs_copy.count < 32)); } else { memset(&rx_bufs_copy, 0, sizeof(rx_bufs_copy)); } memcpy(&config_copy, config, sizeof(*config)); if (spi_cs_is_gpio(&config_copy)) { - Z_OOPS(Z_SYSCALL_OBJ(config_copy.cs.gpio.port, + K_OOPS(K_SYSCALL_OBJ(config_copy.cs.gpio.port, K_OBJ_DRIVER_GPIO)); } @@ -119,8 +119,8 @@ static inline int z_vrfy_spi_transceive(const struct device *dev, static inline int z_vrfy_spi_release(const struct device *dev, const struct spi_config *config) { - Z_OOPS(Z_SYSCALL_MEMORY_READ(config, sizeof(*config))); - Z_OOPS(Z_SYSCALL_DRIVER_SPI(dev, release)); + K_OOPS(K_SYSCALL_MEMORY_READ(config, sizeof(*config))); + K_OOPS(K_SYSCALL_DRIVER_SPI(dev, release)); return z_impl_spi_release((const struct device *)dev, config); } #include diff --git a/drivers/spi/spi_ifx_cat1.c b/drivers/spi/spi_ifx_cat1.c index ceafe8e6635d601..dd5295c3960a91a 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 974f94af5eefb34..dff26a6fc313354 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 e62a763a3f998a0..c222a6244340ecd 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); @@ -299,66 +341,23 @@ static int spi_stm32_get_err(SPI_TypeDef *spi) /* Shift a SPI frame as master. */ static void spi_stm32_shift_m(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)) { + while (!ll_func_tx_is_not_full(spi)) { /* NOP */ } -#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 - - 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); - } 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); - /* The update is ignored if TX is off. */ - spi_context_update_tx(&data->ctx, 2, 1); - } + spi_stm32_send_next_frame(spi, data); while (!ll_func_rx_is_not_empty(spi)) { /* NOP */ } - 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); - } - spi_context_update_rx(&data->ctx, 2, 1); - } + spi_stm32_read_next_frame(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) { @@ -440,7 +439,6 @@ static void spi_stm32_complete(const struct device *dev, int status) ll_func_disable_int_errors(spi); #endif - spi_stm32_cs_control(dev, false); #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_fifo) /* Flush RX buffer */ @@ -453,7 +451,10 @@ 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); @@ -617,6 +618,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 @@ -691,6 +697,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 @@ -902,9 +922,15 @@ static int transceive_dma(const struct device *dev, } #endif +#ifdef CONFIG_SPI_STM32_ERRATA_BUSY + WAIT_FOR(ll_func_spi_dma_busy(spi) != 0, + CONFIG_SPI_STM32_BUSY_FLAG_TIMEOUT, + k_yield()); +#else /* wait until spi is no more busy (spi TX fifo is really empty) */ while (ll_func_spi_dma_busy(spi) == 0) { } +#endif #if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) /* toggle the DMA transfer request */ @@ -1120,14 +1146,6 @@ 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 STM32_SPI_INIT(id) \ @@ -1144,7 +1162,15 @@ static const struct spi_stm32_config spi_stm32_cfg_##id = { \ .pclk_len = DT_INST_NUM_CLOCKS(id), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(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 949b8882dd7d06d..c241750c63e9986 100644 --- a/drivers/spi/spi_ll_stm32.h +++ b/drivers/spi/spi_ll_stm32.h @@ -27,6 +27,10 @@ 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; @@ -94,7 +98,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_mcux_dspi.c b/drivers/spi/spi_mcux_dspi.c index 63bccd704997854..14d47db4dd983f9 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 32b5638d49d6067..cb20fcea6e3be90 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 9b230d1c53f3b12..a1b805d98e0c9ff 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 000000000000000..f82d090d6932132 --- /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 1ef233cfab3819f..04a11c2367a92f9 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 515ed5c6f1f2758..0cf17e2a0356de3 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 fd1dc5d933c49a6..752132fb2482340 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 256250b5d0851d5..08012b389c55bcd 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); \ @@ -672,3 +707,63 @@ SPI_NRFX_SPIM_DEFINE(3); #ifdef CONFIG_HAS_HW_NRF_SPIM4 SPI_NRFX_SPIM_DEFINE(4); #endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM00 +SPI_NRFX_SPIM_DEFINE(00); +#endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM20 +SPI_NRFX_SPIM_DEFINE(20); +#endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM21 +SPI_NRFX_SPIM_DEFINE(21); +#endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM22 +SPI_NRFX_SPIM_DEFINE(22); +#endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM30 +SPI_NRFX_SPIM_DEFINE(30); +#endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM120 +SPI_NRFX_SPIM_DEFINE(120); +#endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM121 +SPI_NRFX_SPIM_DEFINE(121); +#endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM130 +SPI_NRFX_SPIM_DEFINE(130); +#endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM131 +SPI_NRFX_SPIM_DEFINE(131); +#endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM132 +SPI_NRFX_SPIM_DEFINE(132); +#endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM133 +SPI_NRFX_SPIM_DEFINE(133); +#endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM134 +SPI_NRFX_SPIM_DEFINE(134); +#endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM135 +SPI_NRFX_SPIM_DEFINE(135); +#endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM136 +SPI_NRFX_SPIM_DEFINE(136); +#endif + +#ifdef CONFIG_HAS_HW_NRF_SPIM137 +SPI_NRFX_SPIM_DEFINE(137); +#endif diff --git a/drivers/spi/spi_numaker.c b/drivers/spi/spi_numaker.c index 372f96271ad56c5..eda34014ebb5073 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_nxp_s32.c b/drivers/spi/spi_nxp_s32.c index f0d59ea443d9ca3..ae2384079674776 100644 --- a/drivers/spi/spi_nxp_s32.c +++ b/drivers/spi/spi_nxp_s32.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_spi + #include #include #include "spi_nxp_s32.h" @@ -58,7 +60,8 @@ static int spi_nxp_s32_transfer_next_packet(const struct device *dev) * Keep CS signal asserted until the last package, there is no other way * than directly intervening to internal state of low level driver */ - Spi_Ip_apxStateStructureArray[config->instance]->KeepCs = !spi_nxp_s32_last_packet(data); + Spi_Ip_apxStateStructureArray[config->spi_hw_cfg->Instance]->KeepCs = + !spi_nxp_s32_last_packet(data); status = Spi_Ip_AsyncTransmit(&data->transfer_cfg, (uint8_t *)data->ctx.tx_buf, data->ctx.rx_buf, data->transfer_len, data_cb); @@ -72,11 +75,11 @@ static int spi_nxp_s32_transfer_next_packet(const struct device *dev) return 0; #else - while (Spi_Ip_GetStatus(config->instance) == SPI_IP_BUSY) { - Spi_Ip_ManageBuffers(config->instance); + while (Spi_Ip_GetStatus(config->spi_hw_cfg->Instance) == SPI_IP_BUSY) { + Spi_Ip_ManageBuffers(config->spi_hw_cfg->Instance); } - if (Spi_Ip_GetStatus(config->instance) == SPI_IP_FAULT) { + if (Spi_Ip_GetStatus(config->spi_hw_cfg->Instance) == SPI_IP_FAULT) { return -EIO; } @@ -528,7 +531,7 @@ static int spi_nxp_s32_init(const struct device *dev) } #ifdef CONFIG_NXP_S32_SPI_INTERRUPT - if (Spi_Ip_UpdateTransferMode(config->instance, SPI_IP_INTERRUPT)) { + if (Spi_Ip_UpdateTransferMode(config->spi_hw_cfg->Instance, SPI_IP_INTERRUPT)) { return -EBUSY; } @@ -566,6 +569,13 @@ static int spi_nxp_s32_init(const struct device *dev) #ifdef CONFIG_NXP_S32_SPI_INTERRUPT +void spi_nxp_s32_isr(const struct device *dev) +{ + const struct spi_nxp_s32_config *config = dev->config; + + Spi_Ip_IrqHandler(config->spi_hw_cfg->Instance); +} + static void spi_nxp_s32_transfer_callback(const struct device *dev, Spi_Ip_EventType event) { struct spi_nxp_s32_data *data = dev->data; @@ -601,12 +611,17 @@ static const struct spi_driver_api spi_nxp_s32_driver_api = { .release = spi_nxp_s32_release, }; -#define SPI_NXP_S32_NODE(n) DT_NODELABEL(spi##n) -#define SPI_NXP_S32_NUM_CS(n) DT_PROP(SPI_NXP_S32_NODE(n), num_cs) -#define SPI_NXP_S32_IS_MASTER(n) !DT_PROP(SPI_NXP_S32_NODE(n), slave) +#define SPI_NXP_S32_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_SPI_##i##_BASE) ? i : 0) + +#define SPI_NXP_S32_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET SPI_INSTANCE_COUNT, SPI_NXP_S32_HW_INSTANCE_CHECK, (|), n) + +#define SPI_NXP_S32_NUM_CS(n) DT_INST_PROP(n, num_cs) +#define SPI_NXP_S32_IS_MASTER(n) !DT_INST_PROP(n, slave) #ifdef CONFIG_SPI_SLAVE -#define SPI_NXP_S32_SET_SLAVE(n) .SlaveMode = DT_PROP(SPI_NXP_S32_NODE(n), slave), +#define SPI_NXP_S32_SET_SLAVE(n) .SlaveMode = DT_INST_PROP(n, slave), #else #define SPI_NXP_S32_SET_SLAVE(n) #endif @@ -617,15 +632,12 @@ static const struct spi_driver_api spi_nxp_s32_driver_api = { .irq_config_func = spi_nxp_s32_config_func_##n, #define SPI_NXP_S32_INTERRUPT_DEFINE(n) \ - extern void Spi_Ip_SPI_##n##_IRQHandler(void); \ static void spi_nxp_s32_config_func_##n(const struct device *dev) \ { \ - IRQ_CONNECT(DT_IRQN(SPI_NXP_S32_NODE(n)), \ - DT_IRQ(SPI_NXP_S32_NODE(n), priority), \ - Spi_Ip_SPI_##n##_IRQHandler, \ - DEVICE_DT_GET(SPI_NXP_S32_NODE(n)), \ - DT_IRQ(SPI_NXP_S32_NODE(n), flags)); \ - irq_enable(DT_IRQN(SPI_NXP_S32_NODE(n))); \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ + spi_nxp_s32_isr, DEVICE_DT_INST_GET(n), \ + DT_INST_IRQ(n, flags)); \ + irq_enable(DT_INST_IRQN(n)); \ } #define SPI_NXP_S32_CONFIG_CALLBACK_FUNC(n) \ @@ -635,7 +647,7 @@ static const struct spi_driver_api spi_nxp_s32_driver_api = { static void spi_nxp_s32_##n##_callback(uint8 instance, Spi_Ip_EventType event) \ { \ ARG_UNUSED(instance); \ - const struct device *dev = DEVICE_DT_GET(SPI_NXP_S32_NODE(n)); \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ \ spi_nxp_s32_transfer_callback(dev, event); \ } @@ -652,7 +664,7 @@ static const struct spi_driver_api spi_nxp_s32_driver_api = { */ #define SPI_NXP_S32_INSTANCE_CONFIG(n) \ static const Spi_Ip_ConfigType spi_nxp_s32_default_config_##n = { \ - .Instance = n, \ + .Instance = SPI_NXP_S32_HW_INSTANCE(n), \ .Mcr = (SPI_MCR_MSTR(SPI_NXP_S32_IS_MASTER(n)) | \ SPI_MCR_CONT_SCKE(0U) | SPI_MCR_FRZ(0U) | \ SPI_MCR_MTFE(0U) | SPI_MCR_SMPL_PT(0U) | \ @@ -665,26 +677,24 @@ static const struct spi_driver_api spi_nxp_s32_driver_api = { #define SPI_NXP_S32_TRANSFER_CONFIG(n) \ .transfer_cfg = { \ - .Instance = n, \ + .Instance = SPI_NXP_S32_HW_INSTANCE(n), \ .Ctare = SPI_CTARE_FMSZE(0U) | SPI_CTARE_DTCP(1U), \ } #define SPI_NXP_S32_DEVICE(n) \ - PINCTRL_DT_DEFINE(SPI_NXP_S32_NODE(n)); \ + PINCTRL_DT_INST_DEFINE(n); \ SPI_NXP_S32_CALLBACK_DEFINE(n) \ SPI_NXP_S32_INTERRUPT_DEFINE(n) \ SPI_NXP_S32_INSTANCE_CONFIG(n); \ static const struct spi_nxp_s32_config spi_nxp_s32_config_##n = { \ - .instance = n, \ .num_cs = SPI_NXP_S32_NUM_CS(n), \ - .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(SPI_NXP_S32_NODE(n))), \ - .clock_subsys = (clock_control_subsys_t) \ - DT_CLOCKS_CELL(SPI_NXP_S32_NODE(n), name), \ - .sck_cs_delay = DT_PROP_OR(SPI_NXP_S32_NODE(n), spi_sck_cs_delay, 0U), \ - .cs_sck_delay = DT_PROP_OR(SPI_NXP_S32_NODE(n), spi_cs_sck_delay, 0U), \ - .cs_cs_delay = DT_PROP_OR(SPI_NXP_S32_NODE(n), spi_cs_cs_delay, 0U), \ - .spi_hw_cfg = (Spi_Ip_ConfigType *)&spi_nxp_s32_default_config_##n, \ - .pincfg = PINCTRL_DT_DEV_CONFIG_GET(SPI_NXP_S32_NODE(n)), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name), \ + .sck_cs_delay = DT_INST_PROP_OR(n, spi_sck_cs_delay, 0U), \ + .cs_sck_delay = DT_INST_PROP_OR(n, spi_cs_sck_delay, 0U), \ + .cs_cs_delay = DT_INST_PROP_OR(n, spi_cs_cs_delay, 0U), \ + .spi_hw_cfg = (Spi_Ip_ConfigType *)&spi_nxp_s32_default_config_##n, \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ SPI_NXP_S32_CONFIG_CALLBACK_FUNC(n) \ SPI_NXP_S32_CONFIG_INTERRUPT_FUNC(n) \ }; \ @@ -692,50 +702,12 @@ static const struct spi_driver_api spi_nxp_s32_driver_api = { SPI_NXP_S32_TRANSFER_CONFIG(n), \ SPI_CONTEXT_INIT_LOCK(spi_nxp_s32_data_##n, ctx), \ SPI_CONTEXT_INIT_SYNC(spi_nxp_s32_data_##n, ctx), \ - SPI_CONTEXT_CS_GPIOS_INITIALIZE(SPI_NXP_S32_NODE(n), ctx) \ + SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx) \ }; \ - DEVICE_DT_DEFINE(SPI_NXP_S32_NODE(n), \ + DEVICE_DT_INST_DEFINE(n, \ &spi_nxp_s32_init, NULL, \ &spi_nxp_s32_data_##n, &spi_nxp_s32_config_##n, \ POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ &spi_nxp_s32_driver_api); -#if DT_NODE_HAS_STATUS(SPI_NXP_S32_NODE(0), okay) -SPI_NXP_S32_DEVICE(0); -#endif - -#if DT_NODE_HAS_STATUS(SPI_NXP_S32_NODE(1), okay) -SPI_NXP_S32_DEVICE(1); -#endif - -#if DT_NODE_HAS_STATUS(SPI_NXP_S32_NODE(2), okay) -SPI_NXP_S32_DEVICE(2); -#endif - -#if DT_NODE_HAS_STATUS(SPI_NXP_S32_NODE(3), okay) -SPI_NXP_S32_DEVICE(3); -#endif - -#if DT_NODE_HAS_STATUS(SPI_NXP_S32_NODE(4), okay) -SPI_NXP_S32_DEVICE(4); -#endif - -#if DT_NODE_HAS_STATUS(SPI_NXP_S32_NODE(5), okay) -SPI_NXP_S32_DEVICE(5); -#endif - -#if DT_NODE_HAS_STATUS(SPI_NXP_S32_NODE(6), okay) -SPI_NXP_S32_DEVICE(6); -#endif - -#if DT_NODE_HAS_STATUS(SPI_NXP_S32_NODE(7), okay) -SPI_NXP_S32_DEVICE(7); -#endif - -#if DT_NODE_HAS_STATUS(SPI_NXP_S32_NODE(8), okay) -SPI_NXP_S32_DEVICE(8); -#endif - -#if DT_NODE_HAS_STATUS(SPI_NXP_S32_NODE(9), okay) -SPI_NXP_S32_DEVICE(9); -#endif +DT_INST_FOREACH_STATUS_OKAY(SPI_NXP_S32_DEVICE) diff --git a/drivers/spi/spi_nxp_s32.h b/drivers/spi/spi_nxp_s32.h index 3d01d1625bf05c4..68f0943b1309d43 100644 --- a/drivers/spi/spi_nxp_s32.h +++ b/drivers/spi/spi_nxp_s32.h @@ -47,7 +47,6 @@ struct spi_nxp_s32_data { }; struct spi_nxp_s32_config { - uint8_t instance; uint8_t num_cs; const struct device *clock_dev; clock_control_subsys_t clock_subsys; diff --git a/drivers/spi/spi_oc_simple.c b/drivers/spi/spi_oc_simple.c index 3b8f9c126cfdc72..a0f7296b2a996cc 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 3116315d9290d00..c3ed64c4a2eb180 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 d71516f17df2771..ed30dddf1e1efb5 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,9 +906,28 @@ 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) { + if (ret < 0) { LOG_ERR("Failed to apply pinctrl state"); return ret; } @@ -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 e6f4061c6e225d2..fa100f054e0acc8 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 579c97e5cdd6b24..ed5179e346683f9 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 3391137422516ff..282e59b4adc24c3 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_sedi.c b/drivers/spi/spi_sedi.c new file mode 100644 index 000000000000000..b3c4d22f7306195 --- /dev/null +++ b/drivers/spi/spi_sedi.c @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT intel_sedi_spi + +#include +#include +#include + +#define LOG_LEVEL CONFIG_SPI_LOG_LEVEL +#include +LOG_MODULE_REGISTER(spi_sedi); + +#include "sedi_driver_spi.h" +#include "spi_context.h" + + +struct spi_sedi_config { + DEVICE_MMIO_ROM; + sedi_spi_t spi_device; + void (*irq_config)(void); +}; + +struct spi_sedi_data { + DEVICE_MMIO_RAM; + struct spi_context ctx; + bool tx_data_updated; + bool rx_data_updated; + uint32_t tx_dummy_len; + uint32_t rx_dummy_len; +}; + +static int spi_sedi_configure(const struct device *dev, + const struct spi_config *config) +{ + struct spi_sedi_data *data = dev->data; + const struct spi_sedi_config *info = dev->config; + uint32_t word_size, cpol, cpha, loopback; + + if (spi_context_configured(&data->ctx, config) == true) { + return 0; + } + + word_size = SPI_WORD_SIZE_GET(config->operation); + sedi_spi_control(info->spi_device, SEDI_SPI_IOCTL_DATA_WIDTH, + word_size); + + /* CPOL and CPHA */ + cpol = SPI_MODE_GET(config->operation) & SPI_MODE_CPOL; + cpha = SPI_MODE_GET(config->operation) & SPI_MODE_CPHA; + + if ((cpol == 0) && (cpha == 0)) { + sedi_spi_control(info->spi_device, SEDI_SPI_IOCTL_CPOL0_CPHA0, + 0); + } else if ((cpol == 0) && (cpha == 1U)) { + sedi_spi_control(info->spi_device, SEDI_SPI_IOCTL_CPOL0_CPHA1, + 0); + } else if ((cpol == 1) && (cpha == 0U)) { + sedi_spi_control(info->spi_device, SEDI_SPI_IOCTL_CPOL1_CPHA0, + 0); + } else { + sedi_spi_control(info->spi_device, SEDI_SPI_IOCTL_CPOL1_CPHA1, + 0); + } + + /* MSB and LSB */ + if (config->operation & SPI_TRANSFER_LSB) { + sedi_spi_control(info->spi_device, SEDI_SPI_IOCTL_LSB, 0); + } + + /* Set loopack */ + loopback = SPI_MODE_GET(config->operation) & SPI_MODE_LOOP; + sedi_spi_control(info->spi_device, SEDI_SPI_IOCTL_LOOPBACK, loopback); + + /* Set baudrate */ + sedi_spi_control(info->spi_device, SEDI_SPI_IOCTL_SPEED_SET, + config->frequency); + + sedi_spi_control(info->spi_device, SEDI_SPI_IOCTL_CS_HW, config->slave); + + data->ctx.config = config; + spi_context_cs_control(&data->ctx, true); + + 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, bool asynchronous, + spi_callback_t cb, + void *userdata) +{ + const struct spi_sedi_config *info = dev->config; + struct spi_sedi_data *spi = dev->data; + struct spi_context *ctx = &spi->ctx; + int ret; + uint32_t transfer_bytes = 0; + uint8_t *data_out = NULL, *data_in = NULL; + uint32_t i, dummy_len = 0; + const struct spi_buf *buf; + bool is_multibufs = false; + + spi_context_lock(&spi->ctx, asynchronous, cb, userdata, config); + pm_device_busy_set(dev); + + /* Power up use default setting */ + ret = sedi_spi_set_power(info->spi_device, SEDI_POWER_FULL); + if (ret) { + goto out; + } + + /* If need to configure, re-configure */ + spi_sedi_configure(dev, config); + + spi->tx_data_updated = false; + spi->rx_data_updated = false; + /* Set buffers info */ + spi_context_buffers_setup(&spi->ctx, tx_bufs, rx_bufs, 1); + + if ((ctx->tx_count > 1) || (ctx->rx_count > 1)) { + is_multibufs = true; + } + + if (ctx->tx_count > ctx->rx_count) { + spi->tx_dummy_len = 0; + for (i = ctx->rx_count; i < ctx->tx_count; i++) { + buf = ctx->current_tx + i; + dummy_len += buf->len; + } + spi->rx_dummy_len = dummy_len; + } else if (ctx->tx_count < ctx->rx_count) { + spi->rx_dummy_len = 0; + for (i = ctx->tx_count; i < ctx->rx_count; i++) { + buf = ctx->current_rx + i; + dummy_len += buf->len; + } + spi->tx_dummy_len = dummy_len; + } else { + spi->tx_dummy_len = 0; + spi->rx_dummy_len = 0; + } + + if ((ctx->tx_len == 0) && (ctx->rx_len == 0)) { + spi_context_cs_control(&spi->ctx, true); + spi_context_complete(&spi->ctx, dev, 0); + return 0; + } + + /* For multiple buffers, using continuous mode */ + if (is_multibufs) { + sedi_spi_control(info->spi_device, SEDI_SPI_IOCTL_BUFFER_SETS, 1); + } + + if (ctx->tx_len == 0) { + /* rx only, nothing to tx */ + data_out = NULL; + data_in = (uint8_t *)ctx->rx_buf; + transfer_bytes = ctx->rx_len; + spi->tx_dummy_len -= transfer_bytes; + } else if (ctx->rx_len == 0) { + /* tx only, nothing to rx */ + data_out = (uint8_t *)ctx->tx_buf; + data_in = NULL; + transfer_bytes = ctx->tx_len; + spi->rx_dummy_len -= transfer_bytes; + } else if (ctx->tx_len == ctx->rx_len) { + /* rx and tx are the same length */ + data_out = (uint8_t *)ctx->tx_buf; + data_in = (uint8_t *)ctx->rx_buf; + transfer_bytes = ctx->tx_len; + } else if (ctx->tx_len > ctx->rx_len) { + /* Break up the tx into multiple transfers so we don't have to + * rx into a longer intermediate buffer. Leave chip select + * active between transfers. + */ + data_out = (uint8_t *)ctx->tx_buf; + data_in = ctx->rx_buf; + transfer_bytes = ctx->rx_len; + } else { + /* Break up the rx into multiple transfers so we don't have to + * tx from a longer intermediate buffer. Leave chip select + * active between transfers. + */ + data_out = (uint8_t *)ctx->tx_buf; + data_in = ctx->rx_buf; + transfer_bytes = ctx->tx_len; + } + + spi_context_cs_control(&spi->ctx, false); + + ret = sedi_spi_transfer(info->spi_device, data_out, data_in, + transfer_bytes); + + if (ret != SEDI_DRIVER_OK) { + goto out; + } + + ret = spi_context_wait_for_completion(&spi->ctx); + if (ret != 0) { + sedi_spi_status_t spi_status = {0}; + + sedi_spi_get_status(info->spi_device, &spi_status); + + /* SPI ABORT */ + sedi_spi_control(info->spi_device, SEDI_SPI_IOCTL_ABORT, 0); + /* Toggle GPIO back */ + spi_context_cs_control(&spi->ctx, true); + } +out: + spi_context_release(&spi->ctx, ret); + pm_device_busy_clear(dev); + + return ret; +} + +static int spi_sedi_transceive(const struct device *dev, + const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + return transceive(dev, config, tx_bufs, rx_bufs, false, NULL, NULL); +} + +#ifdef CONFIG_SPI_ASYNC +static int spi_sedi_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, + spi_callback_t cb, + void *userdata) +{ + return transceive(dev, config, tx_bufs, rx_bufs, true, cb, userdata); +} +#endif /* CONFIG_SPI_ASYNC */ + +static int spi_sedi_release(const struct device *dev, + const struct spi_config *config) +{ + struct spi_sedi_data *spi = dev->data; + + if (!spi_context_configured(&spi->ctx, config)) { + return -EINVAL; + } + + spi_context_unlock_unconditionally(&spi->ctx); + + return 0; +} + +extern void spi_isr(sedi_spi_t device); + +void spi_sedi_callback(uint32_t event, void *param) +{ + const struct device *dev = (const struct device *)param; + const struct spi_sedi_config *info = dev->config; + struct spi_sedi_data *spi = dev->data; + struct spi_context *ctx = &spi->ctx; + int error; + + if (event == SEDI_SPI_EVENT_DATA_LOST) { + error = -EIO; + } else { + error = 0; + } + + if ((event == SEDI_SPI_EVENT_COMPLETE) || + (event == SEDI_SPI_EVENT_DATA_LOST)) { + spi_context_cs_control(&spi->ctx, true); + spi_context_complete(&spi->ctx, dev, error); + } else if (event == SEDI_SPI_EVENT_TX_FINISHED) { + spi_context_update_tx(ctx, 1, ctx->tx_len); + if (ctx->tx_len != 0) { + sedi_spi_update_tx_buf(info->spi_device, ctx->tx_buf, + ctx->tx_len); + if ((ctx->rx_len == 0) && + (spi->rx_data_updated == false)) { + /* Update rx length if always no rx */ + sedi_spi_update_rx_buf(info->spi_device, NULL, + spi->rx_dummy_len); + spi->rx_data_updated = true; + } + } else if (spi->tx_data_updated == false) { + sedi_spi_update_tx_buf(info->spi_device, NULL, + spi->tx_dummy_len); + spi->tx_data_updated = true; + } + } else if (event == SEDI_SPI_EVENT_RX_FINISHED) { + spi_context_update_rx(ctx, 1, ctx->rx_len); + if (ctx->rx_len != 0) { + sedi_spi_update_rx_buf(info->spi_device, ctx->rx_buf, + ctx->rx_len); + } + } +} + +static const struct spi_driver_api sedi_spi_api = { + .transceive = spi_sedi_transceive, +#ifdef CONFIG_SPI_ASYNC + .transceive_async = spi_sedi_transceive_async, +#endif /* CONFIG_SPI_ASYNC */ + .release = spi_sedi_release, +}; + +static int spi_sedi_init(const struct device *dev) +{ + const struct spi_sedi_config *info = dev->config; + struct spi_sedi_data *spi = dev->data; + int ret; + + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + + ret = sedi_spi_init(info->spi_device, spi_sedi_callback, (void *)dev, + DEVICE_MMIO_GET(dev)); + if (ret != SEDI_DRIVER_OK) { + return -ENODEV; + } + + /* Init and connect IRQ */ + info->irq_config(); + + spi_context_unlock_unconditionally(&spi->ctx); + + return 0; +} + +#ifdef CONFIG_PM_DEVICE + +static int spi_suspend_device(const struct device *dev) +{ + const struct spi_sedi_config *config = dev->config; + + if (pm_device_is_busy(dev)) { + return -EBUSY; + } + + int ret = sedi_spi_set_power(config->spi_device, SEDI_POWER_SUSPEND); + + if (ret != SEDI_DRIVER_OK) { + return -EIO; + } + + return 0; +} + +static int spi_resume_device_from_suspend(const struct device *dev) +{ + const struct spi_sedi_config *config = dev->config; + int ret; + + ret = sedi_spi_set_power(config->spi_device, SEDI_POWER_FULL); + if (ret != SEDI_DRIVER_OK) { + return -EIO; + } + + pm_device_busy_clear(dev); + + return 0; +} + +static int spi_sedi_device_ctrl(const struct device *dev, + enum pm_device_action action) +{ + int ret = 0; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + ret = spi_suspend_device(dev); + break; + case PM_DEVICE_ACTION_RESUME: + ret = spi_resume_device_from_suspend(dev); + break; + default: + ret = -ENOTSUP; + } + + return ret; +} + +#endif /* CONFIG_PM_DEVICE */ + +#define SPI_SEDI_IRQ_FLAGS_SENSE0(n) 0 +#define SPI_SEDI_IRQ_FLAGS_SENSE1(n) DT_INST_IRQ(n, sense) +#define SPI_SEDI_IRQ_FLAGS(n) \ + _CONCAT(SPI_SEDI_IRQ_FLAGS_SENSE, DT_INST_IRQ_HAS_CELL(n, sense))(n) + +#define CREATE_SEDI_SPI_INSTANCE(num) \ + static void spi_##num##_irq_init(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(num), \ + DT_INST_IRQ(num, priority), \ + spi_isr, num, SPI_SEDI_IRQ_FLAGS(num)); \ + irq_enable(DT_INST_IRQN(num)); \ + } \ + static struct spi_sedi_data spi_##num##_data = { \ + SPI_CONTEXT_INIT_LOCK(spi_##num##_data, ctx), \ + SPI_CONTEXT_INIT_SYNC(spi_##num##_data, ctx), \ + }; \ + const static struct spi_sedi_config spi_##num##_config = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(num)), \ + .spi_device = num, .irq_config = spi_##num##_irq_init, \ + }; \ + PM_DEVICE_DEFINE(spi_##num, spi_sedi_device_ctrl); \ + DEVICE_DT_INST_DEFINE(num, \ + &spi_sedi_init, \ + PM_DEVICE_GET(spi_##num), \ + &spi_##num##_data, \ + &spi_##num##_config, \ + POST_KERNEL, \ + CONFIG_SPI_INIT_PRIORITY, \ + &sedi_spi_api); + +DT_INST_FOREACH_STATUS_OKAY(CREATE_SEDI_SPI_INSTANCE) diff --git a/drivers/spi/spi_sifive.c b/drivers/spi/spi_sifive.c index c302e67ba80c576..1b5f178c2a602d7 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 ab48e49c0956efe..a95a28fc176ba97 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/spi/spi_xmc4xxx.c b/drivers/spi/spi_xmc4xxx.c index 9c48fb050983335..97b32f20e049b58 100644 --- a/drivers/spi/spi_xmc4xxx.c +++ b/drivers/spi/spi_xmc4xxx.c @@ -123,10 +123,10 @@ static void spi_xmc4xxx_shift_frames(const struct device *dev) XMC_SPI_CH_STATUS_FLAG_RECEIVE_INDICATION | XMC_SPI_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION); - XMC_SPI_CH_Transmit(config->spi, tx_data, XMC_SPI_CH_MODE_STANDARD); - spi_context_update_tx(ctx, 1, 1); + XMC_SPI_CH_Transmit(config->spi, tx_data, XMC_SPI_CH_MODE_STANDARD); + #if defined(CONFIG_SPI_XMC4XXX_INTERRUPT) return; #endif @@ -195,7 +195,8 @@ static int spi_xmc4xxx_configure(const struct device *dev, const struct spi_conf bool CPOL = SPI_MODE_GET(settings) & SPI_MODE_CPOL; bool CPHA = SPI_MODE_GET(settings) & SPI_MODE_CPHA; XMC_SPI_CH_CONFIG_t usic_cfg = {.baudrate = spi_cfg->frequency}; - XMC_SPI_CH_BRG_SHIFT_CLOCK_PASSIVE_LEVEL_t clock_settings; + XMC_SPI_CH_BRG_SHIFT_CLOCK_PASSIVE_LEVEL_t clock_settings = + XMC_SPI_CH_BRG_SHIFT_CLOCK_PASSIVE_LEVEL_0_DELAY_ENABLED; if (spi_context_configured(ctx, spi_cfg)) { return 0; @@ -468,7 +469,9 @@ static int spi_xmc4xxx_transceive_dma(const struct device *dev, const struct spi spi_context_cs_control(ctx, false); } +#if defined(CONFIG_SPI_XMC4XXX_INTERRUPT) irq_enable(config->irq_num_rx); +#endif spi_context_release(ctx, ret); return ret; diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index 47a10b358c1bd0b..36534e4716f0087 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 fb615c2b7cfc930..f20442dd2c5821e 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -65,7 +65,7 @@ config SYSTEM_CLOCK_LOCK_FREE_COUNT source "drivers/timer/Kconfig.altera_avalon" source "drivers/timer/Kconfig.ambiq" -source "drivers/timer/Kconfig.apic" +source "drivers/timer/Kconfig.x86" source "drivers/timer/Kconfig.arcv2" source "drivers/timer/Kconfig.arm_arch" source "drivers/timer/Kconfig.cavs" @@ -73,7 +73,6 @@ source "drivers/timer/Kconfig.cc13xx_cc26xx_rtc" source "drivers/timer/Kconfig.cortex_m_systick" source "drivers/timer/Kconfig.esp32c3_sys" source "drivers/timer/Kconfig.gecko" -source "drivers/timer/Kconfig.hpet" source "drivers/timer/Kconfig.ite_it8xxx2" source "drivers/timer/Kconfig.leon_gptimer" source "drivers/timer/Kconfig.litex" @@ -85,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.apic b/drivers/timer/Kconfig.apic deleted file mode 100644 index 5e745beb945e5d5..000000000000000 --- a/drivers/timer/Kconfig.apic +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (c) 2014-2015 Wind River Systems, Inc. -# Copyright (c) 2016 Cadence Design Systems, Inc. -# Copyright (c) 2019 Intel Corp. -# SPDX-License-Identifier: Apache-2.0 - -menuconfig APIC_TIMER - bool "New local APIC timer" - depends on X86 - depends on LOAPIC - select TICKLESS_CAPABLE - select SYSTEM_CLOCK_LOCK_FREE_COUNT - help - Use the x86 local APIC in one-shot mode as the system time - source. NOTE: this probably isn't what you want except on - older or idiosyncratic hardware (or environments like qemu - without complete APIC emulation). Modern hardware will work - better with CONFIG_APIC_TSC_DEADLINE_TIMER. - -if APIC_TIMER - -config APIC_TIMER_IRQ - int "Local APIC timer IRQ" - default 24 - help - This option specifies the IRQ used by the local APIC timer. - Note: this MUST be set to the index immediately after the - last IO-APIC IRQ (the timer is the first entry in the APIC - local vector table). This footgun is not intended to be - user-configurable and almost certainly should be managed via - a different mechanism. - -config APIC_TIMER_TSC - bool "Use invariant TSC for sys_clock_cycle_get_32()" - select TIMER_HAS_64BIT_CYCLE_COUNTER - help - If your CPU supports invariant TSC, and you know the ratio of the - TSC frequency to CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC (the local APIC - timer frequency), then enable this for a much faster and more - accurate sys_clock_cycle_get_32(). - -if APIC_TIMER_TSC - -config APIC_TIMER_TSC_N - int "TSC to local APIC timer frequency multiplier (N)" - default 1 - -config APIC_TIMER_TSC_M - int "TSC to local APIC timer frequency divisor (M)" - default 1 - -endif # APIC_TIMER_TSC - -endif # APIC_TIMER - -config APIC_TSC_DEADLINE_TIMER - bool "Even newer APIC timer using TSC deadline mode" - depends on X86 - select LOAPIC - select TICKLESS_CAPABLE - select TIMER_HAS_64BIT_CYCLE_COUNTER - help - Extremely simple timer driver based the local APIC TSC - deadline capability. The use of a free-running 64 bit - counter with comparator eliminates almost all edge cases - from the handling, and the near-instruction-cycle resolution - permits effectively unlimited precision where needed (the - limit becomes the CPU time taken to execute the timing - logic). SMP-safe and very fast, this should be the obvious - choice for any x86 device with invariant TSC and TSC - deadline capability. - -config APIC_TIMER_IRQ_PRIORITY - int "Local APIC timer interrupt priority" - depends on APIC_TIMER || APIC_TSC_DEADLINE_TIMER - default 4 - help - This option specifies the interrupt priority used by the - local APIC timer. diff --git a/drivers/timer/Kconfig.cortex_m_systick b/drivers/timer/Kconfig.cortex_m_systick index 31e4f56fce5138a..2a4f48832cf78a5 100644 --- a/drivers/timer/Kconfig.cortex_m_systick +++ b/drivers/timer/Kconfig.cortex_m_systick @@ -3,6 +3,8 @@ # Copyright (c) 2019 Intel Corp. # SPDX-License-Identifier: Apache-2.0 +DT_CHOSEN_IDLE_TIMER := zephyr,cortex-m-idle-timer + config CORTEX_M_SYSTICK bool "Cortex-M SYSTICK timer" depends on CPU_CORTEX_M_HAS_SYSTICK @@ -40,3 +42,21 @@ config CORTEX_M_SYSTICK_64BIT_CYCLE_COUNTER This is set to y by default when the hardware clock is fast enough to wrap sys_clock_cycle_get_32() in about a minute or less. + +config CORTEX_M_SYSTICK_IDLE_TIMER + bool "Use an additional timer while entering IDLE" + 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 + 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 IDLE timer for timeout (wakeup) when the system is entering + IDLE state. + + The chosen IDLE timer node has to support setting alarm from the + counter API. diff --git a/drivers/timer/Kconfig.hpet b/drivers/timer/Kconfig.hpet deleted file mode 100644 index c83af2b46152221..000000000000000 --- a/drivers/timer/Kconfig.hpet +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2014-2015 Wind River Systems, Inc. -# Copyright (c) 2016 Cadence Design Systems, Inc. -# Copyright (c) 2019 Intel Corp. -# SPDX-License-Identifier: Apache-2.0 - -config HPET_TIMER - bool "HPET timer" - default y - depends on DT_HAS_INTEL_HPET_ENABLED - select IOAPIC if X86 - select LOAPIC if X86 - imply TIMER_READS_ITS_FREQUENCY_AT_RUNTIME - select TICKLESS_CAPABLE - select TIMER_HAS_64BIT_CYCLE_COUNTER - help - This option selects High Precision Event Timer (HPET) as a - system timer. diff --git a/drivers/timer/Kconfig.native_posix b/drivers/timer/Kconfig.native_posix index 6fe1c3bde4df30b..278feeec2a85ce5 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 000000000000000..442c524fd197259 --- /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 acb6f123afe1f90..729dc8d362a7e6a 100644 --- a/drivers/timer/Kconfig.nrf_rtc +++ b/drivers/timer/Kconfig.nrf_rtc @@ -19,7 +19,7 @@ if NRF_RTC_TIMER config NRF_RTC_TIMER_USER_CHAN_COUNT int "Additional channels that can be used" - default 2 if NRF_802154_RADIO_DRIVER && SOC_NRF5340_CPUNET + default 2 if NRF_802154_RADIO_DRIVER && SOC_COMPATIBLE_NRF5340_CPUNET default 3 if NRF_802154_RADIO_DRIVER default 0 help @@ -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 000000000000000..f9fa25a1c3065a7 --- /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 d1e0d5cb81ab327..31bddc0740962ee 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/Kconfig.x86 b/drivers/timer/Kconfig.x86 new file mode 100644 index 000000000000000..aa5f1a9c6d6d972 --- /dev/null +++ b/drivers/timer/Kconfig.x86 @@ -0,0 +1,98 @@ +# Copyright (c) 2014-2015 Wind River Systems, Inc. +# Copyright (c) 2016 Cadence Design Systems, Inc. +# Copyright (c) 2019-2023 Intel Corp. +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "Default System Timer" + default HPET_TIMER if SOC_FAMILY_INTEL_ISH || SOC_IA32 || SOC_LAKEMONT + default APIC_TSC_DEADLINE_TIMER + depends on X86 + help + Select Default System Timer. + +config HPET_TIMER + bool "HPET timer" + depends on DT_HAS_INTEL_HPET_ENABLED + select IOAPIC + select LOAPIC + imply TIMER_READS_ITS_FREQUENCY_AT_RUNTIME + select TICKLESS_CAPABLE + select TIMER_HAS_64BIT_CYCLE_COUNTER + help + This option selects High Precision Event Timer (HPET) as a + system timer. + +config APIC_TIMER + bool "Local APIC timer" + select LOAPIC + select TICKLESS_CAPABLE + select SYSTEM_CLOCK_LOCK_FREE_COUNT + help + Use the x86 local APIC in one-shot mode as the system time + source. NOTE: this probably isn't what you want except on + older or idiosyncratic hardware (or environments like qemu + without complete APIC emulation). Modern hardware will work + better with CONFIG_APIC_TSC_DEADLINE_TIMER. + +config APIC_TSC_DEADLINE_TIMER + bool "Local APIC timer using TSC deadline mode" + select LOAPIC + select TICKLESS_CAPABLE + select TIMER_HAS_64BIT_CYCLE_COUNTER + help + Extremely simple timer driver based the local APIC TSC + deadline capability. The use of a free-running 64 bit + counter with comparator eliminates almost all edge cases + from the handling, and the near-instruction-cycle resolution + permits effectively unlimited precision where needed (the + limit becomes the CPU time taken to execute the timing + logic). SMP-safe and very fast, this should be the obvious + choice for any x86 device with invariant TSC and TSC + deadline capability. + +endchoice + +if APIC_TIMER + +config APIC_TIMER_IRQ + int "Local APIC timer IRQ" + default 24 + help + This option specifies the IRQ used by the local APIC timer. + Note: this MUST be set to the index immediately after the + last IO-APIC IRQ (the timer is the first entry in the APIC + local vector table). This footgun is not intended to be + user-configurable and almost certainly should be managed via + a different mechanism. + +config APIC_TIMER_TSC + bool "Use invariant TSC for sys_clock_cycle_get_32()" + select TIMER_HAS_64BIT_CYCLE_COUNTER + help + If your CPU supports invariant TSC, and you know the ratio of the + TSC frequency to CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC (the local APIC + timer frequency), then enable this for a much faster and more + accurate sys_clock_cycle_get_32(). + +if APIC_TIMER_TSC + +config APIC_TIMER_TSC_N + int "TSC to local APIC timer frequency multiplier (N)" + default 1 + +config APIC_TIMER_TSC_M + int "TSC to local APIC timer frequency divisor (M)" + default 1 + +endif # APIC_TIMER_TSC + +endif # APIC_TIMER + +config APIC_TIMER_IRQ_PRIORITY + int "Local APIC timer interrupt priority" + depends on APIC_TIMER || APIC_TSC_DEADLINE_TIMER + default 4 + help + This option specifies the interrupt priority used by the + local APIC timer. diff --git a/drivers/timer/ambiq_stimer.c b/drivers/timer/ambiq_stimer.c index 5db803fb12da6cd..8a469f35907bff9 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 a9a762d9afa5f07..718fecea5829875 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 e026c3603c6f02a..b5f859ae57cc2f0 100644 --- a/drivers/timer/cortex_m_systick.c +++ b/drivers/timer/cortex_m_systick.c @@ -10,6 +10,7 @@ #include #include #include +#include #define COUNTER_MAX 0x00ffffff #define TIMER_STOPPED 0xff000000 @@ -77,6 +78,26 @@ static cycle_t announced_cycles; */ static volatile uint32_t overflow_cyc; +#ifdef CONFIG_CORTEX_M_SYSTICK_IDLE_TIMER +/* This local variable indicates that the timeout was set right before + * entering idle state. + * + * It is used for chips that has to use a separate idle timer in such + * case because the Cortex-m SysTick is not clocked in the low power + * mode state. + */ +static bool timeout_idle; + +/* Cycle counter before entering the idle state. */ +static cycle_t cycle_pre_idle; + +/* Idle timer value before entering the idle state. */ +static uint32_t idle_timer_pre_idle; + +/* Idle timer used for timer while entering the idle state */ +static const struct device *idle_timer = DEVICE_DT_GET(DT_CHOSEN(zephyr_cortex_m_idle_timer)); +#endif /* CONFIG_CORTEX_M_SYSTICK_IDLE_TIMER */ + /* This internal function calculates the amount of HW cycles that have * elapsed since the last time the absolute HW cycles counter has been * updated. 'cycle_count' may be updated either by the ISR, or when we @@ -159,6 +180,19 @@ void sys_clock_isr(void *arg) cycle_count += overflow_cyc; overflow_cyc = 0; +#ifdef CONFIG_CORTEX_M_SYSTICK_IDLE_TIMER + /* Rare case, when the interrupt was triggered, with previously programmed + * LOAD value, just before entering the idle mode (SysTick is clocked) or right + * after exiting the idle mode, before executing the procedure in the + * sys_clock_idle_exit function. + */ + if (timeout_idle) { + z_arm_int_exit(); + + return; + } +#endif /* CONFIG_CORTEX_M_SYSTICK_IDLE_TIMER */ + if (TICKLESS) { /* In TICKLESS mode, the SysTick.LOAD is re-programmed * in sys_clock_set_timeout(), followed by resetting of @@ -196,6 +230,36 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) return; } +#ifdef CONFIG_CORTEX_M_SYSTICK_IDLE_TIMER + if (idle) { + 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(idle_timer, timeout_us), + .user_data = NULL, + .flags = 0, + }; + + timeout_idle = true; + + /* Set the alarm using timer that runs the idle. + * Needed rump-up/setting time, lower accurency etc. should be + * included in the exit-latency in the power state definition. + */ + counter_cancel_channel_alarm(idle_timer, 0); + counter_set_channel_alarm(idle_timer, 0, &cfg); + + /* Store current values to calculate a difference in + * measurements after exiting the idle state. + */ + counter_get_value(idle_timer, &idle_timer_pre_idle); + cycle_pre_idle = cycle_count + elapsed(); + + return; + } +#endif /* CONFIG_CORTEX_M_SYSTICK_IDLE_TIMER */ + #if defined(CONFIG_TICKLESS_KERNEL) uint32_t delay; uint32_t val1, val2; @@ -300,6 +364,62 @@ uint64_t sys_clock_cycle_get_64(void) void sys_clock_idle_exit(void) { +#ifdef CONFIG_CORTEX_M_SYSTICK_IDLE_TIMER + 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; + + /* 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 */ + /* 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(); + + /* Calculate difference in measurements to get how much time + * the SysTick missed in idle state. + */ + 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; + + /* Announce the passed ticks to the kernel */ + dcycles = cycle_count + elapsed() - announced_cycles; + dticks = dcycles / CYC_PER_TICK; + announced_cycles += dticks * CYC_PER_TICK; + sys_clock_announce(dticks); + + /* We've alredy performed all needed operations */ + timeout_idle = false; + } +#endif /* CONFIG_CORTEX_M_SYSTICK_IDLE_TIMER */ + if (last_load == TIMER_STOPPED) { SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; } diff --git a/drivers/timer/litex_timer.c b/drivers/timer/litex_timer.c index ecc5b22a9d938fe..c12630eba34f0fe 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 31d1fc3bc696a2c..7376034ef62f145 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/npcx_itim_timer.c b/drivers/timer/npcx_itim_timer.c index a54db566d9eba25..fba2bc2b3c11348 100644 --- a/drivers/timer/npcx_itim_timer.c +++ b/drivers/timer/npcx_itim_timer.c @@ -58,6 +58,7 @@ LOG_MODULE_REGISTER(itim, LOG_LEVEL_ERR); #define NPCX_ITIM_CLK_SEL_DELAY 92 /* Delay for clock selection (Unit:us) */ /* Timeout for enabling ITIM module: 100us (Unit:cycles) */ #define NPCX_ITIM_EN_TIMEOUT_CYCLES (100 * SYS_CYCLES_PER_USEC) +#define SYS_CYC_PER_EVT_CYC (sys_clock_hw_cycles_per_sec() / EVT_CYCLES_PER_SEC) /* Instance of system and event timers */ static struct itim64_reg *const sys_tmr = (struct itim64_reg *) @@ -70,6 +71,9 @@ static const struct npcx_clk_cfg itim_clk_cfg[] = NPCX_DT_CLK_CFG_ITEMS_LIST(0); static struct k_spinlock lock; /* Announced cycles in system timer before executing sys_clock_announce() */ static uint64_t cyc_sys_announced; +static uint64_t last_ticks; +static uint32_t last_elapsed; + /* Current target cycles of time-out signal in event timer */ static uint32_t cyc_evt_timeout; /* Total cycles of system timer stopped in "sleep/deep sleep" mode */ @@ -136,18 +140,33 @@ static inline void npcx_itim_evt_disable(void) /* ITIM local functions */ static int npcx_itim_start_evt_tmr_by_tick(int32_t ticks) { + k_spinlock_key_t key = k_spin_lock(&lock); + /* * Get desired cycles of event timer from the requested ticks which * round up to next tick boundary. */ + if (ticks == K_TICKS_FOREVER) { cyc_evt_timeout = NPCX_ITIM32_MAX_CNT; } else { + uint64_t next_cycs; + uint64_t curr = npcx_itim_get_sys_cyc64(); + uint32_t dcycles; + if (ticks <= 0) { ticks = 1; } - cyc_evt_timeout = MIN(EVT_CYCLES_FROM_TICKS(ticks), - NPCX_ITIM32_MAX_CNT); + + next_cycs = (last_ticks + last_elapsed + ticks) * SYS_CYCLES_PER_TICK; + if (unlikely(next_cycs <= curr)) { + cyc_evt_timeout = 1; + } else { + dcycles = next_cycs - curr; + cyc_evt_timeout = + CLAMP((dcycles / SYS_CYC_PER_EVT_CYC), 1, NPCX_ITIM32_MAX_CNT); + } + } LOG_DBG("ticks %x, cyc_evt_timeout %x", ticks, cyc_evt_timeout); @@ -159,9 +178,9 @@ static int npcx_itim_start_evt_tmr_by_tick(int32_t ticks) /* Upload counter of event timer */ evt_tmr->ITCNT32 = MAX(cyc_evt_timeout - 1, 1); + k_spin_unlock(&lock, key); /* Enable event timer and start ticking */ return npcx_itim_evt_enable(); - } static void npcx_itim_evt_isr(const struct device *dev) @@ -175,11 +194,12 @@ static void npcx_itim_evt_isr(const struct device *dev) if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { k_spinlock_key_t key = k_spin_lock(&lock); - uint32_t delta_ticks = (uint32_t)((npcx_itim_get_sys_cyc64() - - cyc_sys_announced) / SYS_CYCLES_PER_TICK); + uint64_t curr = npcx_itim_get_sys_cyc64(); + uint32_t delta_ticks = (uint32_t)((curr - cyc_sys_announced) / SYS_CYCLES_PER_TICK); - /* Store announced cycles of system timer */ - cyc_sys_announced = npcx_itim_get_sys_cyc64(); + cyc_sys_announced += delta_ticks * SYS_CYCLES_PER_TICK; + last_ticks += delta_ticks; + last_elapsed = 0; k_spin_unlock(&lock, key); /* Informs kernel that specified number of ticks have elapsed */ @@ -252,11 +272,13 @@ uint32_t sys_clock_elapsed(void) k_spinlock_key_t key = k_spin_lock(&lock); uint64_t delta_cycle = npcx_itim_get_sys_cyc64() - cyc_sys_announced; + uint32_t delta_ticks = (uint32_t)delta_cycle / SYS_CYCLES_PER_TICK; + last_elapsed = delta_ticks; k_spin_unlock(&lock, key); /* Return how many ticks elapsed since last sys_clock_announce() call */ - return (uint32_t)(delta_cycle / SYS_CYCLES_PER_TICK); + return delta_ticks; } uint32_t sys_clock_cycle_get_32(void) diff --git a/drivers/timer/nrf_grtc_timer.c b/drivers/timer/nrf_grtc_timer.c new file mode 100644 index 000000000000000..dc6ac410905b194 --- /dev/null +++ b/drivers/timer/nrf_grtc_timer.c @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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) + +#define GRTC_NODE DT_NODELABEL(grtc) + +#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); + } + + 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); + + 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 9241c5b7a10044e..e0584a3c8b395ce 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 aaf83c300570754..ba00014ad45508c 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/CMakeLists.txt b/drivers/usb/CMakeLists.txt index 7a0570f146db0fc..e0d9f196b2920e9 100644 --- a/drivers/usb/CMakeLists.txt +++ b/drivers/usb/CMakeLists.txt @@ -5,3 +5,4 @@ add_subdirectory_ifdef(CONFIG_UHC_DRIVER uhc) add_subdirectory_ifdef(CONFIG_UVB uvb) add_subdirectory_ifdef(CONFIG_USB_BC12 bc12) add_subdirectory_ifdef(CONFIG_USB_DEVICE_DRIVER device) +add_subdirectory(common) diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 369b40f6fa35f78..bcccdf6b6578914 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -8,3 +8,4 @@ source "drivers/usb/udc/Kconfig" source "drivers/usb/uhc/Kconfig" source "drivers/usb/uvb/Kconfig" source "drivers/usb/device/Kconfig" +source "drivers/usb/common/Kconfig" diff --git a/drivers/usb/bc12/bc12_handlers.c b/drivers/usb/bc12/bc12_handlers.c index bf7ff8fcf39afa8..dce82695a14d30e 100644 --- a/drivers/usb/bc12/bc12_handlers.c +++ b/drivers/usb/bc12/bc12_handlers.c @@ -5,11 +5,11 @@ */ #include -#include +#include static inline int z_vrfy_bc12_set_role(const struct device *dev, enum bc12_role role) { - Z_OOPS(Z_SYSCALL_DRIVER_BC12(dev, set_role)); + K_OOPS(K_SYSCALL_DRIVER_BC12(dev, set_role)); return z_impl_bc12_set_role(dev, role); } @@ -17,8 +17,8 @@ static inline int z_vrfy_bc12_set_role(const struct device *dev, enum bc12_role static inline int z_vrfy_bc12_set_result_cb(const struct device *dev, bc12_callback_t cb, void *user_data) { - Z_OOPS(Z_SYSCALL_DRIVER_BC12(dev, set_result_cb)); - Z_OOPS(Z_SYSCALL_VERIFY_MSG(cb == NULL, "callbacks may not be set from user mode")); + K_OOPS(K_SYSCALL_DRIVER_BC12(dev, set_result_cb)); + K_OOPS(K_SYSCALL_VERIFY_MSG(cb == NULL, "callbacks may not be set from user mode")); return z_impl_bc12_set_result_cb(dev, cb, user_data); } diff --git a/drivers/usb/common/CMakeLists.txt b/drivers/usb/common/CMakeLists.txt new file mode 100644 index 000000000000000..56e4c734ced9768 --- /dev/null +++ b/drivers/usb/common/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory_ifdef(CONFIG_HAS_NRFX nrf_usbd_common) diff --git a/drivers/usb/common/Kconfig b/drivers/usb/common/Kconfig new file mode 100644 index 000000000000000..7f6a02614b8f0dd --- /dev/null +++ b/drivers/usb/common/Kconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +rsource "nrf_usbd_common/Kconfig" diff --git a/drivers/usb/common/nrf_usbd_common/CMakeLists.txt b/drivers/usb/common/nrf_usbd_common/CMakeLists.txt new file mode 100644 index 000000000000000..84952a8e5f8d7e6 --- /dev/null +++ b/drivers/usb/common/nrf_usbd_common/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_NRF_USBD_COMMON) + zephyr_library() + + zephyr_include_directories(.) + + zephyr_library_sources(nrf_usbd_common.c) +endif() diff --git a/drivers/usb/common/nrf_usbd_common/Kconfig b/drivers/usb/common/nrf_usbd_common/Kconfig new file mode 100644 index 000000000000000..ae8f631fc72ad98 --- /dev/null +++ b/drivers/usb/common/nrf_usbd_common/Kconfig @@ -0,0 +1,20 @@ +# Copyright (c) 2016-2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +module = NRF_USBD_COMMON +module-str = nRF USBD common +source "subsys/logging/Kconfig.template.log_config" + +config NRF_USBD_COMMON + bool "USBD driver" + depends on HAS_NRFX + depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_USBD)) + +config NRF_USBD_ISO_IN_ZLP + bool "Send ZLP on ISO IN when not ready" + depends on NRF_USBD_COMMON + default y + help + Controls the response of the ISO IN endpoint to an IN token when no + data is ready to be sent. When enabled, ZLP is sent when no data is + ready. When disabled, no response is sent (bus timeout occurs). diff --git a/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.c b/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.c new file mode 100644 index 000000000000000..3db193ee2f074e4 --- /dev/null +++ b/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.c @@ -0,0 +1,1623 @@ +/* + * Copyright (c) 2016 - 2023, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* This file is undergoing transition towards native Zephyr nrf USB driver. */ + +/** @cond INTERNAL_HIDDEN */ + +#include + +#include "nrf_usbd_common.h" +#include "nrf_usbd_common_errata.h" +#include +#include + +#include +LOG_MODULE_REGISTER(nrf_usbd_common, CONFIG_NRF_USBD_COMMON_LOG_LEVEL); + +#define NRF_USBD_COMMON_EPIN_CNT 9 +#define NRF_USBD_COMMON_EPOUT_CNT 9 +#define NRF_USBD_COMMON_EP_NUM(ep) (ep & 0xF) +#define NRF_USBD_COMMON_EP_IS_IN(ep) ((ep & 0x80) == 0x80) +#define NRF_USBD_COMMON_EP_IS_OUT(ep) ((ep & 0x80) == 0) +#define NRF_USBD_COMMON_EP_IS_ISO(ep) ((ep & 0xF) >= 8) + +#ifndef NRF_USBD_COMMON_ISO_DEBUG +/* Also generate information about ISOCHRONOUS events and transfers. + * Turn this off if no ISOCHRONOUS transfers are going to be debugged and this + * option generates a lot of useless messages. + */ +#define NRF_USBD_COMMON_ISO_DEBUG 1 +#endif + +#ifndef NRF_USBD_COMMON_FAILED_TRANSFERS_DEBUG +/* Also generate debug information for failed transfers. + * It might be useful but may generate a lot of useless debug messages + * in some library usages (for example when transfer is generated and the + * result is used to check whatever endpoint was busy. + */ +#define NRF_USBD_COMMON_FAILED_TRANSFERS_DEBUG 1 +#endif + +#ifndef NRF_USBD_COMMON_DMAREQ_PROCESS_DEBUG +/* Generate additional messages that mark the status inside + * @ref usbd_dmareq_process. + * It is useful to debug library internals but may generate a lot of + * useless debug messages. + */ +#define NRF_USBD_COMMON_DMAREQ_PROCESS_DEBUG 1 +#endif + +#ifndef NRF_USBD_COMMON_USE_WORKAROUND_FOR_ANOMALY_211 +/* Anomaly 211 - Device remains in SUSPEND too long when host resumes + * a bus activity (sending SOF packets) without a RESUME condition. + */ +#define NRF_USBD_COMMON_USE_WORKAROUND_FOR_ANOMALY_211 0 +#endif + +/** + * @defgroup nrf_usbd_common_int USB Device driver internal part + * @internal + * @ingroup nrf_usbd_common + * + * This part contains auxiliary internal macros, variables and functions. + * @{ + */ + +/** + * @brief Assert endpoint number validity. + * + * Internal macro to be used during program creation in debug mode. + * Generates assertion if endpoint number is not valid. + * + * @param ep Endpoint number to validity check. + */ +#define NRF_USBD_COMMON_ASSERT_EP_VALID(ep) __ASSERT_NO_MSG( \ + ((NRF_USBD_COMMON_EP_IS_IN(ep) && \ + (NRF_USBD_COMMON_EP_NUM(ep) < NRF_USBD_COMMON_EPIN_CNT)) || \ + (NRF_USBD_COMMON_EP_IS_OUT(ep) && \ + (NRF_USBD_COMMON_EP_NUM(ep) < NRF_USBD_COMMON_EPOUT_CNT)))); + +/** + * @brief Lowest position of bit for IN endpoint. + * + * The first bit position corresponding to IN endpoint. + * @sa ep2bit bit2ep + */ +#define NRF_USBD_COMMON_EPIN_BITPOS_0 0 + +/** + * @brief Lowest position of bit for OUT endpoint. + * + * The first bit position corresponding to OUT endpoint + * @sa ep2bit bit2ep + */ +#define NRF_USBD_COMMON_EPOUT_BITPOS_0 16 + +/** + * @brief Input endpoint bits mask. + */ +#define NRF_USBD_COMMON_EPIN_BIT_MASK (0xFFFFU << NRF_USBD_COMMON_EPIN_BITPOS_0) + +/** + * @brief Output endpoint bits mask. + */ +#define NRF_USBD_COMMON_EPOUT_BIT_MASK (0xFFFFU << NRF_USBD_COMMON_EPOUT_BITPOS_0) + +/** + * @brief Isochronous endpoint bit mask + */ +#define USBD_EPISO_BIT_MASK \ + ((1U << NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPOUT8)) | \ + (1U << NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPIN8))) + +/** + * @brief Auxiliary macro to change EP number into bit position. + * + * This macro is used by @ref ep2bit function but also for statically check + * the bitpos values integrity during compilation. + * + * @param[in] ep Endpoint number. + * @return Endpoint bit position. + */ +#define NRF_USBD_COMMON_EP_BITPOS(ep) ((NRF_USBD_COMMON_EP_IS_IN(ep) \ + ? NRF_USBD_COMMON_EPIN_BITPOS_0 : NRF_USBD_COMMON_EPOUT_BITPOS_0) \ + + NRF_USBD_COMMON_EP_NUM(ep)) + +/** + * @brief Helper macro for creating an endpoint transfer event. + * + * @param[in] name Name of the created transfer event variable. + * @param[in] endpoint Endpoint number. + * @param[in] ep_stat Endpoint state to report. + * + * @return Initialized event constant variable. + */ +#define NRF_USBD_COMMON_EP_TRANSFER_EVENT(name, endpont, ep_stat) \ + const nrf_usbd_common_evt_t name = {NRF_USBD_COMMON_EVT_EPTRANSFER, \ + .data = {.eptransfer = {.ep = endpont, .status = ep_stat}}} + +/* Check it the bit positions values match defined DATAEPSTATUS bit positions */ +BUILD_ASSERT( + (NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPIN1) == USBD_EPDATASTATUS_EPIN1_Pos) && + (NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPIN2) == USBD_EPDATASTATUS_EPIN2_Pos) && + (NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPIN3) == USBD_EPDATASTATUS_EPIN3_Pos) && + (NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPIN4) == USBD_EPDATASTATUS_EPIN4_Pos) && + (NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPIN5) == USBD_EPDATASTATUS_EPIN5_Pos) && + (NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPIN6) == USBD_EPDATASTATUS_EPIN6_Pos) && + (NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPIN7) == USBD_EPDATASTATUS_EPIN7_Pos) && + (NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPOUT1) == USBD_EPDATASTATUS_EPOUT1_Pos) && + (NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPOUT2) == USBD_EPDATASTATUS_EPOUT2_Pos) && + (NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPOUT3) == USBD_EPDATASTATUS_EPOUT3_Pos) && + (NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPOUT4) == USBD_EPDATASTATUS_EPOUT4_Pos) && + (NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPOUT5) == USBD_EPDATASTATUS_EPOUT5_Pos) && + (NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPOUT6) == USBD_EPDATASTATUS_EPOUT6_Pos) && + (NRF_USBD_COMMON_EP_BITPOS(NRF_USBD_COMMON_EPOUT7) == USBD_EPDATASTATUS_EPOUT7_Pos), + "NRF_USBD_COMMON bit positions do not match hardware" +); + +/** + * @brief Current driver state. + */ +static nrfx_drv_state_t m_drv_state = NRFX_DRV_STATE_UNINITIALIZED; + +/** + * @brief Event handler for the driver. + * + * Event handler that would be called on events. + * + * @note Currently it cannot be null if any interrupt is activated. + */ +static nrf_usbd_common_event_handler_t m_event_handler; + +/** + * @brief Detected state of the bus. + * + * Internal state changed in interrupts handling when + * RESUME or SUSPEND event is processed. + * + * Values: + * - true - bus suspended + * - false - ongoing normal communication on the bus + * + * @note This is only the bus state and does not mean that the peripheral is in suspend state. + */ +static volatile bool m_bus_suspend; + +/** + * @brief Direction of last received Setup transfer. + * + * This variable is used to redirect internal setup data event + * into selected endpoint (IN or OUT). + */ +static nrf_usbd_common_ep_t m_last_setup_dir; + +/** + * @brief Mark endpoint readiness for DMA transfer. + * + * Bits in this variable are cleared and set in interrupts. + * 1 means that endpoint is ready for DMA transfer. + * 0 means that DMA transfer cannot be performed on selected endpoint. + */ +static uint32_t m_ep_ready; + +/** + * @brief Mark endpoint with prepared data to transfer by DMA. + * + * This variable can be set in interrupt context or within critical section. + * It would be cleared only from USBD interrupt. + * + * Mask prepared USBD data for transmission. + * It is cleared when no more data to transmit left. + */ +static uint32_t m_ep_dma_waiting; + +/* Semaphore to guard EasyDMA access. + * In USBD there is only one DMA channel working in background, and new transfer + * cannot be started when there is ongoing transfer on any other channel. + */ +static K_SEM_DEFINE(dma_available, 1, 1); + +/* Endpoint on which DMA was started. */ +static nrf_usbd_common_ep_t dma_ep; + +/** + * @brief Tracks whether total bytes transferred by DMA is even or odd. + */ +static uint8_t m_dma_odd; + +/** + * @brief First time enabling after reset. Used in nRF52 errata 223. + */ +static bool m_first_enable = true; + +/** + * @brief The structure that would hold transfer configuration to every endpoint + * + * The structure that holds all the data required by the endpoint to proceed + * with LIST functionality and generate quick callback directly when data + * buffer is ready. + */ +typedef struct { + nrf_usbd_common_transfer_t transfer_state; + bool more_transactions; + /** Number of transferred bytes in the current transfer. */ + size_t transfer_cnt; + /** Configured endpoint size. */ + uint16_t max_packet_size; + /** NRFX_SUCCESS or error code, never NRFX_ERROR_BUSY - this one is calculated. */ + nrf_usbd_common_ep_status_t status; +} usbd_ep_state_t; + +/** + * @brief The array of transfer configurations for the endpoints. + * + * The status of the transfer on each endpoint. + */ +static struct { + usbd_ep_state_t ep_out[NRF_USBD_COMMON_EPOUT_CNT]; /*!< Status for OUT endpoints. */ + usbd_ep_state_t ep_in[NRF_USBD_COMMON_EPIN_CNT]; /*!< Status for IN endpoints. */ +} m_ep_state; + +#define NRF_USBD_COMMON_FEEDER_BUFFER_SIZE NRF_USBD_COMMON_EPSIZE + +/** + * @brief Buffer used to send data directly from FLASH. + * + * This is internal buffer that would be used to emulate the possibility + * to transfer data directly from FLASH. + * We do not have to care about the source of data when calling transfer functions. + * + * We do not need more buffers that one, because only one transfer can be pending + * at once. + */ +static uint32_t m_tx_buffer[NRFX_CEIL_DIV(NRF_USBD_COMMON_FEEDER_BUFFER_SIZE, sizeof(uint32_t))]; + +/* Early declaration. Documentation above definition. */ +static void usbd_dmareq_process(void); +static inline void usbd_int_rise(void); +static void nrf_usbd_common_stop(void); + +/* Get EasyDMA end event address for given endpoint */ +static volatile uint32_t *usbd_ep_to_endevent(nrf_usbd_common_ep_t ep) +{ + int ep_in = NRF_USBD_COMMON_EP_IS_IN(ep); + int ep_num = NRF_USBD_COMMON_EP_NUM(ep); + + NRF_USBD_COMMON_ASSERT_EP_VALID(ep); + + if (!NRF_USBD_COMMON_EP_IS_ISO(ep_num)) { + if (ep_in) { + return &NRF_USBD->EVENTS_ENDEPIN[ep_num]; + } else { + return &NRF_USBD->EVENTS_ENDEPOUT[ep_num]; + } + } + + return ep_in ? &NRF_USBD->EVENTS_ENDISOIN : &NRF_USBD->EVENTS_ENDISOOUT; +} + +/* Return number of bytes last transferred by EasyDMA on given endpoint */ +static uint32_t usbd_ep_amount_get(nrf_usbd_common_ep_t ep) +{ + int ep_in = NRF_USBD_COMMON_EP_IS_IN(ep); + int ep_num = NRF_USBD_COMMON_EP_NUM(ep); + + NRF_USBD_COMMON_ASSERT_EP_VALID(ep); + + if (!NRF_USBD_COMMON_EP_IS_ISO(ep_num)) { + if (ep_in) { + return NRF_USBD->EPIN[ep_num].AMOUNT; + } else { + return NRF_USBD->EPOUT[ep_num].AMOUNT; + } + } + + return ep_in ? NRF_USBD->ISOIN.AMOUNT : NRF_USBD->ISOOUT.AMOUNT; +} + +/* Start EasyDMA on given endpoint */ +static void usbd_ep_dma_start(nrf_usbd_common_ep_t ep, uint32_t addr, size_t len) +{ + int ep_in = NRF_USBD_COMMON_EP_IS_IN(ep); + int ep_num = NRF_USBD_COMMON_EP_NUM(ep); + + NRF_USBD_COMMON_ASSERT_EP_VALID(ep); + + if (!NRF_USBD_COMMON_EP_IS_ISO(ep_num)) { + if (ep_in) { + NRF_USBD->EPIN[ep_num].PTR = addr; + NRF_USBD->EPIN[ep_num].MAXCNT = len; + NRF_USBD->TASKS_STARTEPIN[ep_num] = 1; + } else { + NRF_USBD->EPOUT[ep_num].PTR = addr; + NRF_USBD->EPOUT[ep_num].MAXCNT = len; + NRF_USBD->TASKS_STARTEPOUT[ep_num] = 1; + } + } else if (ep_in) { + NRF_USBD->ISOIN.PTR = addr; + NRF_USBD->ISOIN.MAXCNT = len; + NRF_USBD->TASKS_STARTISOIN = 1; + } else { + NRF_USBD->ISOOUT.PTR = addr; + NRF_USBD->ISOOUT.MAXCNT = len; + NRF_USBD->TASKS_STARTISOOUT = 1; + } +} + +static bool nrf_usbd_common_consumer(nrf_usbd_common_ep_transfer_t *p_next, + nrf_usbd_common_transfer_t *p_transfer, + size_t ep_size, size_t data_size) +{ + __ASSERT_NO_MSG(ep_size >= data_size); + __ASSERT_NO_MSG((p_transfer->p_data.rx == NULL) || nrfx_is_in_ram(p_transfer->p_data.rx)); + + size_t size = p_transfer->size; + + if (size < data_size) { + LOG_DBG("consumer: buffer too small: r: %u, l: %u", data_size, size); + /* Buffer size to small */ + p_next->size = 0; + p_next->p_data = p_transfer->p_data; + } else { + p_next->size = data_size; + p_next->p_data = p_transfer->p_data; + size -= data_size; + p_transfer->size = size; + p_transfer->p_data.addr += data_size; + } + return (ep_size == data_size) && (size != 0); +} + +static bool nrf_usbd_common_feeder(nrf_usbd_common_ep_transfer_t *p_next, + nrf_usbd_common_transfer_t *p_transfer, + size_t ep_size) +{ + size_t tx_size = p_transfer->size; + + if (tx_size > ep_size) { + tx_size = ep_size; + } + + if (!nrfx_is_in_ram(p_transfer->p_data.tx)) { + __ASSERT_NO_MSG(tx_size <= NRF_USBD_COMMON_FEEDER_BUFFER_SIZE); + memcpy(m_tx_buffer, (p_transfer->p_data.tx), tx_size); + p_next->p_data.tx = m_tx_buffer; + } else { + p_next->p_data = p_transfer->p_data; + } + + p_next->size = tx_size; + + p_transfer->size -= tx_size; + p_transfer->p_data.addr += tx_size; + + if (p_transfer->flags & NRF_USBD_COMMON_TRANSFER_ZLP_FLAG) { + return (tx_size != 0); + } else { + return (p_transfer->size != 0); + } +} + +/** + * @brief Change Driver endpoint number to HAL endpoint number. + * + * @param ep Driver endpoint identifier. + * + * @return Endpoint identifier in HAL. + * + * @sa nrf_usbd_common_ep_from_hal + */ +static inline uint8_t ep_to_hal(nrf_usbd_common_ep_t ep) +{ + NRF_USBD_COMMON_ASSERT_EP_VALID(ep); + return (uint8_t)ep; +} + +/** + * @brief Access selected endpoint state structure. + * + * Function used to change or just read the state of selected endpoint. + * It is used for internal transmission state. + * + * @param ep Endpoint number. + */ +static inline usbd_ep_state_t *ep_state_access(nrf_usbd_common_ep_t ep) +{ + NRF_USBD_COMMON_ASSERT_EP_VALID(ep); + return ((NRF_USBD_COMMON_EP_IS_IN(ep) ? m_ep_state.ep_in : m_ep_state.ep_out) + + NRF_USBD_COMMON_EP_NUM(ep)); +} + +/** + * @brief Change endpoint number to bit position. + * + * Bit positions are defined the same way as they are placed in DATAEPSTATUS register, + * but bits for endpoint 0 are included. + * + * @param ep Endpoint number. + * + * @return Bit position related to the given endpoint number. + * + * @sa bit2ep + */ +static inline uint8_t ep2bit(nrf_usbd_common_ep_t ep) +{ + NRF_USBD_COMMON_ASSERT_EP_VALID(ep); + return NRF_USBD_COMMON_EP_BITPOS(ep); +} + +/** + * @brief Change bit position to endpoint number. + * + * @param bitpos Bit position. + * + * @return Endpoint number corresponding to given bit position. + * + * @sa ep2bit + */ +static inline nrf_usbd_common_ep_t bit2ep(uint8_t bitpos) +{ + BUILD_ASSERT(NRF_USBD_COMMON_EPOUT_BITPOS_0 > NRF_USBD_COMMON_EPIN_BITPOS_0, + "OUT endpoint bits should be higher than IN endpoint bits"); + return (nrf_usbd_common_ep_t)((bitpos >= NRF_USBD_COMMON_EPOUT_BITPOS_0) + ? NRF_USBD_COMMON_EPOUT(bitpos - NRF_USBD_COMMON_EPOUT_BITPOS_0) + : NRF_USBD_COMMON_EPIN(bitpos)); +} + +/** + * @brief Mark that EasyDMA is working. + * + * Internal function to set the flag informing about EasyDMA transfer pending. + * This function is called always just after the EasyDMA transfer is started. + */ +static inline void usbd_dma_pending_set(void) +{ + if (nrf_usbd_common_errata_199()) { + *((volatile uint32_t *)0x40027C1C) = 0x00000082; + } +} + +/** + * @brief Mark that EasyDMA is free. + * + * Internal function to clear the flag informing about EasyDMA transfer pending. + * This function is called always just after the finished EasyDMA transfer is detected. + */ +static inline void usbd_dma_pending_clear(void) +{ + if (nrf_usbd_common_errata_199()) { + *((volatile uint32_t *)0x40027C1C) = 0x00000000; + } +} + +/** + * @brief Abort pending transfer on selected endpoint. + * + * @param ep Endpoint number. + * + * @note + * This function locks interrupts that may be costly. + * It is good idea to test if the endpoint is still busy before calling this function: + * @code + (m_ep_dma_waiting & (1U << ep2bit(ep))) + * @endcode + * This function would check it again, but it makes it inside critical section. + */ +static inline void usbd_ep_abort(nrf_usbd_common_ep_t ep) +{ + unsigned int irq_lock_key = irq_lock(); + usbd_ep_state_t *p_state = ep_state_access(ep); + + if (NRF_USBD_COMMON_EP_IS_OUT(ep)) { + /* Host -> Device */ + if ((~m_ep_dma_waiting) & (1U << ep2bit(ep))) { + /* If the bit in m_ep_dma_waiting in cleared - nothing would be + * processed inside transfer processing + */ + nrf_usbd_common_transfer_out_drop(ep); + } else { + p_state->more_transactions = false; + m_ep_dma_waiting &= ~(1U << ep2bit(ep)); + m_ep_ready &= ~(1U << ep2bit(ep)); + } + /* Aborted */ + p_state->status = NRF_USBD_COMMON_EP_ABORTED; + } else { + if (!NRF_USBD_COMMON_EP_IS_ISO(ep)) { + /* Workaround: Disarm the endpoint if there is any data buffered. */ + if (ep != NRF_USBD_COMMON_EPIN0) { + *((volatile uint32_t *)((uint32_t)(NRF_USBD) + 0x800)) = + 0x7B6 + (2u * (NRF_USBD_COMMON_EP_NUM(ep) - 1)); + uint8_t temp = + *((volatile uint32_t *)((uint32_t)(NRF_USBD) + 0x804)); + temp |= (1U << 1); + *((volatile uint32_t *)((uint32_t)(NRF_USBD) + 0x804)) |= temp; + (void)(*((volatile uint32_t *)((uint32_t)(NRF_USBD) + 0x804))); + } else { + *((volatile uint32_t *)((uint32_t)(NRF_USBD) + 0x800)) = 0x7B4; + uint8_t temp = + *((volatile uint32_t *)((uint32_t)(NRF_USBD) + 0x804)); + temp |= (1U << 2); + *((volatile uint32_t *)((uint32_t)(NRF_USBD) + 0x804)) |= temp; + (void)(*((volatile uint32_t *)((uint32_t)(NRF_USBD) + 0x804))); + } + } + if ((m_ep_dma_waiting | (~m_ep_ready)) & (1U << ep2bit(ep))) { + /* Device -> Host */ + m_ep_dma_waiting &= ~(1U << ep2bit(ep)); + m_ep_ready |= 1U << ep2bit(ep); + + p_state->more_transactions = false; + p_state->status = NRF_USBD_COMMON_EP_ABORTED; + NRF_USBD_COMMON_EP_TRANSFER_EVENT(evt, ep, NRF_USBD_COMMON_EP_ABORTED); + m_event_handler(&evt); + } + } + + irq_unlock(irq_lock_key); +} + +void nrf_usbd_common_ep_abort(nrf_usbd_common_ep_t ep) +{ + /* Only abort if there is no active DMA */ + k_sem_take(&dma_available, K_FOREVER); + usbd_ep_abort(ep); + k_sem_give(&dma_available); + + /* This function was holding DMA semaphore and could potentially prevent + * next DMA from executing. Fire IRQ handler to check if any DMA needs + * to be started. + */ + usbd_int_rise(); +} + +/** + * @brief Abort all pending endpoints. + * + * Function aborts all pending endpoint transfers. + */ +static void usbd_ep_abort_all(void) +{ + uint32_t ep_waiting = m_ep_dma_waiting | (m_ep_ready & NRF_USBD_COMMON_EPOUT_BIT_MASK); + + while (ep_waiting != 0) { + uint8_t bitpos = NRF_CTZ(ep_waiting); + + if (!NRF_USBD_COMMON_EP_IS_ISO(bit2ep(bitpos))) { + usbd_ep_abort(bit2ep(bitpos)); + } + ep_waiting &= ~(1U << bitpos); + } + + m_ep_ready = (((1U << NRF_USBD_COMMON_EPIN_CNT) - 1U) << NRF_USBD_COMMON_EPIN_BITPOS_0); +} + +/** + * @brief Force the USBD interrupt into pending state. + * + * This function is used to force USBD interrupt to be processed right now. + * It makes it possible to process all EasyDMA access on one thread priority level. + */ +static inline void usbd_int_rise(void) +{ + NVIC_SetPendingIRQ(USBD_IRQn); +} + +/** + * @name USBD interrupt runtimes. + * + * Interrupt runtimes that would be vectorized using @ref m_isr. + * @{ + */ + +static void ev_usbreset_handler(void) +{ + m_bus_suspend = false; + m_last_setup_dir = NRF_USBD_COMMON_EPOUT0; + + const nrf_usbd_common_evt_t evt = {.type = NRF_USBD_COMMON_EVT_RESET}; + + m_event_handler(&evt); +} + +static void nrf_usbd_dma_finished(nrf_usbd_common_ep_t ep) +{ + /* DMA finished, track if total bytes transferred is even or odd */ + m_dma_odd ^= usbd_ep_amount_get(ep) & 1; + usbd_dma_pending_clear(); + k_sem_give(&dma_available); + + usbd_ep_state_t *p_state = ep_state_access(ep); + + if (p_state->status == NRF_USBD_COMMON_EP_ABORTED) { + /* Clear transfer information just in case */ + m_ep_dma_waiting &= ~(1U << ep2bit(ep)); + } else if (!p_state->more_transactions) { + m_ep_dma_waiting &= ~(1U << ep2bit(ep)); + + if (NRF_USBD_COMMON_EP_IS_OUT(ep) || (ep == NRF_USBD_COMMON_EPIN8)) { + /* Send event to the user - for an ISO IN or any OUT endpoint, + * the whole transfer is finished in this moment + */ + NRF_USBD_COMMON_EP_TRANSFER_EVENT(evt, ep, NRF_USBD_COMMON_EP_OK); + m_event_handler(&evt); + } + } else if (ep == NRF_USBD_COMMON_EPOUT0) { + nrf_usbd_common_setup_data_clear(); + } +} + +static void ev_sof_handler(void) +{ + nrf_usbd_common_evt_t evt = { + NRF_USBD_COMMON_EVT_SOF, + .data = {.sof = {.framecnt = (uint16_t)NRF_USBD->FRAMECNTR}}}; + + /* Process isochronous endpoints */ + uint32_t iso_ready_mask = (1U << ep2bit(NRF_USBD_COMMON_EPIN8)); + + /* SIZE.ISOOUT is 0 only when no packet was received at all */ + if (NRF_USBD->SIZE.ISOOUT) { + iso_ready_mask |= (1U << ep2bit(NRF_USBD_COMMON_EPOUT8)); + } + m_ep_ready |= iso_ready_mask; + + m_event_handler(&evt); +} + +/** + * @brief React on data transfer finished. + * + * Auxiliary internal function. + * @param ep Endpoint number. + * @param bitpos Bit position for selected endpoint number. + */ +static void usbd_ep_data_handler(nrf_usbd_common_ep_t ep, uint8_t bitpos) +{ + LOG_DBG("USBD event: EndpointData: %x", ep); + /* Mark endpoint ready for next DMA access */ + m_ep_ready |= (1U << bitpos); + + if (NRF_USBD_COMMON_EP_IS_IN(ep)) { + /* IN endpoint (Device -> Host) */ + if (0 == (m_ep_dma_waiting & (1U << bitpos))) { + LOG_DBG("USBD event: EndpointData: In finished"); + /* No more data to be send - transmission finished */ + NRF_USBD_COMMON_EP_TRANSFER_EVENT(evt, ep, NRF_USBD_COMMON_EP_OK); + m_event_handler(&evt); + } + } else { + /* OUT endpoint (Host -> Device) */ + if (0 == (m_ep_dma_waiting & (1U << bitpos))) { + LOG_DBG("USBD event: EndpointData: Out waiting"); + /* No buffer prepared - send event to the application */ + NRF_USBD_COMMON_EP_TRANSFER_EVENT(evt, ep, NRF_USBD_COMMON_EP_WAITING); + m_event_handler(&evt); + } + } +} + +static void ev_setup_handler(void) +{ + LOG_DBG("USBD event: Setup (rt:%.2x r:%.2x v:%.4x i:%.4x l:%u )", + NRF_USBD->BMREQUESTTYPE, NRF_USBD->BREQUEST, + NRF_USBD->WVALUEL | (NRF_USBD->WVALUEH << 8), + NRF_USBD->WINDEXL | (NRF_USBD->WINDEXH << 8), + NRF_USBD->WLENGTHL | (NRF_USBD->WLENGTHH << 8)); + uint8_t bmRequestType = NRF_USBD->BMREQUESTTYPE; + + m_last_setup_dir = + ((bmRequestType & USBD_BMREQUESTTYPE_DIRECTION_Msk) == + (USBD_BMREQUESTTYPE_DIRECTION_HostToDevice << USBD_BMREQUESTTYPE_DIRECTION_Pos)) + ? NRF_USBD_COMMON_EPOUT0 + : NRF_USBD_COMMON_EPIN0; + + m_ep_dma_waiting &= ~((1U << ep2bit(NRF_USBD_COMMON_EPOUT0)) | + (1U << ep2bit(NRF_USBD_COMMON_EPIN0))); + m_ep_ready &= ~(1U << ep2bit(NRF_USBD_COMMON_EPOUT0)); + m_ep_ready |= 1U << ep2bit(NRF_USBD_COMMON_EPIN0); + + const nrf_usbd_common_evt_t evt = {.type = NRF_USBD_COMMON_EVT_SETUP}; + + m_event_handler(&evt); +} + +static void ev_usbevent_handler(void) +{ + uint32_t event = NRF_USBD->EVENTCAUSE; + + /* Clear handled events */ + NRF_USBD->EVENTCAUSE = event; + + if (event & USBD_EVENTCAUSE_ISOOUTCRC_Msk) { + LOG_DBG("USBD event: ISOOUTCRC"); + /* Currently no support */ + } + if (event & USBD_EVENTCAUSE_SUSPEND_Msk) { + LOG_DBG("USBD event: SUSPEND"); + m_bus_suspend = true; + const nrf_usbd_common_evt_t evt = {.type = NRF_USBD_COMMON_EVT_SUSPEND}; + + m_event_handler(&evt); + } + if (event & USBD_EVENTCAUSE_RESUME_Msk) { + LOG_DBG("USBD event: RESUME"); + m_bus_suspend = false; + const nrf_usbd_common_evt_t evt = {.type = NRF_USBD_COMMON_EVT_RESUME}; + + m_event_handler(&evt); + } + if (event & USBD_EVENTCAUSE_USBWUALLOWED_Msk) { + LOG_DBG("USBD event: WUREQ (%s)", m_bus_suspend ? "In Suspend" : "Active"); + if (m_bus_suspend) { + __ASSERT_NO_MSG(!nrf_usbd_common_suspend_check()); + m_bus_suspend = false; + + NRF_USBD->DPDMVALUE = USBD_DPDMVALUE_STATE_Resume + << USBD_DPDMVALUE_STATE_Pos; + NRF_USBD->TASKS_DPDMDRIVE = 1; + + const nrf_usbd_common_evt_t evt = {.type = NRF_USBD_COMMON_EVT_WUREQ}; + + m_event_handler(&evt); + } + } +} + +static void ev_epdata_handler(uint32_t dataepstatus) +{ + LOG_DBG("USBD event: EndpointEPStatus: %x", dataepstatus); + + /* All finished endpoint have to be marked as busy */ + while (dataepstatus) { + uint8_t bitpos = NRF_CTZ(dataepstatus); + nrf_usbd_common_ep_t ep = bit2ep(bitpos); + + dataepstatus &= ~(1UL << bitpos); + + (void)(usbd_ep_data_handler(ep, bitpos)); + } +} + +/** + * @brief Function to select the endpoint to start. + * + * Function that realizes algorithm to schedule right channel for EasyDMA transfer. + * It gets a variable with flags for the endpoints currently requiring transfer. + * + * @param[in] req Bit flags for channels currently requiring transfer. + * Bits 0...8 used for IN endpoints. + * Bits 16...24 used for OUT endpoints. + * @note + * This function would be never called with 0 as a @c req argument. + * @return The bit number of the endpoint that should be processed now. + */ +static uint8_t usbd_dma_scheduler_algorithm(uint32_t req) +{ + /* Only prioritized scheduling mode is supported. */ + return NRF_CTZ(req); +} + +/** + * @brief Get the size of isochronous endpoint. + * + * The size of isochronous endpoint is configurable. + * This function returns the size of isochronous buffer taking into account + * current configuration. + * + * @param[in] ep Endpoint number. + * + * @return The size of endpoint buffer. + */ +static inline size_t usbd_ep_iso_capacity(nrf_usbd_common_ep_t ep) +{ + (void)ep; + + if (NRF_USBD->ISOSPLIT == USBD_ISOSPLIT_SPLIT_HalfIN << USBD_ISOSPLIT_SPLIT_Pos) { + return NRF_USBD_COMMON_ISOSIZE / 2; + } + return NRF_USBD_COMMON_ISOSIZE; +} + +/** + * @brief Process all DMA requests. + * + * Function that have to be called from USBD interrupt handler. + * It have to be called when all the interrupts connected with endpoints transfer + * and DMA transfer are already handled. + */ +static void usbd_dmareq_process(void) +{ + if ((m_ep_dma_waiting & m_ep_ready) && + (k_sem_take(&dma_available, K_NO_WAIT) == 0)) { + uint32_t req; + + while (0 != (req = m_ep_dma_waiting & m_ep_ready)) { + uint8_t pos; + + if (NRFX_USBD_CONFIG_DMASCHEDULER_ISO_BOOST && + ((req & USBD_EPISO_BIT_MASK) != 0)) { + pos = usbd_dma_scheduler_algorithm(req & USBD_EPISO_BIT_MASK); + } else { + pos = usbd_dma_scheduler_algorithm(req); + } + nrf_usbd_common_ep_t ep = bit2ep(pos); + usbd_ep_state_t *p_state = ep_state_access(ep); + + nrf_usbd_common_ep_transfer_t transfer; + bool continue_transfer; + + __ASSERT_NO_MSG(p_state->more_transactions); + + if (NRF_USBD_COMMON_EP_IS_IN(ep)) { + /* Device -> Host */ + continue_transfer = nrf_usbd_common_feeder( + &transfer, &p_state->transfer_state, + p_state->max_packet_size); + } else { + /* Host -> Device */ + const size_t rx_size = nrf_usbd_common_epout_size_get(ep); + + continue_transfer = nrf_usbd_common_consumer( + &transfer, &p_state->transfer_state, + p_state->max_packet_size, rx_size); + + if (transfer.p_data.rx == NULL) { + /* Dropping transfer - allow processing */ + __ASSERT_NO_MSG(transfer.size == 0); + } else if (transfer.size < rx_size) { + LOG_DBG("Endpoint %x overload (r: %u, e: %u)", ep, + rx_size, transfer.size); + p_state->status = NRF_USBD_COMMON_EP_OVERLOAD; + m_ep_dma_waiting &= ~(1U << pos); + NRF_USBD_COMMON_EP_TRANSFER_EVENT(evt, ep, + NRF_USBD_COMMON_EP_OVERLOAD); + m_event_handler(&evt); + /* This endpoint will not be transmitted now, repeat the + * loop + */ + continue; + } else { + /* Nothing to do - only check integrity if assertions are + * enabled + */ + __ASSERT_NO_MSG(transfer.size == rx_size); + } + } + + if (!continue_transfer) { + p_state->more_transactions = false; + } + + usbd_dma_pending_set(); + m_ep_ready &= ~(1U << pos); + if (NRF_USBD_COMMON_ISO_DEBUG || (!NRF_USBD_COMMON_EP_IS_ISO(ep))) { + LOG_DBG("USB DMA process: Starting transfer on EP: %x, size: %u", + ep, transfer.size); + } + /* Update number of currently transferred bytes */ + p_state->transfer_cnt += transfer.size; + /* Start transfer to the endpoint buffer */ + dma_ep = ep; + usbd_ep_dma_start(ep, transfer.p_data.addr, transfer.size); + + /* Transfer started - exit the loop */ + return; + } + k_sem_give(&dma_available); + } else { + if (NRF_USBD_COMMON_DMAREQ_PROCESS_DEBUG) { + LOG_DBG("USB DMA process - EasyDMA busy"); + } + } +} + +/** + * @brief Begin errata 171. + */ +static inline void usbd_errata_171_begin(void) +{ + unsigned int irq_lock_key = irq_lock(); + + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } else { + *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0; + } + + irq_unlock(irq_lock_key); +} + +/** + * @brief End errata 171. + */ +static inline void usbd_errata_171_end(void) +{ + unsigned int irq_lock_key = irq_lock(); + + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006EC14)) = 0x00000000; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } else { + *((volatile uint32_t *)(0x4006EC14)) = 0x00000000; + } + + irq_unlock(irq_lock_key); +} + +/** + * @brief Begin erratas 187 and 211. + */ +static inline void usbd_errata_187_211_begin(void) +{ + unsigned int irq_lock_key = irq_lock(); + + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006ED14)) = 0x00000003; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } else { + *((volatile uint32_t *)(0x4006ED14)) = 0x00000003; + } + + irq_unlock(irq_lock_key); +} + +/** + * @brief End erratas 187 and 211. + */ +static inline void usbd_errata_187_211_end(void) +{ + unsigned int irq_lock_key = irq_lock(); + + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006ED14)) = 0x00000000; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } else { + *((volatile uint32_t *)(0x4006ED14)) = 0x00000000; + } + + irq_unlock(irq_lock_key); +} + +/** + * @brief Enable USBD peripheral. + */ +static void usbd_enable(void) +{ + if (nrf_usbd_common_errata_187()) { + usbd_errata_187_211_begin(); + } + + if (nrf_usbd_common_errata_171()) { + usbd_errata_171_begin(); + } + + /* Enable the peripheral */ + NRF_USBD->ENABLE = 1; + + /* Waiting for peripheral to enable, this should take a few us */ + while ((NRF_USBD->EVENTCAUSE & USBD_EVENTCAUSE_READY_Msk) == 0) { + } + NRF_USBD->EVENTCAUSE = USBD_EVENTCAUSE_READY_Msk; + + if (nrf_usbd_common_errata_171()) { + usbd_errata_171_end(); + } + + if (nrf_usbd_common_errata_187()) { + usbd_errata_187_211_end(); + } +} +/** @} */ + +/** + * @name Interrupt handlers + * + * @{ + */ +void nrf_usbd_common_irq_handler(void) +{ + volatile uint32_t *dma_endevent; + uint32_t epdatastatus = 0; + + /* Clear EPDATA event and only then get and clear EPDATASTATUS to make + * sure we don't miss any event. + */ + if (NRF_USBD->EVENTS_EPDATA) { + NRF_USBD->EVENTS_EPDATA = 0; + epdatastatus = NRF_USBD->EPDATASTATUS; + NRF_USBD->EPDATASTATUS = epdatastatus; + } + + /* Use common variable to store EP0DATADONE processing needed flag */ + if (NRF_USBD->EVENTS_EP0DATADONE) { + NRF_USBD->EVENTS_EP0DATADONE = 0; + epdatastatus |= BIT(ep2bit(m_last_setup_dir)); + } + + /* Check DMA end event only for last enabled DMA channel. Other channels + * cannot be active and there's no harm in rechecking the event multiple + * times (it is not a problem to check it even if DMA is not active). + * + * It is important to check DMA and handle DMA finished event before + * handling acknowledged data transfer bits (epdatastatus) to avoid + * a race condition between interrupt handler and host IN token. + */ + dma_endevent = usbd_ep_to_endevent(dma_ep); + if (*dma_endevent) { + *dma_endevent = 0; + nrf_usbd_dma_finished(dma_ep); + } + + /* Process acknowledged transfers so we can prepare next DMA (if any) */ + ev_epdata_handler(epdatastatus); + + if (NRF_USBD->EVENTS_USBRESET) { + NRF_USBD->EVENTS_USBRESET = 0; + ev_usbreset_handler(); + } + + /* Always check and clear SOF but call handler only if SOF interrupt + * is actually enabled. + */ + if (NRF_USBD->EVENTS_SOF) { + NRF_USBD->EVENTS_SOF = 0; + if (NRF_USBD->INTENSET & USBD_INTEN_SOF_Msk) { + ev_sof_handler(); + } + } + + if (NRF_USBD->EVENTS_USBEVENT) { + NRF_USBD->EVENTS_USBEVENT = 0; + ev_usbevent_handler(); + } + + /* Handle SETUP only if there is no active DMA on EP0 */ + if (unlikely(NRF_USBD->EVENTS_EP0SETUP) && + (k_sem_count_get(&dma_available) || + (dma_ep != NRF_USBD_COMMON_EPIN0 && dma_ep != NRF_USBD_COMMON_EPOUT0))) { + NRF_USBD->EVENTS_EP0SETUP = 0; + ev_setup_handler(); + } + + usbd_dmareq_process(); +} + +/** @} */ +/** @} */ + +nrfx_err_t nrf_usbd_common_init(nrf_usbd_common_event_handler_t event_handler) +{ + __ASSERT_NO_MSG(event_handler); + + if (m_drv_state != NRFX_DRV_STATE_UNINITIALIZED) { + return NRFX_ERROR_INVALID_STATE; + } + + m_event_handler = event_handler; + m_drv_state = NRFX_DRV_STATE_INITIALIZED; + + uint8_t n; + + for (n = 0; n < NRF_USBD_COMMON_EPIN_CNT; ++n) { + nrf_usbd_common_ep_t ep = NRF_USBD_COMMON_EPIN(n); + + nrf_usbd_common_ep_max_packet_size_set(ep, NRF_USBD_COMMON_EP_IS_ISO(ep) ? + (NRF_USBD_COMMON_ISOSIZE / 2) : NRF_USBD_COMMON_EPSIZE); + usbd_ep_state_t *p_state = ep_state_access(ep); + + p_state->status = NRF_USBD_COMMON_EP_OK; + p_state->more_transactions = false; + p_state->transfer_cnt = 0; + } + for (n = 0; n < NRF_USBD_COMMON_EPOUT_CNT; ++n) { + nrf_usbd_common_ep_t ep = NRF_USBD_COMMON_EPOUT(n); + + nrf_usbd_common_ep_max_packet_size_set(ep, NRF_USBD_COMMON_EP_IS_ISO(ep) ? + (NRF_USBD_COMMON_ISOSIZE / 2) : NRF_USBD_COMMON_EPSIZE); + usbd_ep_state_t *p_state = ep_state_access(ep); + + p_state->status = NRF_USBD_COMMON_EP_OK; + p_state->more_transactions = false; + p_state->transfer_cnt = 0; + } + + return NRFX_SUCCESS; +} + +void nrf_usbd_common_uninit(void) +{ + __ASSERT_NO_MSG(m_drv_state == NRFX_DRV_STATE_INITIALIZED); + + m_event_handler = NULL; + m_drv_state = NRFX_DRV_STATE_UNINITIALIZED; +} + +void nrf_usbd_common_enable(void) +{ + __ASSERT_NO_MSG(m_drv_state == NRFX_DRV_STATE_INITIALIZED); + + /* Prepare for READY event receiving */ + NRF_USBD->EVENTCAUSE = USBD_EVENTCAUSE_READY_Msk; + + usbd_enable(); + + if (nrf_usbd_common_errata_223() && m_first_enable) { + NRF_USBD->ENABLE = 0; + + usbd_enable(); + + m_first_enable = false; + } + +#if NRF_USBD_COMMON_USE_WORKAROUND_FOR_ANOMALY_211 + if (nrf_usbd_common_errata_187() || nrf_usbd_common_errata_211()) +#else + if (nrf_usbd_common_errata_187()) +#endif + { + usbd_errata_187_211_begin(); + } + + if (nrf_usbd_common_errata_166()) { + *((volatile uint32_t *)((uint32_t)(NRF_USBD) + 0x800)) = 0x7E3; + *((volatile uint32_t *)((uint32_t)(NRF_USBD) + 0x804)) = 0x40; + __ISB(); + __DSB(); + } + + NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN << USBD_ISOSPLIT_SPLIT_Pos; + + if (IS_ENABLED(CONFIG_NRF_USBD_ISO_IN_ZLP)) { + NRF_USBD->ISOINCONFIG = USBD_ISOINCONFIG_RESPONSE_ZeroData + << USBD_ISOINCONFIG_RESPONSE_Pos; + } else { + NRF_USBD->ISOINCONFIG = USBD_ISOINCONFIG_RESPONSE_NoResp + << USBD_ISOINCONFIG_RESPONSE_Pos; + } + + m_ep_ready = (((1U << NRF_USBD_COMMON_EPIN_CNT) - 1U) << NRF_USBD_COMMON_EPIN_BITPOS_0); + m_ep_dma_waiting = 0; + m_dma_odd = 0; + __ASSERT_NO_MSG(k_sem_count_get(&dma_available) == 1); + usbd_dma_pending_clear(); + m_last_setup_dir = NRF_USBD_COMMON_EPOUT0; + + m_drv_state = NRFX_DRV_STATE_POWERED_ON; + +#if NRF_USBD_COMMON_USE_WORKAROUND_FOR_ANOMALY_211 + if (nrf_usbd_common_errata_187() && !nrf_usbd_common_errata_211()) +#else + if (nrf_usbd_common_errata_187()) +#endif + { + usbd_errata_187_211_end(); + } +} + +void nrf_usbd_common_disable(void) +{ + __ASSERT_NO_MSG(m_drv_state != NRFX_DRV_STATE_UNINITIALIZED); + + /* Make sure DMA is not active */ + k_sem_take(&dma_available, K_FOREVER); + + /* Stop just in case */ + nrf_usbd_common_stop(); + + /* Disable all parts */ + if (m_dma_odd) { + /* Prevent invalid bus request after next USBD enable by ensuring + * that total number of bytes transferred by DMA is even. + */ + NRF_USBD->EVENTS_ENDEPIN[0] = 0; + usbd_ep_dma_start(NRF_USBD_COMMON_EPIN0, (uint32_t)&m_dma_odd, 1); + while (!NRF_USBD->EVENTS_ENDEPIN[0]) { + } + NRF_USBD->EVENTS_ENDEPIN[0] = 0; + m_dma_odd = 0; + } + NRF_USBD->ENABLE = 0; + usbd_dma_pending_clear(); + k_sem_give(&dma_available); + m_drv_state = NRFX_DRV_STATE_INITIALIZED; + +#if NRF_USBD_COMMON_USE_WORKAROUND_FOR_ANOMALY_211 + if (nrf_usbd_common_errata_211()) { + usbd_errata_187_211_end(); + } +#endif +} + +void nrf_usbd_common_start(bool enable_sof) +{ + __ASSERT_NO_MSG(m_drv_state == NRFX_DRV_STATE_POWERED_ON); + m_bus_suspend = false; + + uint32_t int_mask = USBD_INTEN_USBRESET_Msk | USBD_INTEN_ENDEPIN0_Msk | + USBD_INTEN_ENDEPIN1_Msk | USBD_INTEN_ENDEPIN2_Msk | + USBD_INTEN_ENDEPIN3_Msk | USBD_INTEN_ENDEPIN4_Msk | + USBD_INTEN_ENDEPIN5_Msk | USBD_INTEN_ENDEPIN6_Msk | + USBD_INTEN_ENDEPIN7_Msk | USBD_INTEN_EP0DATADONE_Msk | + USBD_INTEN_ENDISOIN_Msk | USBD_INTEN_ENDEPOUT0_Msk | + USBD_INTEN_ENDEPOUT1_Msk | USBD_INTEN_ENDEPOUT2_Msk | + USBD_INTEN_ENDEPOUT3_Msk | USBD_INTEN_ENDEPOUT4_Msk | + USBD_INTEN_ENDEPOUT5_Msk | USBD_INTEN_ENDEPOUT6_Msk | + USBD_INTEN_ENDEPOUT7_Msk | USBD_INTEN_ENDISOOUT_Msk | + USBD_INTEN_USBEVENT_Msk | USBD_INTEN_EP0SETUP_Msk | + USBD_INTEN_EPDATA_Msk; + + if (enable_sof) { + int_mask |= USBD_INTEN_SOF_Msk; + } + + /* Enable all required interrupts */ + NRF_USBD->INTEN = int_mask; + + /* Enable interrupt globally */ + irq_enable(USBD_IRQn); + + /* Enable pullups */ + NRF_USBD->USBPULLUP = 1; +} + +static void nrf_usbd_common_stop(void) +{ + __ASSERT_NO_MSG(m_drv_state == NRFX_DRV_STATE_POWERED_ON); + + /* Clear interrupt */ + NVIC_ClearPendingIRQ(USBD_IRQn); + + if (irq_is_enabled(USBD_IRQn)) { + /* Abort transfers */ + usbd_ep_abort_all(); + + /* Disable pullups */ + NRF_USBD->USBPULLUP = 0; + + /* Disable interrupt globally */ + irq_disable(USBD_IRQn); + + /* Disable all interrupts */ + NRF_USBD->INTEN = 0; + } +} + +bool nrf_usbd_common_is_initialized(void) +{ + return (m_drv_state >= NRFX_DRV_STATE_INITIALIZED); +} + +bool nrf_usbd_common_is_enabled(void) +{ + return (m_drv_state >= NRFX_DRV_STATE_POWERED_ON); +} + +bool nrf_usbd_common_is_started(void) +{ + return (nrf_usbd_common_is_enabled() && irq_is_enabled(USBD_IRQn)); +} + +bool nrf_usbd_common_suspend(void) +{ + bool suspended = false; + unsigned int irq_lock_key = irq_lock(); + + if (m_bus_suspend) { + if (!(NRF_USBD->EVENTCAUSE & USBD_EVENTCAUSE_RESUME_Msk)) { + NRF_USBD->LOWPOWER = USBD_LOWPOWER_LOWPOWER_LowPower + << USBD_LOWPOWER_LOWPOWER_Pos; + (void)NRF_USBD->LOWPOWER; + if (NRF_USBD->EVENTCAUSE & USBD_EVENTCAUSE_RESUME_Msk) { + NRF_USBD->LOWPOWER = USBD_LOWPOWER_LOWPOWER_ForceNormal + << USBD_LOWPOWER_LOWPOWER_Pos; + } else { + suspended = true; + } + } + } + + irq_unlock(irq_lock_key); + + return suspended; +} + +bool nrf_usbd_common_wakeup_req(void) +{ + bool started = false; + unsigned int irq_lock_key = irq_lock(); + + if (m_bus_suspend && nrf_usbd_common_suspend_check()) { + NRF_USBD->LOWPOWER = USBD_LOWPOWER_LOWPOWER_ForceNormal + << USBD_LOWPOWER_LOWPOWER_Pos; + started = true; + + if (nrf_usbd_common_errata_171()) { + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } else { + *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0; + } + } + } + + irq_unlock(irq_lock_key); + + return started; +} + +bool nrf_usbd_common_suspend_check(void) +{ + return NRF_USBD->LOWPOWER != + (USBD_LOWPOWER_LOWPOWER_ForceNormal << USBD_LOWPOWER_LOWPOWER_Pos); +} + +bool nrf_usbd_common_bus_suspend_check(void) +{ + return m_bus_suspend; +} + +void nrf_usbd_common_force_bus_wakeup(void) +{ + m_bus_suspend = false; +} + +void nrf_usbd_common_ep_max_packet_size_set(nrf_usbd_common_ep_t ep, uint16_t size) +{ + /* Only the power of 2 size allowed for Control Endpoints */ + __ASSERT_NO_MSG((((size & (size - 1)) == 0) || (NRF_USBD_COMMON_EP_NUM(ep) != 0))); + /* Only non zero size allowed for Control Endpoints */ + __ASSERT_NO_MSG((size != 0) || (NRF_USBD_COMMON_EP_NUM(ep) != 0)); + /* Packet size cannot be higher than maximum buffer size */ + __ASSERT_NO_MSG((NRF_USBD_COMMON_EP_IS_ISO(ep) && (size <= usbd_ep_iso_capacity(ep))) || + (!NRF_USBD_COMMON_EP_IS_ISO(ep) && (size <= NRF_USBD_COMMON_EPSIZE))); + + usbd_ep_state_t *p_state = ep_state_access(ep); + + p_state->max_packet_size = size; +} + +uint16_t nrf_usbd_common_ep_max_packet_size_get(nrf_usbd_common_ep_t ep) +{ + usbd_ep_state_t const *p_state = ep_state_access(ep); + + return p_state->max_packet_size; +} + +bool nrf_usbd_common_ep_enable_check(nrf_usbd_common_ep_t ep) +{ + int ep_in = NRF_USBD_COMMON_EP_IS_IN(ep); + int ep_num = NRF_USBD_COMMON_EP_NUM(ep); + + NRF_USBD_COMMON_ASSERT_EP_VALID(ep); + + return (ep_in ? NRF_USBD->EPINEN : NRF_USBD->EPOUTEN) & BIT(ep_num); +} + +void nrf_usbd_common_ep_enable(nrf_usbd_common_ep_t ep) +{ + int ep_in = NRF_USBD_COMMON_EP_IS_IN(ep); + int ep_num = NRF_USBD_COMMON_EP_NUM(ep); + + if (nrf_usbd_common_ep_enable_check(ep)) { + return; + } + + if (ep_in) { + NRF_USBD->EPINEN |= BIT(ep_num); + } else { + NRF_USBD->EPOUTEN |= BIT(ep_num); + } + + if (ep >= NRF_USBD_COMMON_EPOUT1 && ep <= NRF_USBD_COMMON_EPOUT7) { + unsigned int irq_lock_key = irq_lock(); + + nrf_usbd_common_transfer_out_drop(ep); + m_ep_dma_waiting &= ~(1U << ep2bit(ep)); + + irq_unlock(irq_lock_key); + } +} + +void nrf_usbd_common_ep_disable(nrf_usbd_common_ep_t ep) +{ + int ep_in = NRF_USBD_COMMON_EP_IS_IN(ep); + int ep_num = NRF_USBD_COMMON_EP_NUM(ep); + + /* Only disable endpoint if there is no active DMA */ + k_sem_take(&dma_available, K_FOREVER); + usbd_ep_abort(ep); + if (ep_in) { + NRF_USBD->EPINEN &= ~BIT(ep_num); + } else { + NRF_USBD->EPOUTEN &= ~BIT(ep_num); + } + k_sem_give(&dma_available); + + /* This function was holding DMA semaphore and could potentially prevent + * next DMA from executing. Fire IRQ handler to check if any DMA needs + * to be started. + */ + usbd_int_rise(); +} + +nrfx_err_t nrf_usbd_common_ep_transfer(nrf_usbd_common_ep_t ep, + nrf_usbd_common_transfer_t const *p_transfer) +{ + nrfx_err_t ret; + const uint8_t ep_bitpos = ep2bit(ep); + unsigned int irq_lock_key = irq_lock(); + + __ASSERT_NO_MSG(p_transfer != NULL); + + /* Setup data transaction can go only in one direction at a time */ + if ((NRF_USBD_COMMON_EP_NUM(ep) == 0) && (ep != m_last_setup_dir)) { + ret = NRFX_ERROR_INVALID_ADDR; + if (NRF_USBD_COMMON_FAILED_TRANSFERS_DEBUG && + (NRF_USBD_COMMON_ISO_DEBUG || (!NRF_USBD_COMMON_EP_IS_ISO(ep)))) { + LOG_DBG("Transfer failed: Invalid EPr\n"); + } + } else if ((m_ep_dma_waiting | ((~m_ep_ready) & NRF_USBD_COMMON_EPIN_BIT_MASK)) & + (1U << ep_bitpos)) { + /* IN (Device -> Host) transfer has to be transmitted out to allow new transmission + */ + ret = NRFX_ERROR_BUSY; + if (NRF_USBD_COMMON_FAILED_TRANSFERS_DEBUG) { + LOG_DBG("Transfer failed: EP is busy"); + } + } else { + usbd_ep_state_t *p_state = ep_state_access(ep); + + __ASSERT_NO_MSG(NRF_USBD_COMMON_EP_IS_IN(ep) || + (p_transfer->p_data.rx == NULL) || + (nrfx_is_in_ram(p_transfer->p_data.rx))); + p_state->more_transactions = true; + p_state->transfer_state = *p_transfer; + + p_state->transfer_cnt = 0; + p_state->status = NRF_USBD_COMMON_EP_OK; + m_ep_dma_waiting |= 1U << ep_bitpos; + ret = NRFX_SUCCESS; + usbd_int_rise(); + } + + irq_unlock(irq_lock_key); + + return ret; +} + +nrf_usbd_common_ep_status_t nrf_usbd_common_ep_status_get(nrf_usbd_common_ep_t ep, size_t *p_size) +{ + nrf_usbd_common_ep_status_t ret; + usbd_ep_state_t const *p_state = ep_state_access(ep); + unsigned int irq_lock_key = irq_lock(); + + *p_size = p_state->transfer_cnt; + ret = (!p_state->more_transactions) ? p_state->status : NRF_USBD_COMMON_EP_BUSY; + + irq_unlock(irq_lock_key); + + return ret; +} + +size_t nrf_usbd_common_epout_size_get(nrf_usbd_common_ep_t ep) +{ + if (NRF_USBD_COMMON_EP_IS_ISO(ep)) { + size_t size = NRF_USBD->SIZE.ISOOUT; + + if ((size & USBD_SIZE_ISOOUT_ZERO_Msk) == + (USBD_SIZE_ISOOUT_ZERO_ZeroData << USBD_SIZE_ISOOUT_ZERO_Pos)) { + size = 0; + } + return size; + } + + return NRF_USBD->SIZE.EPOUT[NRF_USBD_COMMON_EP_NUM(ep)]; +} + +bool nrf_usbd_common_ep_is_busy(nrf_usbd_common_ep_t ep) +{ + return (0 != ((m_ep_dma_waiting | ((~m_ep_ready) & NRF_USBD_COMMON_EPIN_BIT_MASK)) & + (1U << ep2bit(ep)))); +} + +void nrf_usbd_common_ep_stall(nrf_usbd_common_ep_t ep) +{ + __ASSERT_NO_MSG(!NRF_USBD_COMMON_EP_IS_ISO(ep)); + + LOG_DBG("USB: EP %x stalled.", ep); + NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_Stall << USBD_EPSTALL_STALL_Pos) | ep; +} + +void nrf_usbd_common_ep_stall_clear(nrf_usbd_common_ep_t ep) +{ + __ASSERT_NO_MSG(!NRF_USBD_COMMON_EP_IS_ISO(ep)); + + if (NRF_USBD_COMMON_EP_IS_OUT(ep) && nrf_usbd_common_ep_stall_check(ep)) { + nrf_usbd_common_transfer_out_drop(ep); + } + NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep; +} + +bool nrf_usbd_common_ep_stall_check(nrf_usbd_common_ep_t ep) +{ + int ep_in = NRF_USBD_COMMON_EP_IS_IN(ep); + int ep_num = NRF_USBD_COMMON_EP_NUM(ep); + + if (!NRF_USBD_COMMON_EP_IS_ISO(ep_num)) { + if (ep_in) { + return NRF_USBD->HALTED.EPIN[ep_num]; + } else { + return NRF_USBD->HALTED.EPOUT[ep_num]; + } + } + + return false; +} + +void nrf_usbd_common_ep_dtoggle_clear(nrf_usbd_common_ep_t ep) +{ + __ASSERT_NO_MSG(!NRF_USBD_COMMON_EP_IS_ISO(ep)); + + NRF_USBD->DTOGGLE = ep | (USBD_DTOGGLE_VALUE_Nop << USBD_DTOGGLE_VALUE_Pos); + NRF_USBD->DTOGGLE = ep | (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos); +} + +void nrf_usbd_common_setup_get(nrf_usbd_common_setup_t *p_setup) +{ + memset(p_setup, 0, sizeof(nrf_usbd_common_setup_t)); + p_setup->bmRequestType = NRF_USBD->BMREQUESTTYPE; + p_setup->bRequest = NRF_USBD->BREQUEST; + p_setup->wValue = NRF_USBD->WVALUEL | (NRF_USBD->WVALUEH << 8); + p_setup->wIndex = NRF_USBD->WINDEXL | (NRF_USBD->WINDEXH << 8); + p_setup->wLength = NRF_USBD->WLENGTHL | (NRF_USBD->WLENGTHH << 8); +} + +void nrf_usbd_common_setup_data_clear(void) +{ + NRF_USBD->TASKS_EP0RCVOUT = 1; +} + +void nrf_usbd_common_setup_clear(void) +{ + LOG_DBG(">> ep0status >>"); + NRF_USBD->TASKS_EP0STATUS = 1; +} + +void nrf_usbd_common_setup_stall(void) +{ + LOG_DBG("Setup stalled."); + NRF_USBD->TASKS_EP0STALL = 1; +} + +nrf_usbd_common_ep_t nrf_usbd_common_last_setup_dir_get(void) +{ + return m_last_setup_dir; +} + +void nrf_usbd_common_transfer_out_drop(nrf_usbd_common_ep_t ep) +{ + unsigned int irq_lock_key = irq_lock(); + + __ASSERT_NO_MSG(NRF_USBD_COMMON_EP_IS_OUT(ep)); + + m_ep_ready &= ~(1U << ep2bit(ep)); + if (!NRF_USBD_COMMON_EP_IS_ISO(ep)) { + NRF_USBD->SIZE.EPOUT[NRF_USBD_COMMON_EP_NUM(ep)] = 0; + } + + irq_unlock(irq_lock_key); +} + +/** @endcond */ diff --git a/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.h b/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.h new file mode 100644 index 000000000000000..bb3db14a05b030f --- /dev/null +++ b/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.h @@ -0,0 +1,679 @@ +/* + * Copyright (c) 2016 - 2023, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* This file is undergoing transition towards native Zephyr nrf USB driver. */ + +/** @cond INTERNAL_HIDDEN */ + +#ifndef NRF_USBD_COMMON_H__ +#define NRF_USBD_COMMON_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup nrf_usbd_common USBD driver + * @{ + * @ingroup nrf_usbd + * @brief Universal Serial Bus Device (USBD) peripheral driver. + */ + +/** + * @brief Number of bytes in the endpoint. + */ +#define NRF_USBD_COMMON_EPSIZE 64 + +/** + * @brief Number of bytes for isochronous endpoints. + * + * Number of bytes for isochronous endpoints in total. + * This number would be shared between IN and OUT endpoint. + * It may be also assigned totaly to one endpoint. + * @sa nrf_usbd_isosplit_set + * @sa nrf_usbd_isosplit_get + */ +#define NRF_USBD_COMMON_ISOSIZE 1023 + +/** + * @name Macros for creating endpoint identifiers. + * + * Auxiliary macros for creating endpoint identifiers compatible with the USB specification. + * @{ + */ + +/** + * @brief Create identifier for IN endpoint. + * + * Simple macro to create IN endpoint identifier for given endpoint number. + * + * @param[in] n Endpoint number. + * + * @return Endpoint identifier that connects endpoint number and endpoint direction. + */ +#define NRF_USBD_COMMON_EPIN(n) ((nrf_usbd_common_ep_t)(0x80 | n)) +/** + * @brief Create identifier for OUT endpoint. + * + * Simple macro to create OUT endpoint identifier for given endpoint number. + * + * @param[in] n Endpoint number. + * + * @return Endpoint identifier that connects endpoint number and endpoint direction. + */ +#define NRF_USBD_COMMON_EPOUT(n) ((nrf_usbd_common_ep_t)(n)) +/** @} */ + +/** + * @brief Endpoint identifier. + * + * Endpoint identifier used in the driver. + * This endpoint number is consistent with USB 2.0 specification. + */ +typedef enum { + NRF_USBD_COMMON_EPOUT0 = 0x00, /**< Endpoint OUT 0 */ + NRF_USBD_COMMON_EPOUT1 = 0x01, /**< Endpoint OUT 1 */ + NRF_USBD_COMMON_EPOUT2 = 0x02, /**< Endpoint OUT 2 */ + NRF_USBD_COMMON_EPOUT3 = 0x03, /**< Endpoint OUT 3 */ + NRF_USBD_COMMON_EPOUT4 = 0x04, /**< Endpoint OUT 4 */ + NRF_USBD_COMMON_EPOUT5 = 0x05, /**< Endpoint OUT 5 */ + NRF_USBD_COMMON_EPOUT6 = 0x06, /**< Endpoint OUT 6 */ + NRF_USBD_COMMON_EPOUT7 = 0x07, /**< Endpoint OUT 7 */ + NRF_USBD_COMMON_EPOUT8 = 0x08, /**< Endpoint OUT 8 */ + + NRF_USBD_COMMON_EPIN0 = 0x80, /**< Endpoint IN 0 */ + NRF_USBD_COMMON_EPIN1 = 0x81, /**< Endpoint IN 1 */ + NRF_USBD_COMMON_EPIN2 = 0x82, /**< Endpoint IN 2 */ + NRF_USBD_COMMON_EPIN3 = 0x83, /**< Endpoint IN 3 */ + NRF_USBD_COMMON_EPIN4 = 0x84, /**< Endpoint IN 4 */ + NRF_USBD_COMMON_EPIN5 = 0x85, /**< Endpoint IN 5 */ + NRF_USBD_COMMON_EPIN6 = 0x86, /**< Endpoint IN 6 */ + NRF_USBD_COMMON_EPIN7 = 0x87, /**< Endpoint IN 7 */ + NRF_USBD_COMMON_EPIN8 = 0x88, /**< Endpoint IN 8 */ +} nrf_usbd_common_ep_t; + +/** + * @brief Events generated by the driver. + * + * Enumeration of possible events that may be generated by the driver. + */ +typedef enum { + NRF_USBD_COMMON_EVT_SOF, /**< Start Of Frame event on USB bus detected. */ + NRF_USBD_COMMON_EVT_RESET, /**< Reset condition on USB bus detected. */ + NRF_USBD_COMMON_EVT_SUSPEND, /**< This device should go to suspend mode now. */ + NRF_USBD_COMMON_EVT_RESUME, /**< This device should resume from suspend now. */ + /** Wakeup request - the USBD peripheral is ready to generate + * WAKEUP signal after exiting low power mode. + */ + NRF_USBD_COMMON_EVT_WUREQ, + NRF_USBD_COMMON_EVT_SETUP, /**< Setup frame received and decoded. */ + /** For Rx (OUT: Host->Device): + * 1. The packet has been received but there is no buffer + * prepared for transfer already. + * 2. Whole transfer has been finished. + * + * For Tx (IN: Device->Host): + * The last packet from requested transfer has been transferred + * over USB bus and acknowledged. + */ + NRF_USBD_COMMON_EVT_EPTRANSFER, + NRF_USBD_COMMON_EVT_CNT /**< Number of defined events. */ +} nrf_usbd_common_event_type_t; + +/** + * @brief Endpoint status codes. + * + * Status codes that may be returned by @ref nrf_usbd_common_ep_status_get or, except for + * @ref NRF_USBD_COMMON_EP_BUSY, reported together with @ref NRF_USBD_COMMON_EVT_EPTRANSFER. + */ +typedef enum { + /** No error occurred. */ + NRF_USBD_COMMON_EP_OK, + /** Data received, no buffer prepared already - waiting for configured transfer. */ + NRF_USBD_COMMON_EP_WAITING, + /** Received number of bytes cannot fit given buffer. + * This error would also be returned when next_transfer function + * has been defined but currently received data cannot fit completely + * in current buffer. No data split from single endpoint transmission + * is supported. + * + * When this error is reported - data is left inside endpoint + * buffer. Clear endpoint or prepare new buffer and read it. + */ + NRF_USBD_COMMON_EP_OVERLOAD, + /** EP0 transfer can be aborted when new setup comes. + * Any other transfer can be aborted by USB reset or driver stopping. + */ + NRF_USBD_COMMON_EP_ABORTED, + /** Transfer is in progress. */ + NRF_USBD_COMMON_EP_BUSY, +} nrf_usbd_common_ep_status_t; + +/** + * @brief Event structure. + * + * Structure passed to event handler. + */ +typedef struct { + nrf_usbd_common_event_type_t type; /**< Event type. */ + union { + struct { + uint16_t framecnt; /**< Current value of frame counter. */ + } sof; /**< Data available for @ref NRF_USBD_COMMON_EVT_SOF. */ + struct { + nrf_usbd_common_ep_t ep; /**< Endpoint number. */ + } isocrc; /**< Isochronouns channel endpoint number. */ + struct { + nrf_usbd_common_ep_t ep; /**< Endpoint number. */ + nrf_usbd_common_ep_status_t status; /**< Status for the endpoint. */ + } eptransfer; /**< Endpoint transfer status. */ + } data; /**< Union to store event data. */ +} nrf_usbd_common_evt_t; + +/** + * @brief USBD event callback function type. + * + * @param[in] p_event Event information structure. + */ +typedef void (*nrf_usbd_common_event_handler_t)(nrf_usbd_common_evt_t const *p_event); + +/** + * @brief Universal data pointer. + * + * Universal data pointer that can be used for any type of transfer. + */ +typedef union { + void const *tx; /*!< Constant TX buffer pointer. */ + void *rx; /*!< Writable RX buffer pointer. */ + uint32_t addr; /*!< Numeric value used internally by the driver. */ +} nrf_usbd_common_data_ptr_t; + +/** + * @brief Structure to be filled with information about the next transfer. + * + * This is used mainly for transfer feeders and consumers. + * It describes a single endpoint transfer and therefore the size of the buffer + * can never be higher than the endpoint size. + */ +typedef struct { + /** Union with available data pointers used by the driver. */ + nrf_usbd_common_data_ptr_t p_data; + /** Size of the requested transfer. */ + size_t size; +} nrf_usbd_common_ep_transfer_t; + +/** + * @brief Flags for the current transfer. + * + * Flags configured for the transfer that can be merged using the bitwise 'or' operator (|). + */ +typedef enum { + NRF_USBD_COMMON_TRANSFER_ZLP_FLAG = 1U << 0, /*!< Add a zero-length packet. */ +} nrf_usbd_common_transfer_flags_t; + +/** + * @brief Total transfer configuration. + * + * This structure is used to configure total transfer information. + * It is used by internal built-in feeders and consumers. + */ +typedef struct { + /** Union with available data pointers used by the driver. */ + nrf_usbd_common_data_ptr_t p_data; + /** Total size of the requested transfer. */ + size_t size; + /*!< Transfer flags. Use the @ref nrf_usbd_common_transfer_flags_t values. */ + uint32_t flags; +} nrf_usbd_common_transfer_t; + +/** + * @brief Auxiliary macro for declaring IN transfer description with optional flags. + * + * The base macro for creating transfers with any configuration option. + * + * @param name Instance name. + * @param tx_buff Buffer to transfer. + * @param tx_size Transfer size. + * @param tx_flags Flags for the transfer (see @ref nrf_usbd_common_transfer_flags_t). + * + * @return Configured variable with total transfer description. + */ +#define NRF_USBD_COMMON_TRANSFER_IN(name, tx_buff, tx_size, tx_flags) \ + const nrf_usbd_common_transfer_t name = { \ + .p_data = {.tx = (tx_buff)}, .size = (tx_size), .flags = (tx_flags)} + +/** + * @brief Helper macro for declaring OUT transfer item (@ref nrf_usbd_common_transfer_t). + * + * @param name Instance name. + * @param rx_buff Buffer to transfer. + * @param rx_size Transfer size. + */ +#define NRF_USBD_COMMON_TRANSFER_OUT(name, rx_buff, rx_size) \ + const nrf_usbd_common_transfer_t name = { \ + .p_data = {.rx = (rx_buff)}, .size = (rx_size), .flags = 0} + +/** + * @brief Setup packet structure. + * + * Structure that contains interpreted SETUP packet as described in USB specification. + */ +typedef struct { + uint8_t bmRequestType; /*!< byte 0 */ + uint8_t bRequest; /*!< byte 1 */ + uint16_t wValue; /*!< byte 2, 3 */ + uint16_t wIndex; /*!< byte 4, 5 */ + uint16_t wLength; /*!< byte 6, 7 */ +} nrf_usbd_common_setup_t; + +/** + * @brief Driver initialization. + * + * @param[in] event_handler Event handler provided by the user. Cannot be null. + * + * @retval NRFX_SUCCESS Initialization successful. + * @retval NRFX_ERROR_INVALID_STATE Driver was already initialized. + */ +nrfx_err_t nrf_usbd_common_init(nrf_usbd_common_event_handler_t event_handler); + +/** + * @brief Driver deinitialization. + */ +void nrf_usbd_common_uninit(void); + +/** + * @brief Enable the USBD port. + * + * After calling this function USBD peripheral would be enabled. + * The USB LDO would be enabled. + * Enabled USBD peripheral would request HFCLK. + * This function does not enable external oscillator, so if it is not enabled by other part of the + * program after enabling USBD driver HFINT would be used for the USBD peripheral. + * It is perfectly fine until USBD is started. See @ref nrf_usbd_common_start. + * + * In normal situation this function should be called in reaction to USBDETECTED + * event from POWER peripheral. + * + * Interrupts and USB pins pull-up would stay disabled until @ref nrf_usbd_common_start + * function is called. + */ +void nrf_usbd_common_enable(void); + +/** + * @brief Disable the USBD port. + * + * After calling this function USBD peripheral would be disabled. + * No events would be detected or processed by the driver. + * Clock for the peripheral would be disconnected. + */ +void nrf_usbd_common_disable(void); + +/** + * @brief Start USB functionality. + * + * After calling this function USBD peripheral should be fully functional + * and all new incoming events / interrupts would be processed by the driver. + * + * Also only after calling this function host sees new connected device. + * + * Call this function when USBD power LDO regulator is ready - on USBPWRRDY event + * from POWER peripheral. + * + * Before USBD interrupts are enabled, external HFXO is requested. + * + * @param enable_sof The flag that is used to enable SOF processing. + * If it is false, SOF interrupt is left disabled and will not be generated. + * This improves power saving if SOF is not required. + * + * @note If the isochronous endpoints are going to be used, + * it is required to enable the SOF. + * In other case any isochronous endpoint would stay busy + * after first transmission. + */ +void nrf_usbd_common_start(bool enable_sof); + +/** + * @brief Check if driver is initialized. + * + * @retval false Driver is not initialized. + * @retval true Driver is initialized. + */ +bool nrf_usbd_common_is_initialized(void); + +/** + * @brief Check if driver is enabled. + * + * @retval false Driver is disabled. + * @retval true Driver is enabled. + */ +bool nrf_usbd_common_is_enabled(void); + +/** + * @brief Check if driver is started. + * + * @retval false Driver is not started. + * @retval true Driver is started (fully functional). + * @note The USBD peripheral interrupt state is checked. + */ +bool nrf_usbd_common_is_started(void); + +/** + * @brief Suspend USBD operation. + * + * The USBD peripheral is forced to go into the low power mode. + * The function has to be called in the reaction to @ref NRF_USBD_COMMON_EVT_SUSPEND event + * when the firmware is ready. + * + * After successful call of this function most of the USBD registers would be unavailable. + * + * @note Check returned value for the feedback if suspending was successful. + * + * @retval true USBD peripheral successfully suspended. + * @retval false USBD peripheral was not suspended due to resume detection. + */ +bool nrf_usbd_common_suspend(void); + +/** + * @brief Start wake up procedure. + * + * The USBD peripheral is forced to quit the low power mode. + * After calling this function all the USBD registers would be available. + * + * The hardware starts measuring time when wake up is possible. + * This may take 0-5 ms depending on how long the SUSPEND state was kept on the USB line. + + * When NRF_USBD_COMMON_EVT_WUREQ event is generated it means that Wake Up signaling has just been + * started on the USB lines. + * + * @note Do not expect only @ref NRF_USBD_COMMON_EVT_WUREQ event. + * There always may appear @ref NRF_USBD_COMMON_EVT_RESUME event. + * @note NRF_USBD_COMMON_EVT_WUREQ event means that Remote WakeUp signal + * has just begun to be generated. + * This may take up to 20 ms for the bus to become active. + * + * @retval true WakeUp procedure started. + * @retval false No WakeUp procedure started - bus is already active. + */ +bool nrf_usbd_common_wakeup_req(void); + +/** + * @brief Check if USBD is in SUSPEND mode. + * + * @note This is the information about peripheral itself, not about the bus state. + * + * @retval true USBD peripheral is suspended. + * @retval false USBD peripheral is active. + */ +bool nrf_usbd_common_suspend_check(void); + +/** + * @brief Check the bus state. + * + * This function checks if the bus state is suspended. + * + * @note The value returned by this function changes on SUSPEND and RESUME event processing. + * + * @retval true USBD bus is suspended. + * @retval false USBD bus is active. + */ +bool nrf_usbd_common_bus_suspend_check(void); + +/** + * @brief Force the bus state to active + */ +void nrf_usbd_common_force_bus_wakeup(void); + +/** + * @brief Configure packet size that should be supported by the endpoint. + * + * The real endpoint buffer size is always the same. + * This value sets max packet size that would be transmitted over the endpoint. + * This is required by the driver. + * + * @param[in] ep Endpoint number. + * @param[in] size Required maximum packet size. + * + * @note Endpoint size is always set to @ref NRF_USBD_COMMON_EPSIZE + * or @ref NRF_USBD_COMMON_ISOSIZE / 2 + * when @ref nrf_usbd_common_ep_enable function is called. + */ +void nrf_usbd_common_ep_max_packet_size_set(nrf_usbd_common_ep_t ep, uint16_t size); + +/** + * @brief Get configured endpoint packet size. + * + * Function to get configured endpoint size on the buffer. + * + * @param[in] ep Endpoint number. + * + * @return Maximum pocket size configured on selected endpoint. + */ +uint16_t nrf_usbd_common_ep_max_packet_size_get(nrf_usbd_common_ep_t ep); + +/** + * @brief Check if the selected endpoint is enabled. + * + * @param[in] ep Endpoint number to check. + * + * @retval true Endpoint is enabled. + * @retval false Endpoint is disabled. + */ +bool nrf_usbd_common_ep_enable_check(nrf_usbd_common_ep_t ep); + +/** + * @brief Enable selected endpoint. + * + * This function enables endpoint itself and its interrupts. + * + * @param[in] ep Endpoint number to enable. + * + * @note + * Max packet size is set to endpoint default maximum value. + * + * @sa nrf_usbd_common_ep_max_packet_size_set + */ +void nrf_usbd_common_ep_enable(nrf_usbd_common_ep_t ep); + +/** + * @brief Disable selected endpoint. + * + * This function disables endpoint itself and its interrupts. + * + * @param[in] ep Endpoint number to disable. + */ +void nrf_usbd_common_ep_disable(nrf_usbd_common_ep_t ep); + +/** + * @brief Start sending data over endpoint. + * + * Function initializes endpoint transmission. + * This is asynchronous function - it finishes immediately after configuration + * for transmission is prepared. + * + * @note Data buffer pointed by p_data have to be kept active till + * @ref NRF_USBD_COMMON_EVT_EPTRANSFER event is generated. + * + * @param[in] ep Endpoint number. + * For IN endpoint sending would be initiated. + * For OUT endpoint receiving would be initiated. + * @param[in] p_transfer Transfer parameters. + * + * @retval NRFX_SUCCESS Transfer queued or started. + * @retval NRFX_ERROR_BUSY Selected endpoint is pending. + * @retval NRFX_ERROR_INVALID_ADDR Unexpected transfer on EPIN0 or EPOUT0. + */ +nrfx_err_t nrf_usbd_common_ep_transfer(nrf_usbd_common_ep_t ep, + nrf_usbd_common_transfer_t const *p_transfer); + +/** + * @brief Get the information about last finished or current transfer. + * + * Function returns the status of the last buffer set for transfer on selected endpoint. + * The status considers last buffer set by @ref nrf_usbd_common_ep_transfer function or + * by transfer callback function. + * + * @param[in] ep Endpoint number. + * @param[out] p_size Information about the current/last transfer size. + * + * @return Endpoint status. + * + * @sa nrf_usbd_common_ep_status_t + */ +nrf_usbd_common_ep_status_t nrf_usbd_common_ep_status_get(nrf_usbd_common_ep_t ep, size_t *p_size); + +/** + * @brief Get number of received bytes. + * + * Get the number of received bytes. + * The function behavior is undefined when called on IN endpoint. + * + * @param[in] ep Endpoint number. + * + * @return Number of received bytes. + */ +size_t nrf_usbd_common_epout_size_get(nrf_usbd_common_ep_t ep); + +/** + * @brief Check if endpoint buffer is ready or is under USB IP control. + * + * Function to test if endpoint is busy. + * Endpoint that is busy cannot be accessed by MCU. + * It means that: + * - OUT (TX) endpoint: Last uploaded data is still in endpoint and is waiting + * to be received by the host. + * - IN (RX) endpoint: Endpoint is ready to receive data from the host + * and the endpoint does not have any data. + * When endpoint is not busy: + * - OUT (TX) endpoint: New data can be uploaded. + * - IN (RX) endpoint: New data can be downloaded using @ref nrf_usbd_common_ep_transfer + * function. + * + * @param[in] ep Endpoint number. + * + * @retval false Endpoint is not busy. + * @retval true Endpoint is busy. + */ +bool nrf_usbd_common_ep_is_busy(nrf_usbd_common_ep_t ep); + +/** + * @brief Stall endpoint + * + * Stall endpoit to send error information during next transfer request from + * the host. + * + * @note To stall endpoint it is safer to use @ref nrf_usbd_common_setup_stall + * @note Stalled endpoint would not be cleared when DMA transfer finishes. + * + * @param[in] ep Endpoint number to stall. + */ +void nrf_usbd_common_ep_stall(nrf_usbd_common_ep_t ep); + +/** + * @brief Clear stall flag on endpoint. + * + * This function clears endpoint that is stalled. + * @note + * If it is OUT endpoint (receiving) it would be also prepared for reception. + * It means that busy flag would be set. + * @note + * In endpoint (transmitting) would not be cleared - it gives possibility to + * write new data before transmitting. + * + * @param[in] ep Endpoint number. + */ +void nrf_usbd_common_ep_stall_clear(nrf_usbd_common_ep_t ep); + +/** + * @brief Check if endpoint is stalled. + * + * This function gets stall state of selected endpoint. + * + * @param[in] ep Endpoint number to check. + * + * @retval false Endpoint is not stalled. + * @retval true Endpoint is stalled. + */ +bool nrf_usbd_common_ep_stall_check(nrf_usbd_common_ep_t ep); + +/** + * @brief Clear current endpoint data toggle. + * + * @param[in] ep Endpoint number to clear. + */ +void nrf_usbd_common_ep_dtoggle_clear(nrf_usbd_common_ep_t ep); + +/** + * @brief Get parsed setup data. + * + * Function fills the parsed setup data structure. + * + * @param[out] p_setup Pointer to data structure that would be filled by + * parsed data. + */ +void nrf_usbd_common_setup_get(nrf_usbd_common_setup_t *p_setup); + +/** + * @brief Clear the control endpoint for packet reception during DATA stage. + * + * This function may be called if any more data in control write transfer is expected. + * Clears only OUT endpoint to be able to take another OUT data token. + * It does not allow STATUS stage. + * @sa nrf_usbd_common_setup_clear + */ +void nrf_usbd_common_setup_data_clear(void); + +/** + * @brief Clear setup endpoint. + * + * This function acknowledges setup when SETUP command was received and processed. + * It has to be called if no data respond for the SETUP command is sent. + */ +void nrf_usbd_common_setup_clear(void); + +/** + * @brief Stall setup endpoint. + * + * Mark an error on setup endpoint. + */ +void nrf_usbd_common_setup_stall(void); + +/** + * @brief Abort pending transfer on selected endpoint. + * + * @param[in] ep Endpoint number. + */ +void nrf_usbd_common_ep_abort(nrf_usbd_common_ep_t ep); + +/** + * @brief Get the information about expected transfer SETUP data direction. + * + * Function returns the information about last expected transfer direction. + * + * @retval NRF_USBD_COMMON_EPOUT0 Expecting OUT (Host->Device) direction or no data. + * @retval NRF_USBD_COMMON_EPIN0 Expecting IN (Device->Host) direction. + */ +nrf_usbd_common_ep_t nrf_usbd_common_last_setup_dir_get(void); + +/** + * @brief Drop transfer on OUT endpoint. + * + * @param[in] ep OUT endpoint ID. + */ +void nrf_usbd_common_transfer_out_drop(nrf_usbd_common_ep_t ep); + +/** @} */ + +void nrf_usbd_common_irq_handler(void); + +#ifdef __cplusplus +} +#endif + +#endif /* NRF_USBD_COMMON_H__ */ + +/** @endcond */ diff --git a/drivers/usb/common/nrf_usbd_common/nrf_usbd_common_errata.h b/drivers/usb/common/nrf_usbd_common/nrf_usbd_common_errata.h new file mode 100644 index 000000000000000..0ee23ccd2c56706 --- /dev/null +++ b/drivers/usb/common/nrf_usbd_common/nrf_usbd_common_errata.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016 - 2023, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* This file is undergoing transition towards native Zephyr nrf USB driver. */ + +/** @cond INTERNAL_HIDDEN */ + +#ifndef NRF_USBD_COMMON_ERRATA_H__ +#define NRF_USBD_COMMON_ERRATA_H__ + +#include +#include + +#ifndef NRF_USBD_COMMON_ERRATA_ENABLE +/** + * @brief The constant that informs if errata should be enabled at all. + * + * If this constant is set to 0, all the Errata bug fixes will be automatically disabled. + */ +#define NRF_USBD_COMMON_ERRATA_ENABLE 1 +#endif + +/* Errata: ISO double buffering not functional. **/ +static inline bool nrf_usbd_common_errata_166(void) +{ + return NRF_USBD_COMMON_ERRATA_ENABLE && nrf52_errata_166(); +} + +/* Errata: USBD might not reach its active state. **/ +static inline bool nrf_usbd_common_errata_171(void) +{ + return NRF_USBD_COMMON_ERRATA_ENABLE && nrf52_errata_171(); +} + +/* Errata: USB cannot be enabled. **/ +static inline bool nrf_usbd_common_errata_187(void) +{ + return NRF_USBD_COMMON_ERRATA_ENABLE && nrf52_errata_187(); +} + +/* Errata: USBD cannot receive tasks during DMA. **/ +static inline bool nrf_usbd_common_errata_199(void) +{ + return NRF_USBD_COMMON_ERRATA_ENABLE && nrf52_errata_199(); +} + +/* Errata: Device remains in SUSPEND too long. */ +static inline bool nrf_usbd_common_errata_211(void) +{ + return NRF_USBD_COMMON_ERRATA_ENABLE && nrf52_errata_211(); +} + +/* Errata: Unexpected behavior after reset. **/ +static inline bool nrf_usbd_common_errata_223(void) +{ + return NRF_USBD_COMMON_ERRATA_ENABLE && nrf52_errata_223(); +} + +#endif /* NRF_USBD_COMMON_ERRATA_H__ */ + +/** @endcond */ diff --git a/drivers/usb/common/usb_dwc2_hw.h b/drivers/usb/common/usb_dwc2_hw.h new file mode 100644 index 000000000000000..edcab56b50f7111 --- /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 534195e4a07ba22..a66e5091f1a179c 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) diff --git a/drivers/usb/device/Kconfig b/drivers/usb/device/Kconfig index 768c0da7cf9abbe..91db896eede5e63 100644 --- a/drivers/usb/device/Kconfig +++ b/drivers/usb/device/Kconfig @@ -104,7 +104,7 @@ config USB_NRFX bool "Nordic Semiconductor USB Device Controller Driver" default y depends on DT_HAS_NORDIC_NRF_USBD_ENABLED - select NRFX_USBD + select NRF_USBD_COMMON select NRFX_POWER imply USB_DEVICE_REMOTE_WAKEUP help @@ -147,7 +147,7 @@ config USB_KINETIS config USB_MCUX bool "NXP MCUX USB Device Controller Driver" default y - depends on DT_HAS_NXP_MCUX_USBD_ENABLED + depends on DT_HAS_NXP_EHCI_ENABLED || DT_HAS_NXP_LPCIP3511_ENABLED help NXP MCUX USB Device Controller Driver for MXRT and LPC SoC's. diff --git a/drivers/usb/device/usb_dc_dw.c b/drivers/usb/device/usb_dc_dw.c index 252e4f6d639d6fc..b2f6a8f0e3cbf68 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 282ae41ab998b54..e2cd5208459a79e 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 f67db012e1d70c1..e453144473c0bc3 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,256 +534,209 @@ 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; + } } } } -static void it82xx2_usb_dc_trans_done(uint8_t ep_ctrl, uint8_t ep_trans_type) +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++) { - 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) { - 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; } } } @@ -785,7 +749,6 @@ static void it82xx2_usb_dc_isr(void) uint8_t status = usb_regs->dc_interrupt_status & usb_regs->dc_interrupt_mask; /* mask non enable int */ - uint8_t ep_ctrl, ep_trans_type; /* reset */ if (status & DC_RESET_EVENT) { @@ -793,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; } @@ -813,7 +770,7 @@ static void it82xx2_usb_dc_isr(void) if (status & DC_TRANS_DONE) { /* clear interrupt before new transaction */ usb_regs->dc_interrupt_status = DC_TRANS_DONE; - it82xx2_usb_dc_trans_done(ep_ctrl, ep_trans_type); + it82xx2_usb_dc_trans_done(); return; } @@ -876,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); @@ -935,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; @@ -975,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"); @@ -1002,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; } @@ -1019,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); @@ -1055,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; @@ -1111,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", @@ -1130,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); } @@ -1200,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; @@ -1240,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; @@ -1262,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; } @@ -1295,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; } @@ -1319,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]; } @@ -1373,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]; } @@ -1382,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__); @@ -1406,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; } @@ -1487,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; } @@ -1499,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; @@ -1540,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 + @@ -1574,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; } @@ -1593,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; } @@ -1625,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 903b1a9dc33914c..36734580e6c97eb 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_mcux.c b/drivers/usb/device/usb_dc_mcux.c index 7278d25d728bdd9..0667486b62806aa 100644 --- a/drivers/usb/device/usb_dc_mcux.c +++ b/drivers/usb/device/usb_dc_mcux.c @@ -5,8 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT nxp_mcux_usbd - #include #include #include @@ -21,15 +19,20 @@ #include "usb_device_dci.h" #ifdef CONFIG_USB_DC_NXP_EHCI +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT nxp_ehci #include "usb_device_ehci.h" #endif #ifdef CONFIG_USB_DC_NXP_LPCIP3511 +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT nxp_lpcip3511 #include "usb_device_lpcip3511.h" #endif #ifdef CONFIG_HAS_MCUX_CACHE #include #endif + #define LOG_LEVEL CONFIG_USB_DRIVER_LOG_LEVEL #include #include @@ -68,7 +71,34 @@ static void usb_isr_handler(void); #define EP_ABS_IDX(ep) (USB_EP_GET_IDX(ep) * 2 + \ (USB_EP_GET_DIR(ep) >> 7)) #define NUM_OF_EP_MAX (DT_INST_PROP(0, num_bidir_endpoints) * 2) -#define CONTROLLER_ID (DT_INST_ENUM_IDX(0, usb_controller_index)) + +#define NUM_INSTS DT_NUM_INST_STATUS_OKAY(nxp_ehci) + DT_NUM_INST_STATUS_OKAY(nxp_lpcip3511) +BUILD_ASSERT(NUM_INSTS <= 1, "Only one USB device supported"); + +/* Controller ID is for HAL usage */ +#if defined(CONFIG_SOC_SERIES_IMX_RT5XX) || \ + defined(CONFIG_SOC_SERIES_IMX_RT6XX) || \ + defined(CONFIG_SOC_LPC55S28) || \ + defined(CONFIG_SOC_LPC55S16) +#define CONTROLLER_ID kUSB_ControllerLpcIp3511Hs0 +#elif defined(CONFIG_SOC_LPC55S36) +#define CONTROLLER_ID kUSB_ControllerLpcIp3511Fs0 +#elif defined(CONFIG_SOC_LPC55S69_CPU0) || defined(CONFIG_SOC_LPC55S69_CPU1) +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usbhs), okay) +#define CONTROLLER_ID kUSB_ControllerLpcIp3511Hs0 +#elif DT_NODE_HAS_STATUS(DT_NODELABEL(usbfs), okay) +#define CONTROLLER_ID kUSB_ControllerLpcIp3511Fs0 +#endif /* LPC55s69 */ +#elif defined(CONFIG_SOC_SERIES_IMX_RT) +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usb1), okay) +#define CONTROLLER_ID kUSB_ControllerEhci0 +#elif DT_NODE_HAS_STATUS(DT_NODELABEL(usb2), okay) +#define CONTROLLER_ID kUSB_ControllerEhci1 +#endif /* IMX RT */ +#else +/* If SOC has EHCI or LPCIP3511 then probably just need to add controller ID to this code */ +#error "USB driver does not yet support this SOC" +#endif /* CONTROLLER ID */ /* We do not need a buffer for the write side on platforms that have USB RAM. * The SDK driver will copy the data buffer to be sent to USB RAM. diff --git a/drivers/usb/device/usb_dc_native_posix.c b/drivers/usb/device/usb_dc_native_posix.c index 70410db24403183..c74dad9b35debc2 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_nrfx.c b/drivers/usb/device/usb_dc_nrfx.c index a8032baf1f13222..49cb46219117e6a 100644 --- a/drivers/usb/device/usb_dc_nrfx.c +++ b/drivers/usb/device/usb_dc_nrfx.c @@ -22,7 +22,8 @@ #include #include #include -#include +#include +#include #include @@ -288,12 +289,12 @@ static inline bool dev_ready(void) return get_usbd_ctx()->ready; } -static inline nrfx_usbd_ep_t ep_addr_to_nrfx(uint8_t ep) +static inline nrf_usbd_common_ep_t ep_addr_to_nrfx(uint8_t ep) { - return (nrfx_usbd_ep_t)ep; + return (nrf_usbd_common_ep_t)ep; } -static inline uint8_t nrfx_addr_to_ep(nrfx_usbd_ep_t ep) +static inline uint8_t nrfx_addr_to_ep(nrf_usbd_common_ep_t ep) { return (uint8_t)ep; } @@ -559,7 +560,7 @@ static void usbd_enable_endpoints(struct nrf_usbd_ctx *ctx) __ASSERT_NO_MSG(ep_ctx); if (ep_ctx->cfg.en) { - nrfx_usbd_ep_enable(ep_addr_to_nrfx(ep_ctx->cfg.addr)); + nrf_usbd_common_ep_enable(ep_addr_to_nrfx(ep_ctx->cfg.addr)); } } @@ -568,7 +569,7 @@ static void usbd_enable_endpoints(struct nrf_usbd_ctx *ctx) __ASSERT_NO_MSG(ep_ctx); if (ep_ctx->cfg.en) { - nrfx_usbd_ep_enable(ep_addr_to_nrfx(ep_ctx->cfg.addr)); + nrf_usbd_common_ep_enable(ep_addr_to_nrfx(ep_ctx->cfg.addr)); } } @@ -577,7 +578,7 @@ static void usbd_enable_endpoints(struct nrf_usbd_ctx *ctx) __ASSERT_NO_MSG(ep_ctx); if (ep_ctx->cfg.en) { - nrfx_usbd_ep_enable(ep_addr_to_nrfx(ep_ctx->cfg.addr)); + nrf_usbd_common_ep_enable(ep_addr_to_nrfx(ep_ctx->cfg.addr)); } } @@ -586,7 +587,7 @@ static void usbd_enable_endpoints(struct nrf_usbd_ctx *ctx) __ASSERT_NO_MSG(ep_ctx); if (ep_ctx->cfg.en) { - nrfx_usbd_ep_enable(ep_addr_to_nrfx(ep_ctx->cfg.addr)); + nrf_usbd_common_ep_enable(ep_addr_to_nrfx(ep_ctx->cfg.addr)); } } } @@ -606,7 +607,7 @@ static void ep_ctx_reset(struct nrf_usbd_ep_ctx *ep_ctx) /* Abort ongoing write operation. */ if (ep_ctx->write_in_progress) { - nrfx_usbd_ep_abort(ep_addr_to_nrfx(ep_ctx->cfg.addr)); + nrf_usbd_common_ep_abort(ep_addr_to_nrfx(ep_ctx->cfg.addr)); } ep_ctx->read_complete = true; @@ -673,9 +674,9 @@ static inline void usbd_work_process_pwr_events(struct usbd_pwr_event *pwr_evt) switch (pwr_evt->state) { case USBD_ATTACHED: - if (!nrfx_usbd_is_enabled()) { + if (!nrf_usbd_common_is_enabled()) { LOG_DBG("USB detected"); - nrfx_usbd_enable(); + nrf_usbd_common_enable(); err = hfxo_start(ctx); __ASSERT_NO_MSG(err >= 0); } @@ -687,7 +688,7 @@ static inline void usbd_work_process_pwr_events(struct usbd_pwr_event *pwr_evt) case USBD_POWERED: usbd_enable_endpoints(ctx); - nrfx_usbd_start(IS_ENABLED(CONFIG_USB_DEVICE_SOF)); + nrf_usbd_common_start(IS_ENABLED(CONFIG_USB_DEVICE_SOF)); ctx->ready = true; LOG_DBG("USB Powered"); @@ -699,7 +700,7 @@ static inline void usbd_work_process_pwr_events(struct usbd_pwr_event *pwr_evt) case USBD_DETACHED: ctx->ready = false; - nrfx_usbd_disable(); + nrf_usbd_common_disable(); err = hfxo_stop(ctx); __ASSERT_NO_MSG(err >= 0); @@ -712,7 +713,7 @@ static inline void usbd_work_process_pwr_events(struct usbd_pwr_event *pwr_evt) case USBD_SUSPENDED: if (dev_ready()) { - nrfx_usbd_suspend(); + nrf_usbd_common_suspend(); LOG_DBG("USB Suspend state"); if (ctx->status_cb) { @@ -771,7 +772,7 @@ static inline void usbd_work_process_setup(struct nrf_usbd_ep_ctx *ep_ctx) if (usb_reqtype_is_to_device(usbd_setup) && usbd_setup->wLength) { ctx->ctrl_read_len = usbd_setup->wLength; /* Allow data chunk on EP0 OUT */ - nrfx_usbd_setup_data_clear(); + nrf_usbd_common_setup_data_clear(); } else { ctx->ctrl_read_len = 0U; } @@ -791,9 +792,9 @@ static inline void usbd_work_process_recvreq(struct nrf_usbd_ctx *ctx, ep_ctx->read_complete = false; k_mutex_lock(&ctx->drv_lock, K_FOREVER); - NRFX_USBD_TRANSFER_OUT(transfer, ep_ctx->buf.data, - ep_ctx->cfg.max_sz); - nrfx_err_t err = nrfx_usbd_ep_transfer( + NRF_USBD_COMMON_TRANSFER_OUT(transfer, ep_ctx->buf.data, + ep_ctx->cfg.max_sz); + nrfx_err_t err = nrf_usbd_common_ep_transfer( ep_addr_to_nrfx(ep_ctx->cfg.addr), &transfer); if (err != NRFX_SUCCESS) { LOG_ERR("nRF USBD transfer error (OUT): 0x%02x", err); @@ -831,7 +832,7 @@ static inline void usbd_work_process_ep_events(struct usbd_ep_event *ep_evt) * no ZLP required. */ k_mutex_lock(&ctx->drv_lock, K_FOREVER); - nrfx_usbd_setup_clear(); + nrf_usbd_common_setup_clear(); k_mutex_unlock(&ctx->drv_lock); } ep_ctx->cfg.cb(ep_ctx->cfg.addr, @@ -842,14 +843,14 @@ static inline void usbd_work_process_ep_events(struct usbd_ep_event *ep_evt) } } -static void usbd_event_transfer_ctrl(nrfx_usbd_evt_t const *const p_event) +static void usbd_event_transfer_ctrl(nrf_usbd_common_evt_t const *const p_event) { struct nrf_usbd_ep_ctx *ep_ctx = endpoint_ctx(p_event->data.eptransfer.ep); if (NRF_USBD_EPIN_CHECK(p_event->data.eptransfer.ep)) { switch (p_event->data.eptransfer.status) { - case NRFX_USBD_EP_OK: { + case NRF_USBD_COMMON_EP_OK: { struct usbd_event *ev = usbd_evt_alloc(); if (!ev) { @@ -867,7 +868,7 @@ static void usbd_event_transfer_ctrl(nrfx_usbd_evt_t const *const p_event) } break; - case NRFX_USBD_EP_ABORTED: { + case NRF_USBD_COMMON_EP_ABORTED: { LOG_DBG("Endpoint 0x%02x write aborted", p_event->data.eptransfer.ep); } @@ -882,7 +883,7 @@ static void usbd_event_transfer_ctrl(nrfx_usbd_evt_t const *const p_event) } } else { switch (p_event->data.eptransfer.status) { - case NRFX_USBD_EP_WAITING: { + case NRF_USBD_COMMON_EP_WAITING: { struct usbd_event *ev = usbd_evt_alloc(); if (!ev) { @@ -901,23 +902,23 @@ static void usbd_event_transfer_ctrl(nrfx_usbd_evt_t const *const p_event) } break; - case NRFX_USBD_EP_OK: { + case NRF_USBD_COMMON_EP_OK: { struct nrf_usbd_ctx *ctx = get_usbd_ctx(); struct usbd_event *ev = usbd_evt_alloc(); if (!ev) { return; } - nrfx_usbd_ep_status_t err_code; + nrf_usbd_common_ep_status_t err_code; ev->evt_type = USBD_EVT_EP; ev->evt.ep_evt.evt_type = EP_EVT_RECV_COMPLETE; ev->evt.ep_evt.ep = ep_ctx; - err_code = nrfx_usbd_ep_status_get( + err_code = nrf_usbd_common_ep_status_get( p_event->data.eptransfer.ep, &ep_ctx->buf.len); - if (err_code != NRFX_USBD_EP_OK) { + if (err_code != NRF_USBD_COMMON_EP_OK) { LOG_ERR("_ep_status_get failed! Code: %d", err_code); __ASSERT_NO_MSG(0); @@ -927,7 +928,7 @@ static void usbd_event_transfer_ctrl(nrfx_usbd_evt_t const *const p_event) if (ctx->ctrl_read_len > ep_ctx->buf.len) { ctx->ctrl_read_len -= ep_ctx->buf.len; /* Allow next data chunk on EP0 OUT */ - nrfx_usbd_setup_data_clear(); + nrf_usbd_common_setup_data_clear(); } else { ctx->ctrl_read_len = 0U; } @@ -947,14 +948,14 @@ static void usbd_event_transfer_ctrl(nrfx_usbd_evt_t const *const p_event) } } -static void usbd_event_transfer_data(nrfx_usbd_evt_t const *const p_event) +static void usbd_event_transfer_data(nrf_usbd_common_evt_t const *const p_event) { struct nrf_usbd_ep_ctx *ep_ctx = endpoint_ctx(p_event->data.eptransfer.ep); if (NRF_USBD_EPIN_CHECK(p_event->data.eptransfer.ep)) { switch (p_event->data.eptransfer.status) { - case NRFX_USBD_EP_OK: { + case NRF_USBD_COMMON_EP_OK: { struct usbd_event *ev = usbd_evt_alloc(); if (!ev) { @@ -973,7 +974,7 @@ static void usbd_event_transfer_data(nrfx_usbd_evt_t const *const p_event) } break; - case NRFX_USBD_EP_ABORTED: { + case NRF_USBD_COMMON_EP_ABORTED: { LOG_DBG("Endpoint 0x%02x write aborted", p_event->data.eptransfer.ep); } @@ -989,7 +990,7 @@ static void usbd_event_transfer_data(nrfx_usbd_evt_t const *const p_event) } else { switch (p_event->data.eptransfer.status) { - case NRFX_USBD_EP_WAITING: { + case NRF_USBD_COMMON_EP_WAITING: { struct usbd_event *ev = usbd_evt_alloc(); if (!ev) { @@ -1009,7 +1010,7 @@ static void usbd_event_transfer_data(nrfx_usbd_evt_t const *const p_event) } break; - case NRFX_USBD_EP_OK: { + case NRF_USBD_COMMON_EP_OK: { struct usbd_event *ev = usbd_evt_alloc(); if (!ev) { @@ -1045,42 +1046,42 @@ static void usbd_event_transfer_data(nrfx_usbd_evt_t const *const p_event) /** * @brief nRFx USBD driver event handler function. */ -static void usbd_event_handler(nrfx_usbd_evt_t const *const p_event) +static void usbd_event_handler(nrf_usbd_common_evt_t const *const p_event) { struct usbd_event evt = {0}; bool put_evt = false; switch (p_event->type) { - case NRFX_USBD_EVT_SUSPEND: + case NRF_USBD_COMMON_EVT_SUSPEND: LOG_DBG("SUSPEND state detected"); evt.evt_type = USBD_EVT_POWER; evt.evt.pwr_evt.state = USBD_SUSPENDED; put_evt = true; break; - case NRFX_USBD_EVT_RESUME: + case NRF_USBD_COMMON_EVT_RESUME: LOG_DBG("RESUMING from suspend"); evt.evt_type = USBD_EVT_POWER; evt.evt.pwr_evt.state = USBD_RESUMED; put_evt = true; break; - case NRFX_USBD_EVT_WUREQ: + case NRF_USBD_COMMON_EVT_WUREQ: LOG_DBG("RemoteWU initiated"); evt.evt_type = USBD_EVT_POWER; evt.evt.pwr_evt.state = USBD_RESUMED; put_evt = true; break; - case NRFX_USBD_EVT_RESET: + case NRF_USBD_COMMON_EVT_RESET: evt.evt_type = USBD_EVT_RESET; put_evt = true; break; - case NRFX_USBD_EVT_SOF: + case NRF_USBD_COMMON_EVT_SOF: if (IS_ENABLED(CONFIG_USB_DEVICE_SOF)) { evt.evt_type = USBD_EVT_SOF; put_evt = true; } break; - case NRFX_USBD_EVT_EPTRANSFER: { + case NRF_USBD_COMMON_EVT_EPTRANSFER: { struct nrf_usbd_ep_ctx *ep_ctx; ep_ctx = endpoint_ctx(p_event->data.eptransfer.ep); @@ -1101,10 +1102,10 @@ static void usbd_event_handler(nrfx_usbd_evt_t const *const p_event) break; } - case NRFX_USBD_EVT_SETUP: { - nrfx_usbd_setup_t drv_setup; + case NRF_USBD_COMMON_EVT_SETUP: { + nrf_usbd_common_setup_t drv_setup; - nrfx_usbd_setup_get(&drv_setup); + nrf_usbd_common_setup_get(&drv_setup); if ((drv_setup.bRequest != USB_SREQ_SET_ADDRESS) || (USB_REQTYPE_GET_TYPE(drv_setup.bmRequestType) != USB_REQTYPE_TYPE_STANDARD)) { @@ -1147,8 +1148,8 @@ static inline void usbd_reinit(void) nrfx_err_t err; nrfx_power_usbevt_disable(); - nrfx_usbd_disable(); - nrfx_usbd_uninit(); + nrf_usbd_common_disable(); + nrf_usbd_common_uninit(); usbd_evt_flush(); @@ -1156,7 +1157,7 @@ static inline void usbd_reinit(void) __ASSERT_NO_MSG(ret == 0); nrfx_power_usbevt_enable(); - err = nrfx_usbd_init(usbd_event_handler); + err = nrf_usbd_common_init(usbd_event_handler); if (err != NRFX_SUCCESS) { LOG_DBG("nRF USBD driver reinit failed. Code: %d", err); @@ -1177,7 +1178,7 @@ static void usbd_sof_trigger_iso_read(void) struct usbd_event *ev; struct nrf_usbd_ep_ctx *ep_ctx; - ep_ctx = endpoint_ctx(NRFX_USBD_EPOUT8); + ep_ctx = endpoint_ctx(NRF_USBD_COMMON_EPOUT8); if (!ep_ctx) { LOG_ERR("There is no ISO ep"); return; @@ -1281,7 +1282,7 @@ int usb_dc_attach(void) (CLOCK_CONTROL_NRF_SUBSYS_HF))); IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), - nrfx_isr, nrfx_usbd_irq_handler, 0); + nrfx_isr, nrf_usbd_common_irq_handler, 0); nrfx_power_usbevt_enable(); @@ -1316,8 +1317,8 @@ int usb_dc_detach(void) usbd_evt_flush(); - if (nrfx_usbd_is_enabled()) { - nrfx_usbd_disable(); + if (nrf_usbd_common_is_enabled()) { + nrf_usbd_common_disable(); } (void)hfxo_stop(ctx); @@ -1440,8 +1441,8 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const ep_cfg) } } - nrfx_usbd_ep_max_packet_size_set(ep_addr_to_nrfx(ep_cfg->ep_addr), - ep_cfg->ep_mps); + nrf_usbd_common_ep_max_packet_size_set(ep_addr_to_nrfx(ep_cfg->ep_addr), + ep_cfg->ep_mps); return 0; } @@ -1461,11 +1462,11 @@ int usb_dc_ep_set_stall(const uint8_t ep) switch (ep_ctx->cfg.type) { case USB_DC_EP_CONTROL: - nrfx_usbd_setup_stall(); + nrf_usbd_common_setup_stall(); break; case USB_DC_EP_BULK: case USB_DC_EP_INTERRUPT: - nrfx_usbd_ep_stall(ep_addr_to_nrfx(ep)); + nrf_usbd_common_ep_stall(ep_addr_to_nrfx(ep)); break; case USB_DC_EP_ISOCHRONOUS: LOG_ERR("STALL unsupported on ISO endpoint"); @@ -1499,8 +1500,8 @@ int usb_dc_ep_clear_stall(const uint8_t ep) return -EINVAL; } - nrfx_usbd_ep_dtoggle_clear(ep_addr_to_nrfx(ep)); - nrfx_usbd_ep_stall_clear(ep_addr_to_nrfx(ep)); + nrf_usbd_common_ep_dtoggle_clear(ep_addr_to_nrfx(ep)); + nrf_usbd_common_ep_stall_clear(ep_addr_to_nrfx(ep)); LOG_DBG("Unstall on EP 0x%02x", ep); return 0; @@ -1528,7 +1529,7 @@ int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled) return -EINVAL; } - *stalled = (uint8_t) nrfx_usbd_ep_stall_check(ep_addr_to_nrfx(ep)); + *stalled = (uint8_t) nrf_usbd_common_ep_stall_check(ep_addr_to_nrfx(ep)); return 0; } @@ -1550,11 +1551,11 @@ int usb_dc_ep_enable(const uint8_t ep) /* ISO transactions for full-speed device do not support * toggle sequencing and should only send DATA0 PID. */ - nrfx_usbd_ep_dtoggle_clear(ep_addr_to_nrfx(ep)); + nrf_usbd_common_ep_dtoggle_clear(ep_addr_to_nrfx(ep)); /** Endpoint is enabled on SetInterface request. * This should also clear EP's halt status. */ - nrfx_usbd_ep_stall_clear(ep_addr_to_nrfx(ep)); + nrf_usbd_common_ep_stall_clear(ep_addr_to_nrfx(ep)); } if (ep_ctx->cfg.en) { return -EALREADY; @@ -1566,7 +1567,7 @@ int usb_dc_ep_enable(const uint8_t ep) /* Defer the endpoint enable if USBD is not ready yet. */ if (dev_ready()) { - nrfx_usbd_ep_enable(ep_addr_to_nrfx(ep)); + nrf_usbd_common_ep_enable(ep_addr_to_nrfx(ep)); } return 0; @@ -1587,8 +1588,8 @@ int usb_dc_ep_disable(const uint8_t ep) LOG_DBG("EP disable: 0x%02x", ep); - nrfx_usbd_ep_disable(ep_addr_to_nrfx(ep)); - /* Clear write_in_progress as nrfx_usbd_ep_disable() + nrf_usbd_common_ep_disable(ep_addr_to_nrfx(ep)); + /* Clear write_in_progress as nrf_usbd_common_ep_disable() * terminates endpoint transaction. */ ep_ctx->write_in_progress = false; @@ -1614,7 +1615,7 @@ int usb_dc_ep_flush(const uint8_t ep) ep_ctx->buf.len = 0U; ep_ctx->buf.curr = ep_ctx->buf.data; - nrfx_usbd_transfer_out_drop(ep_addr_to_nrfx(ep)); + nrf_usbd_common_transfer_out_drop(ep_addr_to_nrfx(ep)); return 0; } @@ -1682,15 +1683,15 @@ int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data, * and perform appropriate action. */ if ((ep_ctx->cfg.type == USB_DC_EP_CONTROL) - && (nrfx_usbd_last_setup_dir_get() != ep)) { - nrfx_usbd_setup_clear(); + && (nrf_usbd_common_last_setup_dir_get() != ep)) { + nrf_usbd_common_setup_clear(); k_mutex_unlock(&ctx->drv_lock); return 0; } ep_ctx->write_in_progress = true; - NRFX_USBD_TRANSFER_IN(transfer, data, data_len, 0); - nrfx_err_t err = nrfx_usbd_ep_transfer(ep_addr_to_nrfx(ep), &transfer); + NRF_USBD_COMMON_TRANSFER_IN(transfer, data, data_len, 0); + nrfx_err_t err = nrf_usbd_common_ep_transfer(ep_addr_to_nrfx(ep), &transfer); if (err != NRFX_SUCCESS) { ep_ctx->write_in_progress = false; @@ -1870,7 +1871,7 @@ int usb_dc_ep_mps(const uint8_t ep) int usb_dc_wakeup_request(void) { - bool res = nrfx_usbd_wakeup_req(); + bool res = nrf_usbd_common_wakeup_req(); if (!res) { return -EAGAIN; @@ -1906,7 +1907,7 @@ static int usb_init(void) .handler = usb_dc_power_event_handler }; - err = nrfx_usbd_init(usbd_event_handler); + err = nrf_usbd_common_init(usbd_event_handler); if (err != NRFX_SUCCESS) { LOG_DBG("nRF USBD driver init failed. Code: %d", (uint32_t)err); return -EIO; diff --git a/drivers/usb/device/usb_dc_rpi_pico.c b/drivers/usb/device/usb_dc_rpi_pico.c index bcc5e93151ba260..bb99fa365b285ea 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 c5516b73aef6fa1..13131061610064c 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 83e67c157ced992..000000000000000 --- 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 f4f729cb1818801..ebca5f6427753e7 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 ef1e01d82d26c8a..5b19a3385ad9f85 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 000000000000000..e7f7e782325d00f --- /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/Kconfig.nrf b/drivers/usb/udc/Kconfig.nrf index 0f424ffe5d02db8..93c5090bed2a225 100644 --- a/drivers/usb/udc/Kconfig.nrf +++ b/drivers/usb/udc/Kconfig.nrf @@ -5,7 +5,7 @@ config UDC_NRF bool "Nordic Semiconductor USB device controller driver" default y depends on DT_HAS_NORDIC_NRF_USBD_ENABLED - select NRFX_USBD + select NRF_USBD_COMMON select NRFX_POWER help nRF USB device controller driver. diff --git a/drivers/usb/udc/udc_dwc2.c b/drivers/usb/udc/udc_dwc2.c new file mode 100644 index 000000000000000..c38e03157b62686 --- /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 000000000000000..11d8178c135b0b0 --- /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 000000000000000..104cb5cb8474f16 --- /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 4610aff19f874bd..d4ecc130587c42a 100644 --- a/drivers/usb/udc/udc_nrf.c +++ b/drivers/usb/udc/udc_nrf.c @@ -21,7 +21,8 @@ #include #include -#include +#include +#include #include #include "udc_common.h" @@ -47,7 +48,7 @@ enum udc_nrf_event_type { struct udc_nrf_evt { enum udc_nrf_event_type type; union { - nrfx_usbd_evt_t hal_evt; + nrf_usbd_common_evt_t hal_evt; uint8_t ep; }; }; @@ -82,10 +83,10 @@ static struct onoff_client hfxo_cli; static void udc_nrf_clear_control_out(const struct device *dev) { - if (nrfx_usbd_last_setup_dir_get() == USB_CONTROL_EP_OUT && + if (nrf_usbd_common_last_setup_dir_get() == USB_CONTROL_EP_OUT && udc_nrf_setup_rcvd) { /* Allow data chunk on EP0 OUT */ - nrfx_usbd_setup_data_clear(); + nrf_usbd_common_setup_data_clear(); udc_nrf_setup_rcvd = false; LOG_INF("Allow data OUT"); } @@ -101,15 +102,15 @@ static void udc_event_xfer_in_next(const struct device *dev, const uint8_t ep) buf = udc_buf_peek(dev, ep); if (buf != NULL) { - nrfx_usbd_transfer_t xfer = { + nrf_usbd_common_transfer_t xfer = { .p_data = {.tx = buf->data}, .size = buf->len, .flags = udc_ep_buf_has_zlp(buf) ? - NRFX_USBD_TRANSFER_ZLP_FLAG : 0, + NRF_USBD_COMMON_TRANSFER_ZLP_FLAG : 0, }; nrfx_err_t err; - err = nrfx_usbd_ep_transfer(ep, &xfer); + err = nrf_usbd_common_ep_transfer(ep, &xfer); if (err != NRFX_SUCCESS) { LOG_ERR("ep 0x%02x nrfx error: %x", ep, err); /* REVISE: remove from endpoint queue? ASSERT? */ @@ -141,7 +142,7 @@ static void udc_event_xfer_ctrl_in(const struct device *dev, /* Update to next stage of control transfer */ udc_ctrl_update_stage(dev, buf); - nrfx_usbd_setup_clear(); + nrf_usbd_common_setup_clear(); } static void udc_event_fake_status_in(const struct device *dev) @@ -159,13 +160,13 @@ static void udc_event_fake_status_in(const struct device *dev) } static void udc_event_xfer_in(const struct device *dev, - nrfx_usbd_evt_t const *const event) + nrf_usbd_common_evt_t const *const event) { uint8_t ep = event->data.eptransfer.ep; struct net_buf *buf; switch (event->data.eptransfer.status) { - case NRFX_USBD_EP_OK: + case NRF_USBD_COMMON_EP_OK: buf = udc_buf_get(dev, ep); if (buf == NULL) { LOG_ERR("ep 0x%02x queue is empty", ep); @@ -181,7 +182,7 @@ static void udc_event_xfer_in(const struct device *dev, udc_submit_ep_event(dev, buf, 0); break; - case NRFX_USBD_EP_ABORTED: + case NRF_USBD_COMMON_EP_ABORTED: LOG_WRN("aborted IN ep 0x%02x", ep); buf = udc_buf_get_all(dev, ep); @@ -228,14 +229,14 @@ static void udc_event_xfer_out_next(const struct device *dev, const uint8_t ep) buf = udc_buf_peek(dev, ep); if (buf != NULL) { - nrfx_usbd_transfer_t xfer = { + nrf_usbd_common_transfer_t xfer = { .p_data = {.rx = buf->data}, .size = buf->size, .flags = 0, }; nrfx_err_t err; - err = nrfx_usbd_ep_transfer(ep, &xfer); + err = nrf_usbd_common_ep_transfer(ep, &xfer); if (err != NRFX_SUCCESS) { LOG_ERR("ep 0x%02x nrfx error: %x", ep, err); /* REVISE: remove from endpoint queue? ASSERT? */ @@ -249,24 +250,24 @@ static void udc_event_xfer_out_next(const struct device *dev, const uint8_t ep) } static void udc_event_xfer_out(const struct device *dev, - nrfx_usbd_evt_t const *const event) + nrf_usbd_common_evt_t const *const event) { uint8_t ep = event->data.eptransfer.ep; - nrfx_usbd_ep_status_t err_code; + nrf_usbd_common_ep_status_t err_code; struct net_buf *buf; size_t len; switch (event->data.eptransfer.status) { - case NRFX_USBD_EP_WAITING: + case NRF_USBD_COMMON_EP_WAITING: /* * There is nothing to do here, new transfer * will be tried in both cases later. */ break; - case NRFX_USBD_EP_OK: - err_code = nrfx_usbd_ep_status_get(ep, &len); - if (err_code != NRFX_USBD_EP_OK) { + case NRF_USBD_COMMON_EP_OK: + err_code = nrf_usbd_common_ep_status_get(ep, &len); + if (err_code != NRF_USBD_COMMON_EP_OK) { LOG_ERR("OUT transfer failed %d", err_code); } @@ -325,8 +326,8 @@ static int udc_event_xfer_setup(const struct device *dev) } udc_ep_buf_set_setup(buf); - nrfx_usbd_setup_get((nrfx_usbd_setup_t *)buf->data); - net_buf_add(buf, sizeof(nrfx_usbd_setup_t)); + nrf_usbd_common_setup_get((nrf_usbd_common_setup_t *)buf->data); + net_buf_add(buf, sizeof(nrf_usbd_common_setup_t)); udc_nrf_setup_rcvd = true; /* Update to next stage of control transfer */ @@ -348,8 +349,13 @@ static int udc_event_xfer_setup(const struct device *dev) return err; } -static void udc_nrf_thread(const struct device *dev) +static void udc_nrf_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; + while (true) { bool start_xfer = false; struct udc_nrf_evt evt; @@ -361,7 +367,7 @@ static void udc_nrf_thread(const struct device *dev) case UDC_NRF_EVT_HAL: ep = evt.hal_evt.data.eptransfer.ep; switch (evt.hal_evt.type) { - case NRFX_USBD_EVT_EPTRANSFER: + case NRF_USBD_COMMON_EVT_EPTRANSFER: start_xfer = true; if (USB_EP_DIR_IS_IN(ep)) { udc_event_xfer_in(dev, &evt.hal_evt); @@ -369,7 +375,7 @@ static void udc_nrf_thread(const struct device *dev) udc_event_xfer_out(dev, &evt.hal_evt); } break; - case NRFX_USBD_EVT_SETUP: + case NRF_USBD_COMMON_EVT_SETUP: udc_event_xfer_setup(dev); break; default: @@ -414,33 +420,35 @@ static void udc_sof_check_iso_out(const struct device *dev) } } -static void usbd_event_handler(nrfx_usbd_evt_t const *const hal_evt) +static void usbd_event_handler(nrf_usbd_common_evt_t const *const hal_evt) { switch (hal_evt->type) { - case NRFX_USBD_EVT_SUSPEND: + case NRF_USBD_COMMON_EVT_SUSPEND: LOG_INF("SUSPEND state detected"); - nrfx_usbd_suspend(); + nrf_usbd_common_suspend(); udc_set_suspended(udc_nrf_dev, true); udc_submit_event(udc_nrf_dev, UDC_EVT_SUSPEND, 0); break; - case NRFX_USBD_EVT_RESUME: + case NRF_USBD_COMMON_EVT_RESUME: LOG_INF("RESUMING from suspend"); udc_set_suspended(udc_nrf_dev, false); udc_submit_event(udc_nrf_dev, UDC_EVT_RESUME, 0); break; - case NRFX_USBD_EVT_WUREQ: + 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 NRFX_USBD_EVT_RESET: + case NRF_USBD_COMMON_EVT_RESET: LOG_INF("Reset"); udc_submit_event(udc_nrf_dev, UDC_EVT_RESET, 0); break; - case NRFX_USBD_EVT_SOF: + case NRF_USBD_COMMON_EVT_SOF: udc_submit_event(udc_nrf_dev, UDC_EVT_SOF, 0); udc_sof_check_iso_out(udc_nrf_dev); break; - case NRFX_USBD_EVT_EPTRANSFER: - case NRFX_USBD_EVT_SETUP: { + case NRF_USBD_COMMON_EVT_EPTRANSFER: + case NRF_USBD_COMMON_EVT_SETUP: { struct udc_nrf_evt evt = { .type = UDC_NRF_EVT_HAL, .hal_evt = *hal_evt, @@ -466,7 +474,7 @@ static void udc_nrf_power_handler(nrfx_power_usb_evt_t pwr_evt) case NRFX_POWER_USB_EVT_READY: LOG_INF("POWER event ready"); udc_submit_event(udc_nrf_dev, UDC_EVT_VBUS_READY, 0); - nrfx_usbd_start(true); + nrf_usbd_common_start(true); break; case NRFX_POWER_USB_EVT_REMOVED: LOG_INF("POWER event removed"); @@ -484,7 +492,7 @@ static void udc_nrf_fake_status_in(const struct device *dev) .ep = USB_CONTROL_EP_IN, }; - if (nrfx_usbd_last_setup_dir_get() == USB_CONTROL_EP_OUT) { + if (nrf_usbd_common_last_setup_dir_get() == USB_CONTROL_EP_OUT) { /* Let controller perform status IN stage */ k_msgq_put(&drv_msgq, &evt, K_NO_WAIT); } @@ -514,9 +522,9 @@ static int udc_nrf_ep_enqueue(const struct device *dev, static int udc_nrf_ep_dequeue(const struct device *dev, struct udc_ep_config *cfg) { - bool busy = nrfx_usbd_ep_is_busy(cfg->addr); + bool busy = nrf_usbd_common_ep_is_busy(cfg->addr); - nrfx_usbd_ep_abort(cfg->addr); + nrf_usbd_common_ep_abort(cfg->addr); if (USB_EP_DIR_IS_OUT(cfg->addr) || !busy) { struct net_buf *buf; @@ -545,14 +553,14 @@ static int udc_nrf_ep_enable(const struct device *dev, __ASSERT_NO_MSG(cfg); mps = (cfg->mps == 0) ? cfg->caps.mps : cfg->mps; - nrfx_usbd_ep_max_packet_size_set(cfg->addr, mps); - nrfx_usbd_ep_enable(cfg->addr); + nrf_usbd_common_ep_max_packet_size_set(cfg->addr, mps); + nrf_usbd_common_ep_enable(cfg->addr); if (!NRF_USBD_EPISO_CHECK(cfg->addr)) { /* ISO transactions for full-speed device do not support * toggle sequencing and should only send DATA0 PID. */ - nrfx_usbd_ep_dtoggle_clear(cfg->addr); - nrfx_usbd_ep_stall_clear(cfg->addr); + nrf_usbd_common_ep_dtoggle_clear(cfg->addr); + nrf_usbd_common_ep_stall_clear(cfg->addr); } LOG_DBG("Enable ep 0x%02x", cfg->addr); @@ -564,7 +572,7 @@ static int udc_nrf_ep_disable(const struct device *dev, struct udc_ep_config *cfg) { __ASSERT_NO_MSG(cfg); - nrfx_usbd_ep_disable(cfg->addr); + nrf_usbd_common_ep_disable(cfg->addr); LOG_DBG("Disable ep 0x%02x", cfg->addr); return 0; @@ -577,9 +585,9 @@ static int udc_nrf_ep_set_halt(const struct device *dev, if (cfg->addr == USB_CONTROL_EP_OUT || cfg->addr == USB_CONTROL_EP_IN) { - nrfx_usbd_setup_stall(); + nrf_usbd_common_setup_stall(); } else { - nrfx_usbd_ep_stall(cfg->addr); + nrf_usbd_common_ep_stall(cfg->addr); } return 0; @@ -590,8 +598,8 @@ static int udc_nrf_ep_clear_halt(const struct device *dev, { LOG_DBG("Clear halt ep 0x%02x", cfg->addr); - nrfx_usbd_ep_dtoggle_clear(cfg->addr); - nrfx_usbd_ep_stall_clear(cfg->addr); + nrf_usbd_common_ep_dtoggle_clear(cfg->addr); + nrf_usbd_common_ep_stall_clear(cfg->addr); return 0; } @@ -611,7 +619,7 @@ static int udc_nrf_set_address(const struct device *dev, const uint8_t addr) static int udc_nrf_host_wakeup(const struct device *dev) { - bool res = nrfx_usbd_wakeup_req(); + bool res = nrf_usbd_common_wakeup_req(); LOG_DBG("Host wakeup request"); if (!res) { @@ -625,7 +633,7 @@ static int udc_nrf_enable(const struct device *dev) { int ret; - nrfx_usbd_enable(); + nrf_usbd_common_enable(); sys_notify_init_spinwait(&hfxo_cli.notify); ret = onoff_request(hfxo_mgr, &hfxo_cli); @@ -641,7 +649,7 @@ static int udc_nrf_disable(const struct device *dev) { int ret; - nrfx_usbd_disable(); + nrf_usbd_common_disable(); ret = onoff_cancel_or_release(hfxo_mgr, &hfxo_cli); if (ret < 0) { @@ -670,12 +678,12 @@ static int udc_nrf_init(const struct device *dev) #endif IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), - nrfx_isr, nrfx_usbd_irq_handler, 0); + nrfx_isr, nrf_usbd_common_irq_handler, 0); (void)nrfx_power_init(&cfg->pwr); nrfx_power_usbevt_init(&cfg->evt); - ret = nrfx_usbd_init(usbd_event_handler); + ret = nrf_usbd_common_init(usbd_event_handler); if (ret != NRFX_SUCCESS) { LOG_ERR("nRF USBD driver initialization failed"); return -EIO; @@ -714,7 +722,7 @@ static int udc_nrf_shutdown(const struct device *dev) } nrfx_power_usbevt_disable(); - nrfx_usbd_uninit(); + nrf_usbd_common_uninit(); nrfx_power_usbevt_uninit(); #ifdef CONFIG_HAS_HW_NRF_USBREG irq_disable(USBREGULATOR_IRQn); @@ -733,7 +741,7 @@ static int udc_nrf_driver_init(const struct device *dev) k_mutex_init(&data->mutex); k_thread_create(&drv_stack_data, drv_stack, K_KERNEL_STACK_SIZEOF(drv_stack), - (k_thread_entry_t)udc_nrf_thread, + udc_nrf_thread, (void *)dev, NULL, NULL, K_PRIO_COOP(8), 0, K_NO_WAIT); @@ -743,14 +751,14 @@ static int udc_nrf_driver_init(const struct device *dev) ep_cfg_out[i].caps.out = 1; if (i == 0) { ep_cfg_out[i].caps.control = 1; - ep_cfg_out[i].caps.mps = NRFX_USBD_EPSIZE; + ep_cfg_out[i].caps.mps = NRF_USBD_COMMON_EPSIZE; } else if (i < (CFG_EPOUT_CNT + 1)) { ep_cfg_out[i].caps.bulk = 1; ep_cfg_out[i].caps.interrupt = 1; - ep_cfg_out[i].caps.mps = NRFX_USBD_EPSIZE; + ep_cfg_out[i].caps.mps = NRF_USBD_COMMON_EPSIZE; } else { ep_cfg_out[i].caps.iso = 1; - ep_cfg_out[i].caps.mps = NRFX_USBD_ISOSIZE / 2; + ep_cfg_out[i].caps.mps = NRF_USBD_COMMON_ISOSIZE / 2; } ep_cfg_out[i].addr = USB_EP_DIR_OUT | i; @@ -765,14 +773,14 @@ static int udc_nrf_driver_init(const struct device *dev) ep_cfg_in[i].caps.in = 1; if (i == 0) { ep_cfg_in[i].caps.control = 1; - ep_cfg_in[i].caps.mps = NRFX_USBD_EPSIZE; + ep_cfg_in[i].caps.mps = NRF_USBD_COMMON_EPSIZE; } else if (i < (CFG_EPIN_CNT + 1)) { ep_cfg_in[i].caps.bulk = 1; ep_cfg_in[i].caps.interrupt = 1; - ep_cfg_in[i].caps.mps = NRFX_USBD_EPSIZE; + ep_cfg_in[i].caps.mps = NRF_USBD_COMMON_EPSIZE; } else { ep_cfg_in[i].caps.iso = 1; - ep_cfg_in[i].caps.mps = NRFX_USBD_ISOSIZE / 2; + ep_cfg_in[i].caps.mps = NRF_USBD_COMMON_ISOSIZE / 2; } ep_cfg_in[i].addr = USB_EP_DIR_IN | i; diff --git a/drivers/usb/udc/udc_stm32.c b/drivers/usb/udc/udc_stm32.c index 88070329cc30a96..e11228619b8f357 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/uhc/uhc_max3421e.c b/drivers/usb/uhc/uhc_max3421e.c index a7955631fb99252..ac9aa2a526dff4c 100644 --- a/drivers/usb/uhc/uhc_max3421e.c +++ b/drivers/usb/uhc/uhc_max3421e.c @@ -652,8 +652,12 @@ static int max3421e_handle_bus_irq(const struct device *dev) return ret; } -static void uhc_max3421e_thread(const struct device *dev) +static void uhc_max3421e_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; struct max3421e_data *priv = uhc_get_private(dev); LOG_DBG("MAX3421E thread started"); @@ -1076,7 +1080,7 @@ static int max3421e_driver_init(const struct device *dev) k_mutex_init(&data->mutex); k_thread_create(&drv_stack_data, drv_stack, K_KERNEL_STACK_SIZEOF(drv_stack), - (k_thread_entry_t)uhc_max3421e_thread, + uhc_max3421e_thread, (void *)dev, NULL, NULL, K_PRIO_COOP(2), 0, K_NO_WAIT); k_thread_name_set(&drv_stack_data, "uhc_max3421e"); diff --git a/drivers/usb_c/CMakeLists.txt b/drivers/usb_c/CMakeLists.txt index d576f955cec220b..9629bbad2f62a35 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 f62da2a67c7d0b8..b30259c80b437a9 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 000000000000000..dc3fc83988cc57a --- /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 000000000000000..c3fc93e1f4e3192 --- /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 000000000000000..1d1de6a49e9c2c0 --- /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 000000000000000..8b6a2fe914d8e3f --- /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 000000000000000..b033be4a730510b --- /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 000000000000000..a69db474ce88a3d --- /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/usb_c/tcpc/CMakeLists.txt b/drivers/usb_c/tcpc/CMakeLists.txt index b81aa5224d6607f..cc5eaf71ea6447e 100644 --- a/drivers/usb_c/tcpc/CMakeLists.txt +++ b/drivers/usb_c/tcpc/CMakeLists.txt @@ -2,4 +2,5 @@ zephyr_library() +zephyr_library_sources_ifdef(CONFIG_USBC_TCPC_SHELL shell.c) zephyr_library_sources_ifdef(CONFIG_USBC_TCPC_STM32 ucpd_stm32.c) diff --git a/drivers/usb_c/tcpc/Kconfig b/drivers/usb_c/tcpc/Kconfig index 51b9a79c394b755..8d0e2ad1017e1d9 100644 --- a/drivers/usb_c/tcpc/Kconfig +++ b/drivers/usb_c/tcpc/Kconfig @@ -19,6 +19,12 @@ config USBC_TCPC_INIT_PRIORITY Note that the priority needs to be lower than the USBC stack so that it can start before the USBC sub-system. +config USBC_TCPC_SHELL + bool "Shell commands for TCPC subsystem" + help + Enable support for TCPC shell commands that helps with USB-C diagnostics. + Example functions are printing vbus, chip information and dumping registers. + source "drivers/usb_c/tcpc/Kconfig.tcpc_stm32" module = USBC diff --git a/drivers/usb_c/tcpc/shell.c b/drivers/usb_c/tcpc/shell.c new file mode 100644 index 000000000000000..43ea2a9077cb787 --- /dev/null +++ b/drivers/usb_c/tcpc/shell.c @@ -0,0 +1,157 @@ +/* + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +/** Macro used to call the dump_std_reg function from the TCPC device pointer */ +#define TCPC_DUMP_DEV(dev) ret |= tcpc_dump_std_reg(dev); + +/** Macro used to call the dump_std_reg function from the USB-C connector node */ +#define TCPC_DUMP_CONN_NODE(node) TCPC_DUMP_DEV(DEVICE_DT_GET(DT_PROP(node, tcpc))) + +/** Macro used to call the vbus_measure function from the VBUS device pointer */ +#define TCPC_VBUS_DEV(dev) \ + { \ + int val; \ + ret |= usbc_vbus_measure(dev, &val); \ + shell_print(sh, "%s vbus: %d mV", dev->name, val); \ + } + +/** Macro used to call the vbus_measure function from the USB-C connector node */ +#define TCPC_VBUS_CONN_NODE(node) TCPC_VBUS_DEV(DEVICE_DT_GET(DT_PROP(node, vbus))) + +/** Macro used to call the get_chip function from the TCPC device pointer */ +#define TCPC_GET_CHIP_DEV(dev) \ + { \ + ret |= tcpc_get_chip_info(dev, &chip_info); \ + shell_print(sh, "Chip: %s", dev->name); \ + shell_print(sh, "\tVendor: %04x", chip_info.vendor_id); \ + shell_print(sh, "\tProduct: %04x", chip_info.product_id); \ + shell_print(sh, "\tDevice: %04x", chip_info.device_id); \ + shell_print(sh, "\tFirmware: %llx", chip_info.fw_version_number); \ + } + +/** Macro used to call the get_chip function from the USB-C connector node */ +#define TCPC_GET_CHIP_CONN_NODE(node) TCPC_GET_CHIP_DEV(DEVICE_DT_GET(DT_PROP(node, tcpc))) + +/** + * @brief Shell command that dumps standard registers of TCPCs for all available USB-C ports + * + * @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_tcpc_dump(const struct shell *sh, size_t argc, char **argv) +{ + int ret = 0; + + if (argc <= 1) { + DT_FOREACH_STATUS_OKAY(usb_c_connector, TCPC_DUMP_CONN_NODE); + } else { + const struct device *dev = device_get_binding(argv[1]); + + if (dev != NULL) { + TCPC_DUMP_DEV(dev); + } else { + ret = -ENODEV; + } + } + + return ret; +} + +/** + * @brief Shell command that prints the vbus measures for all available USB-C ports + * + * @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_tcpc_vbus(const struct shell *sh, size_t argc, char **argv) +{ + int ret = 0; + + if (argc <= 1) { + DT_FOREACH_STATUS_OKAY(usb_c_connector, TCPC_VBUS_CONN_NODE); + } else { + const struct device *dev = device_get_binding(argv[1]); + + if (dev != NULL) { + TCPC_VBUS_DEV(dev); + } else { + ret = -ENODEV; + } + } + + return ret; +} + +/** + * @brief Shell command that prints the TCPCs chips information for all available USB-C ports + * + * @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_tcpc_chip_info(const struct shell *sh, size_t argc, char **argv) +{ + struct tcpc_chip_info chip_info; + int ret = 0; + + if (argc <= 1) { + DT_FOREACH_STATUS_OKAY(usb_c_connector, TCPC_GET_CHIP_CONN_NODE); + } else { + const struct device *dev = device_get_binding(argv[1]); + + if (dev != NULL) { + TCPC_GET_CHIP_DEV(dev); + } else { + ret = -ENODEV; + } + } + + 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_tcpc_cmds, + SHELL_CMD_ARG(dump, &list_device_names, + "Dump TCPC registers\n" + "Usage: tcpc dump []", + cmd_tcpc_dump, 1, 1), + SHELL_CMD_ARG(vbus, &list_device_names, + "Display VBUS voltage\n" + "Usage: tcpc vbus []", + cmd_tcpc_vbus, 1, 1), + SHELL_CMD_ARG(chip, &list_device_names, + "Display chip information\n" + "Usage: tcpc chip []", + cmd_tcpc_chip_info, 1, 1), + SHELL_SUBCMD_SET_END); + +SHELL_CMD_REGISTER(tcpc, &sub_tcpc_cmds, "TCPC (USB-C PD) diagnostics", NULL); diff --git a/drivers/usb_c/tcpc/ucpd_stm32.c b/drivers/usb_c/tcpc/ucpd_stm32.c index 7082342dd1e6cb1..2fca84346fc5a85 100644 --- a/drivers/usb_c/tcpc/ucpd_stm32.c +++ b/drivers/usb_c/tcpc/ucpd_stm32.c @@ -1024,45 +1024,25 @@ static int ucpd_transmit_data(const struct device *dev, return 0; } -/** - * @brief Tests if a received Power Delivery message is pending - * - * @retval true if message is pending, else false - */ -static bool ucpd_is_rx_pending_msg(const struct device *dev, - enum pd_packet_type *type) -{ - struct tcpc_data *data = dev->data; - bool ret; - - ret = (*(uint32_t *)data->ucpd_rx_buffer > 0); - - if (ret & (type != NULL)) { - *type = *(uint16_t *)data->ucpd_rx_buffer; - } - - return ret; -} - /** * @brief Retrieves the Power Delivery message from the TCPC * - * @retval number of bytes received - * @retval -EIO on no message to retrieve - * @retval -EFAULT on buf being NULL + * @retval number of bytes received if msg parameter is provided + * @retval 0 if there is a message pending and the msg parameter is NULL + * @retval -ENODATA if there is no pending message */ -static int ucpd_receive_data(const struct device *dev, struct pd_msg *msg) +static int ucpd_get_rx_pending_msg(const struct device *dev, struct pd_msg *msg) { struct tcpc_data *data = dev->data; int ret = 0; - if (msg == NULL) { - return -EFAULT; + /* Make sure we have a message to retrieve */ + if (*(uint32_t *)data->ucpd_rx_buffer == 0) { + return -ENODATA; } - /* Make sure we have a message to retrieve */ - if (!ucpd_is_rx_pending_msg(dev, NULL)) { - return -EIO; + if (msg == NULL) { + return 0; } msg->type = *(uint16_t *)data->ucpd_rx_buffer; @@ -1386,7 +1366,7 @@ static int ucpd_init(const struct device *dev) LOG_DBG("Pinctrl signals configuration"); ret = pinctrl_apply_state(config->ucpd_pcfg, PINCTRL_STATE_DEFAULT); - if (ret < 0) { + if (ret != 0) { LOG_ERR("USB pinctrl setup failed (%d)", ret); return ret; } @@ -1443,8 +1423,7 @@ static const struct tcpc_driver_api driver_api = { .set_alert_handler_cb = ucpd_set_alert_handler_cb, .get_cc = ucpd_get_cc, .set_rx_enable = ucpd_set_rx_enable, - .is_rx_pending_msg = ucpd_is_rx_pending_msg, - .receive_data = ucpd_receive_data, + .get_rx_pending_msg = ucpd_get_rx_pending_msg, .transmit_data = ucpd_transmit_data, .select_rp_value = ucpd_select_rp_value, .get_rp_value = ucpd_get_rp_value, diff --git a/drivers/usb_c/vbus/usbc_vbus_adc.c b/drivers/usb_c/vbus/usbc_vbus_adc.c index a1fbe6f3421c056..1b2d576a3ed96a4 100644 --- a/drivers/usb_c/vbus/usbc_vbus_adc.c +++ b/drivers/usb_c/vbus/usbc_vbus_adc.c @@ -146,13 +146,12 @@ static int adc_vbus_init(const struct device *dev) /* Configure VBUS Measurement enable pin if defined */ if (gcp->port) { - ret = device_is_ready(gcp->port); - if (ret < 0) { + if (!device_is_ready(gcp->port)) { LOG_ERR("%s: device not ready", gcp->port->name); - return ret; + return -EIO; } ret = gpio_pin_configure_dt(gcp, GPIO_OUTPUT_INACTIVE); - if (ret < 0) { + if (ret != 0) { LOG_ERR("Failed to control feed %s.%u: %d", gcp->port->name, gcp->pin, ret); return ret; @@ -161,13 +160,12 @@ static int adc_vbus_init(const struct device *dev) /* Configure VBUS Discharge pin if defined */ if (gcd->port) { - ret = device_is_ready(gcd->port); - if (ret == false) { + if (!device_is_ready(gcd->port)) { LOG_ERR("%s: device not ready", gcd->port->name); - return ret; + return -EIO; } ret = gpio_pin_configure_dt(gcd, GPIO_OUTPUT_INACTIVE); - if (ret < 0) { + if (ret != 0) { LOG_ERR("Failed to control feed %s.%u: %d", gcd->port->name, gcd->pin, ret); return ret; @@ -179,13 +177,13 @@ static int adc_vbus_init(const struct device *dev) data->sequence.buffer_size = sizeof(data->sample); ret = adc_channel_setup_dt(&config->adc_channel); - if (ret < 0) { + if (ret != 0) { LOG_INF("Could not setup channel (%d)\n", ret); return ret; } ret = adc_sequence_init_dt(&config->adc_channel, &data->sequence); - if (ret < 0) { + if (ret != 0) { LOG_INF("Could not init sequence (%d)\n", ret); return ret; } diff --git a/drivers/virtualization/Kconfig b/drivers/virtualization/Kconfig index 4f32552f09aeef4..f439f5ba97d07e9 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 6e8258f1dadc82c..f620ab473f9e066 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 e64394087872207..8a7ae11c3646e84 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/virtualization/virt_ivshmem_handlers.c b/drivers/virtualization/virt_ivshmem_handlers.c index bd49b8949eb6f85..821ab16f3040749 100644 --- a/drivers/virtualization/virt_ivshmem_handlers.c +++ b/drivers/virtualization/virt_ivshmem_handlers.c @@ -5,14 +5,14 @@ */ #include -#include +#include #include static inline size_t z_vrfy_ivshmem_get_mem(const struct device *dev, uintptr_t *memmap) { - Z_OOPS(Z_SYSCALL_DRIVER_IVSHMEM(dev, get_mem)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(memmap, sizeof(uintptr_t))); + K_OOPS(K_SYSCALL_DRIVER_IVSHMEM(dev, get_mem)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(memmap, sizeof(uintptr_t))); return z_impl_ivshmem_get_mem(dev, memmap); } @@ -20,7 +20,7 @@ static inline size_t z_vrfy_ivshmem_get_mem(const struct device *dev, static inline uint32_t z_vrfy_ivshmem_get_id(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_IVSHMEM(dev, get_id)); + K_OOPS(K_SYSCALL_DRIVER_IVSHMEM(dev, get_id)); return z_impl_ivshmem_get_id(dev); } @@ -28,7 +28,7 @@ static inline uint32_t z_vrfy_ivshmem_get_id(const struct device *dev) static inline uint16_t z_vrfy_ivshmem_get_vectors(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_IVSHMEM(dev, get_vectors)); + K_OOPS(K_SYSCALL_DRIVER_IVSHMEM(dev, get_vectors)); return z_impl_ivshmem_get_vectors(dev); } @@ -37,7 +37,7 @@ static inline uint16_t z_vrfy_ivshmem_get_vectors(const struct device *dev) static inline int z_vrfy_ivshmem_int_peer(const struct device *dev, uint32_t peer_id, uint16_t vector) { - Z_OOPS(Z_SYSCALL_DRIVER_IVSHMEM(dev, int_peer)); + K_OOPS(K_SYSCALL_DRIVER_IVSHMEM(dev, int_peer)); return z_impl_ivshmem_int_peer(dev, peer_id, vector); } @@ -47,8 +47,8 @@ static inline int z_vrfy_ivshmem_register_handler(const struct device *dev, struct k_poll_signal *signal, uint16_t vector) { - Z_OOPS(Z_SYSCALL_DRIVER_IVSHMEM(dev, register_handler)); - Z_OOPS(Z_SYSCALL_OBJ(signal, K_OBJ_POLL_SIGNAL)); + K_OOPS(K_SYSCALL_DRIVER_IVSHMEM(dev, register_handler)); + K_OOPS(K_SYSCALL_OBJ(signal, K_OBJ_POLL_SIGNAL)); return z_impl_ivshmem_register_handler(dev, signal, vector); } @@ -59,8 +59,8 @@ static inline int z_vrfy_ivshmem_register_handler(const struct device *dev, static inline size_t z_vrfy_ivshmem_get_rw_mem_section(const struct device *dev, uintptr_t *memmap) { - Z_OOPS(Z_SYSCALL_DRIVER_IVSHMEM(dev, get_rw_mem_section)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(memmap, sizeof(uintptr_t))); + K_OOPS(K_SYSCALL_DRIVER_IVSHMEM(dev, get_rw_mem_section)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(memmap, sizeof(uintptr_t))); return z_impl_ivshmem_get_rw_mem_section(dev, memmap); } @@ -70,8 +70,8 @@ static inline size_t z_vrfy_ivshmem_get_output_mem_section(const struct device * uint32_t peer_id, uintptr_t *memmap) { - Z_OOPS(Z_SYSCALL_DRIVER_IVSHMEM(dev, get_output_mem_section)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(memmap, sizeof(uintptr_t))); + K_OOPS(K_SYSCALL_DRIVER_IVSHMEM(dev, get_output_mem_section)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(memmap, sizeof(uintptr_t))); return z_impl_ivshmem_get_output_mem_section(dev, peer_id, memmap); } @@ -80,7 +80,7 @@ static inline size_t z_vrfy_ivshmem_get_output_mem_section(const struct device * static inline uint32_t z_vrfy_ivshmem_get_state(const struct device *dev, uint32_t peer_id) { - Z_OOPS(Z_SYSCALL_DRIVER_IVSHMEM(dev, get_state)); + K_OOPS(K_SYSCALL_DRIVER_IVSHMEM(dev, get_state)); return z_impl_ivshmem_get_state(dev, peer_id); } @@ -89,7 +89,7 @@ static inline uint32_t z_vrfy_ivshmem_get_state(const struct device *dev, static inline int z_vrfy_ivshmem_set_state(const struct device *dev, uint32_t state) { - Z_OOPS(Z_SYSCALL_DRIVER_IVSHMEM(dev, set_state)); + K_OOPS(K_SYSCALL_DRIVER_IVSHMEM(dev, set_state)); return z_impl_ivshmem_set_state(dev, state); } @@ -97,7 +97,7 @@ static inline int z_vrfy_ivshmem_set_state(const struct device *dev, static inline uint32_t z_vrfy_ivshmem_get_max_peers(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_IVSHMEM(dev, get_max_peers)); + K_OOPS(K_SYSCALL_DRIVER_IVSHMEM(dev, get_max_peers)); return z_impl_ivshmem_get_max_peers(dev); } @@ -105,7 +105,7 @@ static inline uint32_t z_vrfy_ivshmem_get_max_peers(const struct device *dev) static inline uint16_t z_vrfy_ivshmem_get_protocol(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_IVSHMEM(dev, get_protocol)); + K_OOPS(K_SYSCALL_DRIVER_IVSHMEM(dev, get_protocol)); return z_impl_ivshmem_get_protocol(dev); } @@ -114,7 +114,7 @@ static inline uint16_t z_vrfy_ivshmem_get_protocol(const struct device *dev) static inline int z_vrfy_ivshmem_enable_interrupts(const struct device *dev, bool enable) { - Z_OOPS(Z_SYSCALL_DRIVER_IVSHMEM(dev, enable_interrupts)); + K_OOPS(K_SYSCALL_DRIVER_IVSHMEM(dev, enable_interrupts)); return z_impl_ivshmem_enable_interrupts(dev, enable); } diff --git a/drivers/virtualization/virt_ivshmem_shell.c b/drivers/virtualization/virt_ivshmem_shell.c index ebf925785979b21..6c9dc9631a5e0b7 100644 --- a/drivers/virtualization/virt_ivshmem_shell.c +++ b/drivers/virtualization/virt_ivshmem_shell.c @@ -23,8 +23,13 @@ K_THREAD_STACK_DEFINE(doorbell_stack, STACK_SIZE); static bool doorbell_started; static struct k_thread doorbell_thread; -static void doorbell_notification_thread(const struct shell *sh) +static void doorbell_notification_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct shell *sh = p1; + while (1) { unsigned int signaled; int vector; @@ -174,7 +179,7 @@ static int cmd_ivshmem_get_notified(const struct shell *sh, tid = k_thread_create( &doorbell_thread, doorbell_stack, STACK_SIZE, - (k_thread_entry_t)doorbell_notification_thread, + doorbell_notification_thread, (void *)sh, NULL, NULL, K_PRIO_COOP(2), 0, K_NO_WAIT); if (!tid) { diff --git a/drivers/w1/CMakeLists.txt b/drivers/w1/CMakeLists.txt index 57d010f4e4d5d05..58fa21ab84a66ef 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 2fabe874b6d0446..d33503c26842cc2 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig @@ -26,7 +26,6 @@ config W1_INIT_PRIORITY config W1_SHELL bool "1-Wire Shell" depends on SHELL - default y if !SHELL_MINIMAL help Enable 1-Wire Shell for testing. @@ -45,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 000000000000000..57bccfabd91d61a --- /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/Kconfig.zephyr_serial b/drivers/w1/Kconfig.zephyr_serial index 9555fb43a92750f..10eb274ee1e1451 100644 --- a/drivers/w1/Kconfig.zephyr_serial +++ b/drivers/w1/Kconfig.zephyr_serial @@ -8,6 +8,7 @@ config W1_ZEPHYR_SERIAL select SERIAL default y depends on DT_HAS_ZEPHYR_W1_SERIAL_ENABLED + select UART_USE_RUNTIME_CONFIGURE help This option enables the Zephyr serial 1-Wire master driver. diff --git a/drivers/w1/w1_handlers.c b/drivers/w1/w1_handlers.c index 5eac465c38389ca..f2299705a269bab 100644 --- a/drivers/w1/w1_handlers.c +++ b/drivers/w1/w1_handlers.c @@ -4,12 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include static inline int z_vrfy_w1_reset_bus(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_W1(dev, reset_bus)); + K_OOPS(K_SYSCALL_DRIVER_W1(dev, reset_bus)); return z_impl_w1_reset_bus((const struct device *)dev); } @@ -17,7 +17,7 @@ static inline int z_vrfy_w1_reset_bus(const struct device *dev) static inline int z_vrfy_w1_read_bit(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_W1(dev, read_bit)); + K_OOPS(K_SYSCALL_DRIVER_W1(dev, read_bit)); return z_impl_w1_read_bit((const struct device *)dev); } @@ -25,7 +25,7 @@ static inline int z_vrfy_w1_read_bit(const struct device *dev) static inline int z_vrfy_w1_write_bit(const struct device *dev, bool bit) { - Z_OOPS(Z_SYSCALL_DRIVER_W1(dev, write_bit)); + K_OOPS(K_SYSCALL_DRIVER_W1(dev, write_bit)); return z_impl_w1_write_bit((const struct device *)dev, bit); } @@ -33,7 +33,7 @@ static inline int z_vrfy_w1_write_bit(const struct device *dev, bool bit) static inline int z_vrfy_w1_read_byte(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_W1(dev, read_byte)); + K_OOPS(K_SYSCALL_DRIVER_W1(dev, read_byte)); return z_impl_w1_read_byte((const struct device *)dev); } @@ -41,7 +41,7 @@ static inline int z_vrfy_w1_read_byte(const struct device *dev) static inline int z_vrfy_w1_write_byte(const struct device *dev, uint8_t byte) { - Z_OOPS(Z_SYSCALL_DRIVER_W1(dev, write_byte)); + K_OOPS(K_SYSCALL_DRIVER_W1(dev, write_byte)); return z_impl_w1_write_byte((const struct device *)dev, (uint8_t)byte); } @@ -50,8 +50,8 @@ static inline int z_vrfy_w1_write_byte(const struct device *dev, uint8_t byte) static inline int z_vrfy_w1_read_block(const struct device *dev, uint8_t *buffer, size_t len) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_W1)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(buffer, len)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_W1)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(buffer, len)); return z_impl_w1_read_block((const struct device *)dev, (uint8_t *)buffer, (size_t)len); @@ -61,8 +61,8 @@ static inline int z_vrfy_w1_read_block(const struct device *dev, static inline int z_vrfy_w1_write_block(const struct device *dev, const uint8_t *buffer, size_t len) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_W1)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(buffer, len)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_W1)); + K_OOPS(K_SYSCALL_MEMORY_READ(buffer, len)); return z_impl_w1_write_block((const struct device *)dev, (const uint8_t *)buffer, (size_t)len); @@ -71,7 +71,7 @@ static inline int z_vrfy_w1_write_block(const struct device *dev, static inline int z_vrfy_w1_change_bus_lock(const struct device *dev, bool lock) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_W1)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_W1)); return z_impl_w1_change_bus_lock((const struct device *)dev, lock); } @@ -80,7 +80,7 @@ static inline int z_vrfy_w1_change_bus_lock(const struct device *dev, bool lock) static inline int z_vrfy_w1_configure(const struct device *dev, enum w1_settings_type type, uint32_t value) { - Z_OOPS(Z_SYSCALL_DRIVER_W1(dev, configure)); + K_OOPS(K_SYSCALL_DRIVER_W1(dev, configure)); return z_impl_w1_configure(dev, type, value); } @@ -88,7 +88,7 @@ static inline int z_vrfy_w1_configure(const struct device *dev, static inline size_t z_vrfy_w1_get_slave_count(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_W1)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_W1)); return z_impl_w1_get_slave_count((const struct device *)dev); } @@ -100,9 +100,9 @@ static inline int z_vrfy_w1_search_bus(const struct device *dev, w1_search_callback_t callback, void *user_data) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_W1)); + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_W1)); - Z_OOPS(Z_SYSCALL_VERIFY_MSG(callback == 0, + K_OOPS(K_SYSCALL_VERIFY_MSG(callback == 0, "callbacks may not be set from user mode")); /* user_data is not dereferenced, no need to check parameter */ diff --git a/drivers/w1/w1_zephyr_gpio.c b/drivers/w1/w1_zephyr_gpio.c new file mode 100644 index 000000000000000..090df881122b5f4 --- /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/CMakeLists.txt b/drivers/watchdog/CMakeLists.txt index e72f3683c0610f9..7f58a5461a930a7 100644 --- a/drivers/watchdog/CMakeLists.txt +++ b/drivers/watchdog/CMakeLists.txt @@ -39,6 +39,7 @@ zephyr_library_sources_ifdef(CONFIG_WDT_XILINX_AXI wdt_xilinx_axi.c) zephyr_library_sources_ifdef(CONFIG_WDT_INFINEON_CAT1 wdt_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_WDT_OPENTITAN wdt_opentitan.c) zephyr_library_sources_ifdef(CONFIG_WDT_AMBIQ wdt_ambiq.c) +zephyr_library_sources_ifdef(CONFIG_WDT_XMC4XXX wdt_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_WDT_DW wdt_dw.c wdt_dw_common.c) zephyr_library_sources_ifdef(CONFIG_WDT_INTEL_ADSP wdt_intel_adsp.c wdt_dw_common.c) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 2049d78faa05037..2ee5545f39e02c8 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -120,4 +120,6 @@ source "drivers/watchdog/Kconfig.ambiq" source "drivers/watchdog/Kconfig.shell" +source "drivers/watchdog/Kconfig.xmc4xxx" + endif # WATCHDOG diff --git a/drivers/watchdog/Kconfig.npm1300 b/drivers/watchdog/Kconfig.npm1300 index 8e9cd65024d116f..b18e4b69b13a0fa 100644 --- a/drivers/watchdog/Kconfig.npm1300 +++ b/drivers/watchdog/Kconfig.npm1300 @@ -13,7 +13,7 @@ config WDT_NPM1300 config WDT_NPM1300_INIT_PRIORITY int "nPM1300 Watchdog driver initialization priority" depends on WDT_NPM1300 - default 75 + default 85 help Initialization priority for the nPM1300 Watchdog driver. It must be greater than GPIO_NPM1300_INIT_PRIORITY. diff --git a/drivers/watchdog/Kconfig.npm6001 b/drivers/watchdog/Kconfig.npm6001 index 3230deffc26a088..0d3f864e5cf0a8e 100644 --- a/drivers/watchdog/Kconfig.npm6001 +++ b/drivers/watchdog/Kconfig.npm6001 @@ -13,6 +13,6 @@ config WDT_NPM6001 config WDT_NPM6001_INIT_PRIORITY int "nPM6001 Watchdog driver initialization priority" depends on WDT_NPM6001 - default 65 + default 85 help Initialization priority for the nPM6001 Watchdog driver. diff --git a/drivers/watchdog/Kconfig.nrfx b/drivers/watchdog/Kconfig.nrfx index 52cf45dc068746d..2967fe8648901e1 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/Kconfig.shell b/drivers/watchdog/Kconfig.shell index 5f5a97a6bda1310..11503277e935ce8 100644 --- a/drivers/watchdog/Kconfig.shell +++ b/drivers/watchdog/Kconfig.shell @@ -3,7 +3,6 @@ config WDT_SHELL bool "Watchdog (WDT) shell" - default y depends on SHELL help Enable WDT shell. diff --git a/drivers/watchdog/Kconfig.xmc4xxx b/drivers/watchdog/Kconfig.xmc4xxx new file mode 100644 index 000000000000000..8c18d06da0d24cb --- /dev/null +++ b/drivers/watchdog/Kconfig.xmc4xxx @@ -0,0 +1,22 @@ +# Infineon XMC4xxx WDT configuration + +# Copyright (C) 2023 SLB +# SPDX-License-Identifier: Apache-2.0 + +config WDT_XMC4XXX + bool "Infineon XMC4xxx MCU Family Watchdog (WDT) Driver" + default y + depends on DT_HAS_INFINEON_XMC4XXX_WATCHDOG_ENABLED + help + Enable WDT driver for Infineon XMC4xxx MCUs. + +if WDT_XMC4XXX && !WDT_DISABLE_AT_BOOT + +config WDT_XMC4XXX_DEFAULT_TIMEOUT_MAX_MS + int "Default watchdog timeout to use at startup" + default 20000 + help + Default watchdog timeout to use if the watchdog is not disabled + at startup. + +endif diff --git a/drivers/watchdog/wdt_andes_atcwdt200.c b/drivers/watchdog/wdt_andes_atcwdt200.c index 62a9677b96d2750..5fca002680502cf 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 f41b3b1b2cd5933..657001b1b5c36dd 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 7c7a1532d1517ab..3f8bce57ce62f17 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_handlers.c b/drivers/watchdog/wdt_handlers.c index 2af078514437de8..2ac872f1379d7d0 100644 --- a/drivers/watchdog/wdt_handlers.c +++ b/drivers/watchdog/wdt_handlers.c @@ -5,11 +5,11 @@ */ #include -#include +#include static inline int z_vrfy_wdt_setup(const struct device *dev, uint8_t options) { - Z_OOPS(Z_SYSCALL_DRIVER_WDT(dev, setup)); + K_OOPS(K_SYSCALL_DRIVER_WDT(dev, setup)); return z_impl_wdt_setup(dev, options); } @@ -17,7 +17,7 @@ static inline int z_vrfy_wdt_setup(const struct device *dev, uint8_t options) static inline int z_vrfy_wdt_disable(const struct device *dev) { - Z_OOPS(Z_SYSCALL_DRIVER_WDT(dev, disable)); + K_OOPS(K_SYSCALL_DRIVER_WDT(dev, disable)); return z_impl_wdt_disable(dev); } @@ -25,7 +25,7 @@ static inline int z_vrfy_wdt_disable(const struct device *dev) static inline int z_vrfy_wdt_feed(const struct device *dev, int channel_id) { - Z_OOPS(Z_SYSCALL_DRIVER_WDT(dev, feed)); + K_OOPS(K_SYSCALL_DRIVER_WDT(dev, feed)); return z_impl_wdt_feed(dev, channel_id); } diff --git a/drivers/watchdog/wdt_intel_adsp.c b/drivers/watchdog/wdt_intel_adsp.c index c0e2c0a7d364a23..9a30ea4f45bdfd6 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 8d61f11d6fbe5ad..8967d1e162be561 100644 --- a/drivers/watchdog/wdt_nrfx.c +++ b/drivers/watchdog/wdt_nrfx.c @@ -20,37 +20,36 @@ struct wdt_nrfx_data { }; struct wdt_nrfx_config { - nrfx_wdt_t wdt; - nrfx_wdt_config_t config; + nrfx_wdt_t wdt; }; static int wdt_nrf_setup(const struct device *dev, uint8_t options) { const struct wdt_nrfx_config *config = dev->config; - struct wdt_nrfx_data *data = dev->data; - uint32_t behaviour; + const struct wdt_nrfx_data *data = dev->data; + nrfx_err_t err_code; + + nrfx_wdt_config_t wdt_config = { + .reload_value = data->m_timeout + }; - /* Activate all available options. Run in all cases. */ - behaviour = NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK | NRF_WDT_BEHAVIOUR_RUN_HALT_MASK; +#if NRF_WDT_HAS_STOP + wdt_config.behaviour |= NRF_WDT_BEHAVIOUR_STOP_ENABLE_MASK; +#endif - /* Deactivate running in sleep mode. */ - if (options & WDT_OPT_PAUSE_IN_SLEEP) { - behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK; + if (!(options & WDT_OPT_PAUSE_IN_SLEEP)) { + wdt_config.behaviour |= NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK; } - /* Deactivate running when debugger is attached. */ - if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) { - behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_HALT_MASK; + if (!(options & WDT_OPT_PAUSE_HALTED_BY_DBG)) { + wdt_config.behaviour |= NRF_WDT_BEHAVIOUR_RUN_HALT_MASK; } - nrf_wdt_behaviour_set(config->wdt.p_reg, behaviour); - /* The watchdog timer is driven by the LFCLK clock running at 32768 Hz. - * The timeout value given in milliseconds needs to be converted here - * to watchdog ticks.*/ - nrf_wdt_reload_value_set( - config->wdt.p_reg, - (uint32_t)(((uint64_t)data->m_timeout * 32768U) - / 1000)); + err_code = nrfx_wdt_reconfigure(&config->wdt, &wdt_config); + + if (err_code != NRFX_SUCCESS) { + return -EBUSY; + } nrfx_wdt_enable(&config->wdt); @@ -59,9 +58,21 @@ static int wdt_nrf_setup(const struct device *dev, uint8_t options) static int wdt_nrf_disable(const struct device *dev) { - /* Started watchdog cannot be stopped on nRF devices. */ +#if NRFX_WDT_HAS_STOP + const struct wdt_nrfx_config *config = dev->config; + nrfx_err_t err_code; + + err_code = nrfx_wdt_stop(&config->wdt); + + if (err_code != NRFX_SUCCESS) { + return -ENOTSUP; + } + + return 0; +#else ARG_UNUSED(dev); return -EPERM; +#endif } static int wdt_nrf_install_timeout(const struct device *dev, @@ -134,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) { @@ -151,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) \ { \ @@ -162,8 +180,9 @@ static void wdt_event_handler(const struct device *dev, uint32_t requests) IRQ_CONNECT(DT_IRQN(WDT(idx)), DT_IRQ(WDT(idx), priority), \ nrfx_isr, nrfx_wdt_##idx##_irq_handler, 0); \ err_code = nrfx_wdt_init(&config->wdt, \ - &config->config, \ - wdt_##idx##_event_handler); \ + NULL, \ + wdt_##idx##_event_handler, \ + NULL); \ if (err_code != NRFX_SUCCESS) { \ return -EBUSY; \ } \ @@ -175,11 +194,6 @@ static void wdt_event_handler(const struct device *dev, uint32_t requests) }; \ static const struct wdt_nrfx_config wdt_##idx##z_config = { \ .wdt = NRFX_WDT_INSTANCE(idx), \ - .config = { \ - .behaviour = NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK | \ - NRF_WDT_BEHAVIOUR_RUN_HALT_MASK, \ - .reload_value = 2000, \ - } \ }; \ DEVICE_DT_DEFINE(WDT(idx), \ wdt_##idx##_init, \ @@ -196,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_nxp_fs26.c b/drivers/watchdog/wdt_nxp_fs26.c index 07cddc1bd3b371a..f6aed5079e4ecf6 100644 --- a/drivers/watchdog/wdt_nxp_fs26.c +++ b/drivers/watchdog/wdt_nxp_fs26.c @@ -27,9 +27,9 @@ LOG_MODULE_REGISTER(wdt_nxp_fs26); #define FS26_INIT_FS_TIMEOUT_MS 1000U /* Helper macros to set register values from Kconfig options */ -#define WD_ERR_LIMIT(x) CONCAT(WD_ERR_LIMIT_, x) -#define WD_RFR_LIMIT(x) CONCAT(WD_RFR_LIMIT_, x) -#define WDW_PERIOD(x) CONCAT(CONCAT(WDW_PERIOD_, x), MS) +#define WD_ERR_LIMIT(x) _CONCAT(WD_ERR_LIMIT_, x) +#define WD_RFR_LIMIT(x) _CONCAT(WD_RFR_LIMIT_, x) +#define WDW_PERIOD(x) _CONCAT(_CONCAT(WDW_PERIOD_, x), MS) #define BAD_WD_REFRESH_ERROR_STRING(x) \ ((((x) & BAD_WD_DATA) ? "error in the data" : \ @@ -580,8 +580,12 @@ static int wdt_nxp_fs26_disable(const struct device *dev) return 0; } -static void wdt_nxp_fs26_int_thread(const struct device *dev) +static void wdt_nxp_fs26_int_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; const struct wdt_nxp_fs26_config *config = dev->config; struct wdt_nxp_fs26_data *data = dev->data; struct fs26_spi_rx_frame rx_frame; @@ -661,7 +665,7 @@ static int wdt_nxp_fs26_init(const struct device *dev) k_thread_create(&data->int_thread, data->int_thread_stack, CONFIG_WDT_NXP_FS26_INT_THREAD_STACK_SIZE, - (k_thread_entry_t)wdt_nxp_fs26_int_thread, + wdt_nxp_fs26_int_thread, (void *)dev, NULL, NULL, K_PRIO_COOP(CONFIG_WDT_NXP_FS26_INT_THREAD_PRIO), 0, K_NO_WAIT); @@ -822,7 +826,7 @@ static const struct wdt_driver_api wdt_nxp_fs26_api = { static const struct wdt_nxp_fs26_config wdt_nxp_fs26_config_##n = { \ .spi = SPI_DT_SPEC_INST_GET(n, \ SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(32), 0), \ - .wd_type = CONCAT(FS26_WD_, DT_INST_STRING_UPPER_TOKEN(n, type)), \ + .wd_type = _CONCAT(FS26_WD_, DT_INST_STRING_UPPER_TOKEN(n, type)), \ .int_gpio = GPIO_DT_SPEC_INST_GET(n, int_gpios), \ }; \ \ diff --git a/drivers/watchdog/wdt_nxp_s32.c b/drivers/watchdog/wdt_nxp_s32.c index 2d380264b941387..709cf9aaffbdf2b 100644 --- a/drivers/watchdog/wdt_nxp_s32.c +++ b/drivers/watchdog/wdt_nxp_s32.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_swt + #include #include #include @@ -129,6 +131,13 @@ static int swt_nxp_s32_feed(const struct device *dev, int channel_id) return 0; } +void swt_nxp_s32_isr(const struct device *dev) +{ + const struct swt_nxp_s32_config *config = dev->config; + + Swt_Ip_IrqHandler(config->instance); +} + static const struct wdt_driver_api swt_nxp_s32_driver_api = { .setup = swt_nxp_s32_setup, .disable = swt_nxp_s32_disable, @@ -136,17 +145,10 @@ static const struct wdt_driver_api swt_nxp_s32_driver_api = { .feed = swt_nxp_s32_feed, }; -#define SWT_NODE(n) DT_NODELABEL(swt##n) -#define RTU0_SWT_OFFSET_IDX 2 -#define RTU1_SWT_OFFSET_IDX 7 -#define RTU_SWT(n) \ - COND_CODE_1(CONFIG_NXP_S32_RTU_INDEX, (RTU1_SWT_OFFSET_IDX + n), \ - (RTU0_SWT_OFFSET_IDX + n)) - #define SWT_NXP_S32_CALLBACK(n) \ void swt_nxp_s32_##n##_callback(void) \ { \ - const struct device *dev = DEVICE_DT_GET(SWT_NODE(n)); \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ struct swt_nxp_s32_data *data = dev->data; \ \ if (data->callback) { \ @@ -154,6 +156,12 @@ static const struct wdt_driver_api swt_nxp_s32_driver_api = { } \ } +#define SWT_NXP_S32_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_SWT_##i##_BASE) ? i : 0) + +#define SWT_NXP_S32_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET SWT_INSTANCE_COUNT, SWT_NXP_S32_HW_INSTANCE_CHECK, (|), n) + #define SWT_NXP_S32_DEVICE_INIT(n) \ SWT_NXP_S32_CALLBACK(n) \ static struct swt_nxp_s32_data swt_nxp_s32_data_##n = { \ @@ -171,10 +179,10 @@ static const struct wdt_driver_api swt_nxp_s32_driver_api = { }, \ }; \ static const struct swt_nxp_s32_config swt_nxp_s32_config_##n = { \ - .instance = (uint8_t)(RTU_SWT(n)), \ - .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(SWT_NODE(n))), \ + .instance = SWT_NXP_S32_HW_INSTANCE(n), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .clock_subsys = (clock_control_subsys_t) \ - DT_CLOCKS_CELL(SWT_NODE(n), name), \ + DT_INST_CLOCKS_CELL(n, name), \ }; \ \ static int swt_nxp_s32_##n##_init(const struct device *dev) \ @@ -191,17 +199,15 @@ static const struct wdt_driver_api swt_nxp_s32_driver_api = { return err; \ } \ \ - IRQ_CONNECT(DT_IRQN(SWT_NODE(n)), \ - DT_IRQ(SWT_NODE(n), priority), \ - Swt_Ip_IrqHandler, \ - (uint8_t)(RTU_SWT(n)), \ - DT_IRQ(SWT_NODE(n), flags)); \ - irq_enable(DT_IRQN(SWT_NODE(n))); \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ + swt_nxp_s32_isr, DEVICE_DT_INST_GET(n), \ + DT_INST_IRQ(n, flags)); \ + irq_enable(DT_INST_IRQN(n)); \ \ return 0; \ } \ \ - DEVICE_DT_DEFINE(SWT_NODE(n), \ + DEVICE_DT_INST_DEFINE(n, \ swt_nxp_s32_##n##_init, \ NULL, \ &swt_nxp_s32_data_##n, \ @@ -210,23 +216,4 @@ static const struct wdt_driver_api swt_nxp_s32_driver_api = { CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ &swt_nxp_s32_driver_api); - -#if DT_NODE_HAS_STATUS(SWT_NODE(0), okay) -SWT_NXP_S32_DEVICE_INIT(0) -#endif - -#if DT_NODE_HAS_STATUS(SWT_NODE(1), okay) -SWT_NXP_S32_DEVICE_INIT(1) -#endif - -#if DT_NODE_HAS_STATUS(SWT_NODE(2), okay) -SWT_NXP_S32_DEVICE_INIT(2) -#endif - -#if DT_NODE_HAS_STATUS(SWT_NODE(3), okay) -SWT_NXP_S32_DEVICE_INIT(3) -#endif - -#if DT_NODE_HAS_STATUS(SWT_NODE(4), okay) -SWT_NXP_S32_DEVICE_INIT(4) -#endif +DT_INST_FOREACH_STATUS_OKAY(SWT_NXP_S32_DEVICE_INIT) diff --git a/drivers/watchdog/wdt_rpi_pico.c b/drivers/watchdog/wdt_rpi_pico.c index 83285ba659e8f30..7d3f2a5fc607843 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/watchdog/wdt_xmc4xxx.c b/drivers/watchdog/wdt_xmc4xxx.c new file mode 100644 index 000000000000000..e038bb0d4d59f94 --- /dev/null +++ b/drivers/watchdog/wdt_xmc4xxx.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2023 SLB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT infineon_xmc4xxx_watchdog + +#include +#include + +#include +#include +#include + +#include +#include + +struct wdt_xmc4xxx_dev_data { + wdt_callback_t cb; + uint8_t mode; + bool timeout_valid; + bool is_serviced; +}; + +/* When the watchdog counter rolls over, the SCU will generate a */ +/* pre-warning event which gets routed to the ISR below. If the */ +/* watchdog is not serviced, the SCU will only reset the MCU */ +/* after the second time the counter rolls over. */ +/* Hence the reset will only happen after 2*cfg->window.max have elapsed. */ +/* We could potentially manually reset the MCU, but this way the context */ +/* information (i.e. that reset happened because of a watchdog) is lost. */ + +static void wdt_xmc4xxx_isr(const struct device *dev) +{ + struct wdt_xmc4xxx_dev_data *data = dev->data; + uint32_t event = XMC_SCU_INTERUPT_GetEventStatus(); + + /* todo add interrupt controller? */ + if ((event & XMC_SCU_INTERRUPT_EVENT_WDT_WARN) == 0) { + return; + } + + /* this is a level triggered interrupt. the event must be cleared */ + XMC_SCU_INTERRUPT_ClearEventStatus(XMC_SCU_INTERRUPT_EVENT_WDT_WARN); + + data->is_serviced = false; + + if (data->cb) { + data->cb(dev, 0); + } + + /* Ensure that watchdog is serviced if RESET_NONE mode is used */ + if (data->mode == WDT_FLAG_RESET_NONE && !data->is_serviced) { + XMC_WDT_Service(); + } + + XMC_WDT_ClearAlarm(); +} + +static int wdt_xmc4xxx_disable(const struct device *dev) +{ + struct wdt_xmc4xxx_dev_data *data = dev->data; + + XMC_WDT_Stop(); + XMC_WDT_Disable(); + + data->timeout_valid = false; + + return 0; +} + +static int wdt_xmc4xxx_setup(const struct device *dev, uint8_t options) +{ + struct wdt_xmc4xxx_dev_data *data = dev->data; + + if (!data->timeout_valid) { + return -EINVAL; + } + + if ((options & WDT_OPT_PAUSE_IN_SLEEP) != 0) { + SCU_CLK->SLEEPCR &= ~XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_ENABLE_WDT; + } else { + SCU_CLK->SLEEPCR |= XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_ENABLE_WDT; + } + + if ((options & WDT_OPT_PAUSE_HALTED_BY_DBG) != 0) { + XMC_WDT_SetDebugMode(XMC_WDT_DEBUG_MODE_STOP); + } else { + XMC_WDT_SetDebugMode(XMC_WDT_DEBUG_MODE_RUN); + } + + XMC_WDT_Start(); + + return 0; +} + +static int wdt_xmc4xxx_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *cfg) +{ + XMC_WDT_CONFIG_t wdt_config = {0}; + struct wdt_xmc4xxx_dev_data *data = dev->data; + uint32_t wdt_clock; + + /* disable the watchdog if timeout was already installed */ + if (data->timeout_valid) { + wdt_xmc4xxx_disable(dev); + data->timeout_valid = false; + } + + if (cfg->window.min != 0 || cfg->window.max == 0) { + return -EINVAL; + } + + wdt_clock = XMC_SCU_CLOCK_GetWdtClockFrequency(); + + if ((uint64_t)cfg->window.max * wdt_clock / 1000 > UINT32_MAX) { + return -EINVAL; + } + + wdt_config.window_upper_bound = (uint64_t)cfg->window.max * wdt_clock / 1000; + + XMC_WDT_Init(&wdt_config); + XMC_WDT_SetDebugMode(XMC_WDT_MODE_PREWARNING); + XMC_SCU_INTERRUPT_EnableEvent(XMC_SCU_INTERRUPT_EVENT_WDT_WARN); + + if (cfg->flags == WDT_FLAG_RESET_NONE && cfg->callback == NULL) { + return -EINVAL; + } + + data->cb = cfg->callback; + data->mode = cfg->flags; + data->timeout_valid = true; + + return 0; +} + +static int wdt_xmc4xxx_feed(const struct device *dev, int channel_id) +{ + ARG_UNUSED(channel_id); + struct wdt_xmc4xxx_dev_data *data = dev->data; + + XMC_WDT_Service(); + data->is_serviced = true; + + return 0; +} + +static const struct wdt_driver_api wdt_xmc4xxx_api = { + .setup = wdt_xmc4xxx_setup, + .disable = wdt_xmc4xxx_disable, + .install_timeout = wdt_xmc4xxx_install_timeout, + .feed = wdt_xmc4xxx_feed, +}; + +static struct wdt_xmc4xxx_dev_data wdt_xmc4xxx_data; + +static void wdt_xmc4xxx_irq_config(void) +{ + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), wdt_xmc4xxx_isr, + DEVICE_DT_INST_GET(0), 0); + irq_enable(DT_INST_IRQN(0)); +} + +static int wdt_xmc4xxx_init(const struct device *dev) +{ + wdt_xmc4xxx_irq_config(); + +#ifdef CONFIG_WDT_DISABLE_AT_BOOT + return 0; +#else + int ret; + const struct wdt_timeout_cfg cfg = {.window.max = CONFIG_WDT_XMC4XXX_DEFAULT_TIMEOUT_MAX_MS, + .flags = WDT_FLAG_RESET_SOC}; + + ret = wdt_xmc4xxx_install_timeout(dev, &cfg); + if (ret < 0) { + return ret; + } + + return wdt_xmc4xxx_setup(dev, WDT_OPT_PAUSE_HALTED_BY_DBG); +#endif +} +DEVICE_DT_INST_DEFINE(0, wdt_xmc4xxx_init, NULL, &wdt_xmc4xxx_data, NULL, PRE_KERNEL_1, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &wdt_xmc4xxx_api); diff --git a/drivers/wifi/CMakeLists.txt b/drivers/wifi/CMakeLists.txt index b12ecf88a3ed917..df1e7c394653479 100644 --- a/drivers/wifi/CMakeLists.txt +++ b/drivers/wifi/CMakeLists.txt @@ -8,3 +8,4 @@ add_subdirectory_ifdef(CONFIG_WIFI_ESP32 esp32) add_subdirectory_ifdef(CONFIG_WIFI_ESWIFI eswifi) add_subdirectory_ifdef(CONFIG_WIFI_SIMPLELINK simplelink) add_subdirectory_ifdef(CONFIG_WIFI_WINC1500 winc1500) +add_subdirectory_ifdef(CONFIG_WIFI_AIROC infineon) diff --git a/drivers/wifi/Kconfig b/drivers/wifi/Kconfig index 4bb4197bedebb26..d7133f5be04011e 100644 --- a/drivers/wifi/Kconfig +++ b/drivers/wifi/Kconfig @@ -40,5 +40,6 @@ source "drivers/wifi/simplelink/Kconfig.simplelink" source "drivers/wifi/eswifi/Kconfig.eswifi" source "drivers/wifi/esp_at/Kconfig.esp_at" source "drivers/wifi/esp32/Kconfig.esp32" +source "drivers/wifi/infineon/Kconfig.airoc" endif # WIFI diff --git a/drivers/wifi/esp32/src/esp_wifi_drv.c b/drivers/wifi/esp32/src/esp_wifi_drv.c index cb3431598543a16..2e86ef39552519e 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" @@ -61,7 +60,7 @@ struct esp32_wifi_runtime { uint8_t state; }; -static void esp_wifi_event_task(void); +static void esp_wifi_event_task(void *, void *, void *); K_MSGQ_DEFINE(esp_wifi_msgq, sizeof(system_event_t), 10, 4); K_THREAD_STACK_DEFINE(esp_wifi_event_stack, CONFIG_ESP32_WIFI_EVENT_TASK_STACK_SIZE); @@ -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 { @@ -262,8 +280,11 @@ static void esp_wifi_handle_disconnect_event(void) } } -static void esp_wifi_event_task(void) +static void esp_wifi_event_task(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + system_event_t evt; uint8_t s_con_cnt = 0; @@ -283,7 +304,7 @@ static void esp_wifi_event_task(void) 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(); @@ -615,7 +636,7 @@ static int esp32_wifi_dev_init(const struct device *dev) k_tid_t tid = k_thread_create(&esp_wifi_event_thread, esp_wifi_event_stack, CONFIG_ESP32_WIFI_EVENT_TASK_STACK_SIZE, - (k_thread_entry_t)esp_wifi_event_task, NULL, NULL, NULL, + esp_wifi_event_task, NULL, NULL, NULL, CONFIG_ESP32_WIFI_EVENT_TASK_PRIO, K_INHERIT_PERMS, K_NO_WAIT); @@ -652,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/Kconfig.esp_at b/drivers/wifi/esp_at/Kconfig.esp_at index afe02931ee6ae85..9b7e38045d95f18 100644 --- a/drivers/wifi/esp_at/Kconfig.esp_at +++ b/drivers/wifi/esp_at/Kconfig.esp_at @@ -11,6 +11,7 @@ menuconfig WIFI_ESP_AT select MODEM_IFACE_UART select NET_L2_WIFI_MGMT select WIFI_OFFLOAD + imply UART_USE_RUNTIME_CONFIGURE help Enable Espressif AT Command offloaded WiFi driver. It is supported on any serial capable platform and communicates with Espressif chips diff --git a/drivers/wifi/esp_at/esp.c b/drivers/wifi/esp_at/esp.c index df20caae5b66696..e71a9b2bc1c69b9 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" @@ -199,8 +200,13 @@ MODEM_CMD_DEFINE(on_cmd_error) } /* RX thread */ -static void esp_rx(struct esp_data *data) +static void esp_rx(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct esp_data *data = p1; + while (true) { /* wait for incoming data */ modem_iface_uart_rx_wait(&data->mctx.iface, K_FOREVER); @@ -438,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); } @@ -504,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); @@ -511,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)) { @@ -756,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; @@ -1273,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) @@ -1366,7 +1380,7 @@ static int esp_init(const struct device *dev) /* start RX thread */ k_thread_create(&esp_rx_thread, esp_rx_stack, K_KERNEL_STACK_SIZEOF(esp_rx_stack), - (k_thread_entry_t)esp_rx, + esp_rx, data, NULL, NULL, K_PRIO_COOP(CONFIG_WIFI_ESP_AT_RX_THREAD_PRIORITY), 0, K_NO_WAIT); diff --git a/drivers/wifi/esp_at/esp_socket.c b/drivers/wifi/esp_at/esp_socket.c index e3600ea53669056..6a4147e528b80a3 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/CMakeLists.txt b/drivers/wifi/eswifi/CMakeLists.txt index 7b324a27b130717..9b3dae623afa866 100644 --- a/drivers/wifi/eswifi/CMakeLists.txt +++ b/drivers/wifi/eswifi/CMakeLists.txt @@ -5,6 +5,7 @@ if(CONFIG_WIFI_ESWIFI) zephyr_library_include_directories( # IP headers ${ZEPHYR_BASE}/subsys/net/ip + ${ZEPHYR_BASE}/subsys/net/lib/sockets ) zephyr_library_sources( diff --git a/drivers/wifi/eswifi/eswifi_bus_spi.c b/drivers/wifi/eswifi/eswifi_bus_spi.c index edade1ffdf8aaab..9fb24dda9076891 100644 --- a/drivers/wifi/eswifi/eswifi_bus_spi.c +++ b/drivers/wifi/eswifi/eswifi_bus_spi.c @@ -219,8 +219,11 @@ static void eswifi_spi_read_msg(struct eswifi_dev *eswifi) eswifi_unlock(eswifi); } -static void eswifi_spi_poll_thread(void *p1) +static void eswifi_spi_poll_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + struct eswifi_dev *eswifi = p1; while (1) { @@ -255,7 +258,7 @@ int eswifi_spi_init(struct eswifi_dev *eswifi) k_thread_create(&spi->poll_thread, eswifi_spi_poll_stack, ESWIFI_SPI_THREAD_STACK_SIZE, - (k_thread_entry_t)eswifi_spi_poll_thread, eswifi, NULL, + eswifi_spi_poll_thread, eswifi, NULL, NULL, K_PRIO_COOP(CONFIG_WIFI_ESWIFI_THREAD_PRIO), 0, K_NO_WAIT); diff --git a/drivers/wifi/eswifi/eswifi_core.c b/drivers/wifi/eswifi/eswifi_core.c index 0beecd4a4fc66f3..82f24982d1a37c8 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/CMakeLists.txt b/drivers/wifi/infineon/CMakeLists.txt new file mode 100644 index 000000000000000..20f69f181117fc8 --- /dev/null +++ b/drivers/wifi/infineon/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(./) + +zephyr_library_sources_ifdef(CONFIG_WIFI_AIROC airoc_wifi.c) +zephyr_library_sources_ifdef(CONFIG_WIFI_AIROC airoc_whd_hal.c) + +zephyr_compile_definitions(CYBSP_WIFI_CAPABLE) +zephyr_compile_definitions(CY_RTOS_AWARE) +zephyr_compile_definitions(WHD_USE_CUSTOM_MALLOC_IMPL) +zephyr_compile_definitions(WHD_USE_CUSTOM_HAL_IMPL) diff --git a/drivers/wifi/infineon/Kconfig.airoc b/drivers/wifi/infineon/Kconfig.airoc new file mode 100644 index 000000000000000..a3eac53862d54c6 --- /dev/null +++ b/drivers/wifi/infineon/Kconfig.airoc @@ -0,0 +1,142 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +menuconfig WIFI_AIROC + bool "Infineon AIROC SoC Wi-Fi support" + select THREAD_CUSTOM_DATA + select WIFI_OFFLOAD + select NET_L2_WIFI_MGMT + select SDIO_STACK + select SDHC + select WIFI_USE_NATIVE_NETWORKING + select USE_INFINEON_ABSTRACTION_RTOS + depends on DT_HAS_INFINEON_AIROC_WIFI_ENABLED + help + Enable Infineon AIROC SoC Wi-Fi support. + +if WIFI_AIROC + +config AIROC_WIFI_EVENT_TASK_STACK_SIZE + int "Event Task Stack Size" + default 4096 + +config AIROC_WIFI_EVENT_TASK_PRIO + int "Event Task Priority" + default 4 + +config AIROC_WLAN_MFG_FIRMWARE + bool "WLAN Manufacturing Firmware" + help + Enable WLAN Manufacturing Firmware. + +config AIROC_WIFI_CUSTOM + bool "Custom CYW43xx device/module" + help + Select Custom CYW43xx device/module. For this option, + user must to provide path to FW, CLM and NVRAM for + custom or vendor CYW43xx modules. + +choice AIROC_PART + prompt "Select AIROC part" + depends on !AIROC_WIFI_CUSTOM + +config CYW4343W + bool "CYW4343W" + help + Enable Infineon AIROC CYW4343W Wi-Fi connectivity, + More information about CYW4343W device you can find on + https://www.infineon.com/cms/en/product/wireless-connectivity/airoc-wi-fi-plus-bluetooth-combos/cyw4343w/ + +config CYW4373 + bool "CYW4373" + help + Enable Infineon AIROC CYW4373 Wi-Fi connectivity, + More information about CYW4373 device you can find on + https://www.infineon.com/cms/en/product/wireless-connectivity/airoc-wi-fi-plus-bluetooth-combos/cyw4373/ + +config CYW43012 + bool "CYW43012" + help + Enable Infineon AIROC CYW43012 Wi-Fi connectivity, + More information about CYW43012 device you can find on + https://www.infineon.com/cms/en/product/wireless-connectivity/airoc-wi-fi-plus-bluetooth-combos/cyw43012/ + +config CYW43438 + bool "CYW43438" + help + Enable Infineon AIROC CYW43438 Wi-Fi connectivity, + More information about CYW43438 device you can find on + https://www.infineon.com/cms/en/product/wireless-connectivity/airoc-wi-fi-plus-bluetooth-combos/cyw43438/ + +config CYW43439 + bool "CYW43439" + help + Enable Infineon AIROC CYW43439 Wi-Fi connectivity, + More information about CYW43439 device you can find on + https://www.infineon.com/cms/en/product/wireless-connectivity/airoc-wi-fi-plus-bluetooth-combos/cyw43439/ +endchoice + +choice CYW43012_MODULE + prompt "Select CYW43012 module" + depends on CYW43012 && !AIROC_WIFI_CUSTOM + +config CYW43012_MURATA_1LV + bool "MURATA-1LV" + help + Murata Type 1LV module based on Infineon CYW43012 combo chipset + which supports Wi-Fi® 802.11a/b/g/n + Bluetooth® 5.0 BR/EDR/LE + up to 72.2Mbps PHY data rate on Wi-fi® and 3Mbps PHY data rate + on Bluetooth®. 2Mbps LE PHY is also supported. + + Detailed information about Murata Type 1LV module you can find on + https://www.murata.com/en-us/products/connectivitymodule/wi-fi-bluetooth/overview/lineup/type1lv +endchoice + +choice CYW4343W_MODULE + prompt "Select CYW4343W module" + depends on CYW4343W && !AIROC_WIFI_CUSTOM + +config CYW4343W_MURATA_1DX + bool "MURATA-1DX" + help + Murata Type 1DX modules based on Infineon CYW4343W combo chipset + which supports Wi-Fi® 802.11b/g/n + Bluetooth® 5.1 BR/EDR/LE + up to 65Mbps PHY data rate on Wi-fi® and 3Mbps PHY data rate + on Bluetooth®. + + Detailed information about Type 1DX module you can find on + https://www.murata.com/en-us/products/connectivitymodule/wi-fi-bluetooth/overview/lineup/type1dx +endchoice + +choice CYW4373_MODULE + prompt "Select CYW4373 module" + depends on CYW4373 && !AIROC_WIFI_CUSTOM + +config CYW4373_STERLING_LWB5PLUS + bool "STERLING-LWB5plus" + help + Laird Sterling LWB5+ 802.11ac / Bluetooth 5.0 M.2 Carrier Board + (E-Type Key w/ SDIO/UART) + + Detailed information about Type Sterling LWB5+ module you can find on + https://www.lairdconnect.com/wireless-modules/wifi-modules-bluetooth/sterling-lwb5-plus-wifi-5-bluetooth-5-module +endchoice + +choice CYW43439_MODULE + prompt "Select CYW43439 module" + depends on CYW43439 && !AIROC_WIFI_CUSTOM + +config CYW43439_MURATA_1YN + bool "MURATA_1YN" + help + Murata Type 1YN module based on Infineon CYW43439 combo chipset + which supports Wi-Fi® 802.11b/g/n + Bluetooth® 5.2 BR/EDR/LE + up to 65Mbps PHY data rate on Wi-fi® and 3Mbps PHY data rate on + Bluetooth®. + + Detailed information about Murata Type 1YN module you can find on + https://www.murata.com/en-us/products/connectivitymodule/wi-fi-bluetooth/overview/lineup/type1yn +endchoice + +endif # AIROC_WIFI diff --git a/drivers/wifi/infineon/airoc_whd_hal.c b/drivers/wifi/infineon/airoc_whd_hal.c new file mode 100644 index 000000000000000..5b02d0bba4950f3 --- /dev/null +++ b/drivers/wifi/infineon/airoc_whd_hal.c @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include + +#define DT_DRV_COMPAT infineon_airoc_wifi + +LOG_MODULE_REGISTER(infineon_airoc, CONFIG_WIFI_LOG_LEVEL); + +#ifdef __cplusplus +extern "C" { +#endif + +/** Defines the amount of stack memory available for the wifi thread. */ +#if !defined(CY_WIFI_THREAD_STACK_SIZE) +#define CY_WIFI_THREAD_STACK_SIZE (5120) +#endif + +/** Defines the priority of the thread that services wifi packets. Legal values are defined by the + * RTOS being used. + */ +#if !defined(CY_WIFI_THREAD_PRIORITY) +#define CY_WIFI_THREAD_PRIORITY (CY_RTOS_PRIORITY_HIGH) +#endif + +/** Defines the country this will operate in for wifi initialization parameters. See the + * wifi-host-driver's whd_country_code_t for legal options. + */ +#if !defined(CY_WIFI_COUNTRY) +#define CY_WIFI_COUNTRY (WHD_COUNTRY_AUSTRALIA) +#endif + +/** Defines the priority of the interrupt that handles out-of-band notifications from the wifi + * chip. Legal values are defined by the MCU running this code. + */ +#if !defined(CY_WIFI_OOB_INTR_PRIORITY) +#define CY_WIFI_OOB_INTR_PRIORITY (2) +#endif + +/** Defines whether to use the out-of-band pin to allow the WIFI chip to wake up the MCU. */ +#if defined(CY_WIFI_HOST_WAKE_SW_FORCE) +#define CY_USE_OOB_INTR (CY_WIFI_HOST_WAKE_SW_FORCE) +#else +#define CY_USE_OOB_INTR (1u) +#endif /* defined(CY_WIFI_HOST_WAKE_SW_FORCE) */ + +#define CY_WIFI_HOST_WAKE_IRQ_EVENT GPIO_INT_TRIG_LOW +#define DEFAULT_OOB_PIN (0) +#define WLAN_POWER_UP_DELAY_MS (250) +#define WLAN_CBUCK_DISCHARGE_MS (10) + +extern whd_resource_source_t resource_ops; + +struct whd_bus_priv { + whd_sdio_config_t sdio_config; + whd_bus_stats_t whd_bus_stats; + whd_sdio_t sdio_obj; +}; + +static whd_init_config_t init_config_default = { + .thread_stack_size = CY_WIFI_THREAD_STACK_SIZE, + .thread_stack_start = NULL, + .thread_priority = (uint32_t)CY_WIFI_THREAD_PRIORITY, + .country = CY_WIFI_COUNTRY +}; + +/****************************************************** + * Function + ******************************************************/ + +int airoc_wifi_power_on(const struct device *dev) +{ +#if DT_INST_NODE_HAS_PROP(0, wifi_reg_on_gpios) + int ret; + const struct airoc_wifi_config *config = dev->config; + + /* Check WIFI REG_ON gpio instance */ + if (!device_is_ready(config->wifi_reg_on_gpio.port)) { + LOG_ERR("Error: failed to configure wifi_reg_on %s pin %d", + config->wifi_reg_on_gpio.port->name, config->wifi_reg_on_gpio.pin); + return -EIO; + } + + /* Configure wifi_reg_on as output */ + ret = gpio_pin_configure_dt(&config->wifi_reg_on_gpio, GPIO_OUTPUT); + if (ret) { + LOG_ERR("Error %d: failed to configure wifi_reg_on %s pin %d", ret, + config->wifi_reg_on_gpio.port->name, config->wifi_reg_on_gpio.pin); + return ret; + } + ret = gpio_pin_set_dt(&config->wifi_reg_on_gpio, 0); + if (ret) { + return ret; + } + + /* Allow CBUCK regulator to discharge */ + (void)cyhal_system_delay_ms(WLAN_CBUCK_DISCHARGE_MS); + + /* WIFI power on */ + ret = gpio_pin_set_dt(&config->wifi_reg_on_gpio, 1); + if (ret) { + return ret; + } + (void)cyhal_system_delay_ms(WLAN_POWER_UP_DELAY_MS); +#endif /* DT_INST_NODE_HAS_PROP(0, reg_on_gpios) */ + + return 0; +} + +int airoc_wifi_init_primary(const struct device *dev, whd_interface_t *interface, + whd_netif_funcs_t *netif_funcs, whd_buffer_funcs_t *buffer_if) +{ + int ret; + struct airoc_wifi_data *data = dev->data; + const struct airoc_wifi_config *config = dev->config; + + whd_sdio_config_t whd_sdio_config = { + .sdio_1bit_mode = WHD_FALSE, + .high_speed_sdio_clock = WHD_FALSE, + }; + +#if DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) + whd_oob_config_t oob_config = { + .host_oob_pin = (void *)&config->wifi_host_wake_gpio, + .dev_gpio_sel = DEFAULT_OOB_PIN, + .is_falling_edge = + (CY_WIFI_HOST_WAKE_IRQ_EVENT == GPIO_INT_TRIG_LOW) ? WHD_TRUE : WHD_FALSE, + .intr_priority = CY_WIFI_OOB_INTR_PRIORITY}; + whd_sdio_config.oob_config = oob_config; +#endif + + if (airoc_wifi_power_on(dev)) { + LOG_ERR("airoc_wifi_power_on retuens fail"); + return -ENODEV; + } + + if (!device_is_ready(config->sdhc_dev)) { + LOG_ERR("SDHC device is not ready"); + return -ENODEV; + } + + ret = sd_init(config->sdhc_dev, &data->card); + if (ret) { + return ret; + } + + /* Init SDIO functions */ + ret = sdio_init_func(&data->card, &data->sdio_func1, BACKPLANE_FUNCTION); + if (ret) { + LOG_ERR("sdio_enable_func BACKPLANE_FUNCTION, error: %x", ret); + return ret; + } + ret = sdio_init_func(&data->card, &data->sdio_func2, WLAN_FUNCTION); + if (ret) { + LOG_ERR("sdio_enable_func WLAN_FUNCTION, error: %x", ret); + return ret; + } + ret = sdio_set_block_size(&data->sdio_func1, SDIO_64B_BLOCK); + if (ret) { + LOG_ERR("Can't set block size for BACKPLANE_FUNCTION, error: %x", ret); + return ret; + } + ret = sdio_set_block_size(&data->sdio_func2, SDIO_64B_BLOCK); + if (ret) { + LOG_ERR("Can't set block size for WLAN_FUNCTION, error: %x", ret); + return ret; + } + + /* Init wifi host driver (whd) */ + cy_rslt_t whd_ret = whd_init(&data->whd_drv, &init_config_default, &resource_ops, buffer_if, + netif_funcs); + if (whd_ret == CY_RSLT_SUCCESS) { + whd_ret = whd_bus_sdio_attach(data->whd_drv, &whd_sdio_config, + (whd_sdio_t)&data->card); + + if (whd_ret == CY_RSLT_SUCCESS) { + whd_ret = whd_wifi_on(data->whd_drv, interface); + } + + if (whd_ret != CY_RSLT_SUCCESS) { + whd_deinit(*interface); + return -ENODEV; + } + } + return 0; +} + +/* + * Implement SDIO CMD52/53 wrappers + */ + +static struct sdio_func *airoc_wifi_get_sdio_func(struct sd_card *sd, whd_bus_function_t function) +{ + struct airoc_wifi_data *data = CONTAINER_OF(sd, struct airoc_wifi_data, card); + struct sdio_func *func[] = {&sd->func0, &data->sdio_func1, &data->sdio_func2}; + + if (function > WLAN_FUNCTION) { + return NULL; + } + + return func[function]; +} + +whd_result_t whd_bus_sdio_cmd52(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction, + whd_bus_function_t function, uint32_t address, uint8_t value, + sdio_response_needed_t response_expected, uint8_t *response) +{ + int ret; + struct sd_card *sd = whd_driver->bus_priv->sdio_obj; + struct sdio_func *func = airoc_wifi_get_sdio_func(sd, function); + + WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, cmd52); + + if (direction == BUS_WRITE) { + ret = sdio_rw_byte(func, address, value, response); + } else { + ret = sdio_read_byte(func, address, response); + } + WHD_BUS_STATS_CONDITIONAL_INCREMENT_VARIABLE(whd_driver->bus_priv, (ret != WHD_SUCCESS), + cmd52_fail); + + /* Possibly device might not respond to this cmd. So, don't check return value here */ + if ((ret != WHD_SUCCESS) && (address == SDIO_SLEEP_CSR)) { + return ret; + } + + CHECK_RETURN(ret); + return WHD_SUCCESS; +} + +whd_result_t whd_bus_sdio_cmd53(whd_driver_t whd_driver, whd_bus_transfer_direction_t direction, + whd_bus_function_t function, sdio_transfer_mode_t mode, + uint32_t address, uint16_t data_size, uint8_t *data, + sdio_response_needed_t response_expected, uint32_t *response) +{ + whd_result_t ret; + struct sd_card *sd = whd_driver->bus_priv->sdio_obj; + struct sdio_func *func = airoc_wifi_get_sdio_func(sd, function); + + if (direction == BUS_WRITE) { + WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, cmd53_write); + ret = sdio_write_addr(func, address, data, data_size); + } else { + WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, cmd53_read); + ret = sdio_read_addr(func, address, data, data_size); + } + + WHD_BUS_STATS_CONDITIONAL_INCREMENT_VARIABLE( + whd_driver->bus_priv, ((ret != WHD_SUCCESS) && (direction == BUS_READ)), + cmd53_read_fail); + WHD_BUS_STATS_CONDITIONAL_INCREMENT_VARIABLE( + whd_driver->bus_priv, ((ret != WHD_SUCCESS) && (direction == BUS_WRITE)), + cmd53_write_fail); + + CHECK_RETURN(ret); + return WHD_SUCCESS; +} + +/* + * Implement SDIO Card interrupt + */ + +void whd_bus_sdio_irq_handler(const struct device *dev, int reason, const void *user_data) +{ + if (reason == SDHC_INT_SDIO) { + whd_driver_t whd_driver = (whd_driver_t)user_data; + + WHD_BUS_STATS_INCREMENT_VARIABLE(whd_driver->bus_priv, sdio_intrs); + + /* call thread notify to wake up WHD thread */ + whd_thread_notify_irq(whd_driver); + } +} + +whd_result_t whd_bus_sdio_irq_register(whd_driver_t whd_driver) +{ + /* Nothing to do here, all handles by whd_bus_sdio_irq_enable function */ + return WHD_SUCCESS; +} + +whd_result_t whd_bus_sdio_irq_enable(whd_driver_t whd_driver, whd_bool_t enable) +{ + int ret; + struct sd_card *sd = whd_driver->bus_priv->sdio_obj; + + /* Enable/disable SDIO Card interrupts */ + if (enable) { + ret = sdhc_enable_interrupt(sd->sdhc, whd_bus_sdio_irq_handler, SDHC_INT_SDIO, + whd_driver); + } else { + ret = sdhc_disable_interrupt(sd->sdhc, SDHC_INT_SDIO); + } + return ret; +} + +/* + * Implement OOB functionality + */ + +void whd_bus_sdio_oob_irq_handler(const struct device *port, struct gpio_callback *cb, + gpio_port_pins_t pins) +{ +#if DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) + struct airoc_wifi_data *data = CONTAINER_OF(cb, struct airoc_wifi_data, host_oob_pin_cb); + + /* Get OOB pin info */ + const whd_oob_config_t *oob_config = &data->whd_drv->bus_priv->sdio_config.oob_config; + const struct gpio_dt_spec *host_oob_pin = oob_config->host_oob_pin; + + /* Check OOB state is correct */ + int expected_event = (oob_config->is_falling_edge == WHD_TRUE) ? 0 : 1; + + if (!(pins & BIT(host_oob_pin->pin)) || (gpio_pin_get_dt(host_oob_pin) != expected_event)) { + WPRINT_WHD_ERROR(("Unexpected interrupt event %d\n", expected_event)); + WHD_BUS_STATS_INCREMENT_VARIABLE(data->whd_drv->bus_priv, error_intrs); + return; + } + + WHD_BUS_STATS_INCREMENT_VARIABLE(data->whd_drv->bus_priv, oob_intrs); + + /* Call thread notify to wake up WHD thread */ + whd_thread_notify_irq(data->whd_drv); + +#endif /* DT_INST_NODE_HAS_PROP(0, wifi-host-wake-gpios) */ +} + +whd_result_t whd_bus_sdio_register_oob_intr(whd_driver_t whd_driver) +{ +#if DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) + int ret; + const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); + struct airoc_wifi_data *data = dev->data; + + /* Get OOB pin info */ + const whd_oob_config_t *oob_config = &whd_driver->bus_priv->sdio_config.oob_config; + const struct gpio_dt_spec *host_oob_pin = oob_config->host_oob_pin; + + /* Check if OOB pin is ready */ + if (!gpio_is_ready_dt(host_oob_pin)) { + WPRINT_WHD_ERROR(("%s: Failed at gpio_is_ready_dt for host_oob_pin\n", __func__)); + return WHD_HAL_ERROR; + } + + /* Configure OOB pin as output */ + ret = gpio_pin_configure_dt(host_oob_pin, GPIO_INPUT); + if (ret != 0) { + WPRINT_WHD_ERROR(( + " %s: Failed at gpio_pin_configure_dt for host_oob_pin, result code = %d\n", + __func__, ret)); + return WHD_HAL_ERROR; + } + + /* Initialize/add OOB pin callback */ + gpio_init_callback(&data->host_oob_pin_cb, whd_bus_sdio_oob_irq_handler, + BIT(host_oob_pin->pin)); + + ret = gpio_add_callback_dt(host_oob_pin, &data->host_oob_pin_cb); + if (ret != 0) { + WPRINT_WHD_ERROR( + ("%s: Failed at gpio_add_callback_dt for host_oob_pin, result code = %d\n", + __func__, ret)); + return WHD_HAL_ERROR; + } +#endif /* DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) */ + + return WHD_SUCCESS; +} + +whd_result_t whd_bus_sdio_unregister_oob_intr(whd_driver_t whd_driver) +{ +#if DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) + int ret; + const whd_oob_config_t *oob_config = &whd_driver->bus_priv->sdio_config.oob_config; + + /* Disable OOB pin interrupts */ + ret = gpio_pin_interrupt_configure_dt(oob_config->host_oob_pin, GPIO_INT_DISABLE); + if (ret != 0) { + WPRINT_WHD_ERROR(("%s: Failed at gpio_pin_interrupt_configure_dt for host_oob_pin, " + "result code = %d\n", + __func__, ret)); + return WHD_HAL_ERROR; + } +#endif /* DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) */ + return WHD_SUCCESS; +} + +whd_result_t whd_bus_sdio_enable_oob_intr(whd_driver_t whd_driver, whd_bool_t enable) +{ +#if DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) + int ret; + const whd_oob_config_t *oob_config = &whd_driver->bus_priv->sdio_config.oob_config; + uint32_t trig_conf = + (oob_config->is_falling_edge == WHD_TRUE) ? GPIO_INT_TRIG_LOW : GPIO_INT_TRIG_HIGH; + + /* Enable OOB pin interrupts */ + ret = gpio_pin_interrupt_configure_dt(oob_config->host_oob_pin, + GPIO_INT_ENABLE | GPIO_INT_EDGE | trig_conf); + if (ret != 0) { + WPRINT_WHD_ERROR(("%s: Failed at gpio_pin_interrupt_configure_dt for host_oob_pin, " + "result code = %d\n", + __func__, ret)); + return WHD_HAL_ERROR; + } +#endif /* DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) */ + return WHD_SUCCESS; +} + +/* + * Implement WHD memory wrappers + */ + +void *whd_mem_malloc(size_t size) +{ + return k_malloc(size); +} + +void *whd_mem_calloc(size_t nitems, size_t size) +{ + return k_calloc(nitems, size); +} + +void whd_mem_free(void *ptr) +{ + k_free(ptr); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/drivers/wifi/infineon/airoc_wifi.c b/drivers/wifi/infineon/airoc_wifi.c new file mode 100644 index 000000000000000..752e6c9048ae527 --- /dev/null +++ b/drivers/wifi/infineon/airoc_wifi.c @@ -0,0 +1,775 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief AIROC Wi-Fi driver. + */ + +#define DT_DRV_COMPAT infineon_airoc_wifi + +#include +#include +#include + +LOG_MODULE_REGISTER(infineon_airoc_wifi, CONFIG_WIFI_LOG_LEVEL); + +#ifndef AIROC_WIFI_TX_PACKET_POOL_COUNT +#define AIROC_WIFI_TX_PACKET_POOL_COUNT (10) +#endif + +#ifndef AIROC_WIFI_RX_PACKET_POOL_COUNT +#define AIROC_WIFI_RX_PACKET_POOL_COUNT (10) +#endif + +#ifndef AIROC_WIFI_PACKET_POOL_SIZE +#define AIROC_WIFI_PACKET_POOL_SIZE (1600) +#endif + +#define AIROC_WIFI_PACKET_POOL_COUNT \ + (AIROC_WIFI_TX_PACKET_POOL_COUNT + AIROC_WIFI_RX_PACKET_POOL_COUNT) + +#define AIROC_WIFI_WAIT_SEMA_MS (30 * 1000) +#define AIROC_WIFI_SCAN_TIMEOUT_MS (12 * 1000) + +/* AIROC private functions */ +static whd_result_t airoc_wifi_host_buffer_get(whd_buffer_t *buffer, whd_buffer_dir_t direction, + uint16_t size, uint32_t timeout_ms); +static void airoc_wifi_buffer_release(whd_buffer_t buffer, whd_buffer_dir_t direction); +static uint8_t *airoc_wifi_buffer_get_current_piece_data_pointer(whd_buffer_t buffer); +static uint16_t airoc_wifi_buffer_get_current_piece_size(whd_buffer_t buffer); +static whd_result_t airoc_wifi_buffer_set_size(whd_buffer_t buffer, unsigned short size); +static whd_result_t airoc_wifi_buffer_add_remove_at_front(whd_buffer_t *buffer, + int32_t add_remove_amount); +static void airoc_wifi_network_process_ethernet_data(whd_interface_t interface, + whd_buffer_t buffer); +int airoc_wifi_init_primary(const struct device *dev, whd_interface_t *interface, + whd_netif_funcs_t *netif_funcs, whd_buffer_funcs_t *buffer_if); + +/* Allocate network pool */ +NET_BUF_POOL_FIXED_DEFINE(airoc_pool, AIROC_WIFI_PACKET_POOL_COUNT, + AIROC_WIFI_PACKET_POOL_SIZE, 0, NULL); + +/* AIROC globals */ +static uint16_t ap_event_handler_index = 0xFF; + +/* Use global iface pointer to support any Ethernet driver */ +/* necessary for wifi callback functions */ +static struct net_if *airoc_wifi_iface; + +static whd_interface_t airoc_if; +static whd_interface_t airoc_sta_if; +static whd_interface_t airoc_ap_if; + +static const whd_event_num_t sta_link_events[] = { + WLC_E_LINK, WLC_E_DEAUTH_IND, WLC_E_DISASSOC_IND, + WLC_E_PSK_SUP, WLC_E_CSA_COMPLETE_IND, WLC_E_NONE}; + +static const whd_event_num_t ap_link_events[] = {WLC_E_DISASSOC_IND, WLC_E_DEAUTH_IND, + WLC_E_ASSOC_IND, WLC_E_REASSOC_IND, + WLC_E_AUTHORIZED, WLC_E_NONE}; + +static uint16_t sta_event_handler_index = 0xFF; +static void airoc_event_task(void); +static struct airoc_wifi_data airoc_wifi_data = {0}; + +static struct airoc_wifi_config airoc_wifi_config = { + .sdhc_dev = DEVICE_DT_GET(DT_INST_PARENT(0)), + .wifi_reg_on_gpio = GPIO_DT_SPEC_GET_OR(DT_DRV_INST(0), wifi_reg_on_gpios, {0}), + .wifi_host_wake_gpio = GPIO_DT_SPEC_GET_OR(DT_DRV_INST(0), wifi_host_wake_gpios, {0}), + .wifi_dev_wake_gpio = GPIO_DT_SPEC_GET_OR(DT_DRV_INST(0), wifi_dev_wake_gpios, {0}), +}; + +static whd_buffer_funcs_t airoc_wifi_buffer_if_default = { + .whd_host_buffer_get = airoc_wifi_host_buffer_get, + .whd_buffer_release = airoc_wifi_buffer_release, + .whd_buffer_get_current_piece_data_pointer = + airoc_wifi_buffer_get_current_piece_data_pointer, + .whd_buffer_get_current_piece_size = airoc_wifi_buffer_get_current_piece_size, + .whd_buffer_set_size = airoc_wifi_buffer_set_size, + .whd_buffer_add_remove_at_front = airoc_wifi_buffer_add_remove_at_front, +}; + +static whd_netif_funcs_t airoc_wifi_netif_if_default = { + .whd_network_process_ethernet_data = airoc_wifi_network_process_ethernet_data, +}; + +K_MSGQ_DEFINE(airoc_wifi_msgq, sizeof(whd_event_header_t), 10, 4); +K_THREAD_STACK_DEFINE(airoc_wifi_event_stack, CONFIG_AIROC_WIFI_EVENT_TASK_STACK_SIZE); +static struct k_thread airoc_wifi_event_thread; + +struct airoc_wifi_event_t { + uint8_t is_ap_event; + uint32_t event_type; +}; + +/* + * AIROC Wi-Fi helper functions + */ +whd_interface_t airoc_wifi_get_whd_interface(void) +{ + return airoc_if; +} + +static void airoc_wifi_scan_cb_search(whd_scan_result_t **result_ptr, void *user_data, + whd_scan_status_t status) +{ + if (status == WHD_SCAN_ABORTED) { + k_sem_give(&airoc_wifi_data.sema_scan); + return; + } + + if (status == WHD_SCAN_COMPLETED_SUCCESSFULLY) { + k_sem_give(&airoc_wifi_data.sema_scan); + } else if ((status == WHD_SCAN_INCOMPLETE) && (user_data != NULL) && + ((**result_ptr).SSID.length > 0)) { + + if (strncmp(((whd_scan_result_t *)user_data)->SSID.value, (**result_ptr).SSID.value, + (**result_ptr).SSID.length) == 0) { + memcpy(user_data, *result_ptr, sizeof(whd_scan_result_t)); + } + } +} + +static int convert_whd_security_to_zephyr(whd_security_t security) +{ + int zephyr_security = WIFI_SECURITY_TYPE_UNKNOWN; + + switch (security) { + case WHD_SECURITY_OPEN: + zephyr_security = WIFI_SECURITY_TYPE_NONE; + break; + case WHD_SECURITY_WEP_PSK: + zephyr_security = WIFI_SECURITY_TYPE_WEP; + break; + + case WHD_SECURITY_WPA3_WPA2_PSK: + case WHD_SECURITY_WPA2_AES_PSK: + zephyr_security = WIFI_SECURITY_TYPE_PSK; + break; + + case WHD_SECURITY_WPA2_AES_PSK_SHA256: + zephyr_security = WIFI_SECURITY_TYPE_PSK_SHA256; + break; + + case WHD_SECURITY_WPA3_SAE: + zephyr_security = WIFI_SECURITY_TYPE_SAE; + break; + + case WHD_SECURITY_WPA_AES_PSK: + zephyr_security = WIFI_SECURITY_TYPE_WPA_PSK; + break; + + default: + if ((security & ENTERPRISE_ENABLED) != 0) { + zephyr_security = WIFI_SECURITY_TYPE_EAP; + } + break; + } + return zephyr_security; +} + +static void parse_scan_result(whd_scan_result_t *p_whd_result, struct wifi_scan_result *p_zy_result) +{ + if (p_whd_result->SSID.length != 0) { + p_zy_result->ssid_length = p_whd_result->SSID.length; + strncpy(p_zy_result->ssid, p_whd_result->SSID.value, p_whd_result->SSID.length); + p_zy_result->channel = p_whd_result->channel; + p_zy_result->security = convert_whd_security_to_zephyr(p_whd_result->security); + p_zy_result->rssi = (int8_t)p_whd_result->signal_strength; + p_zy_result->mac_length = 6; + memcpy(p_zy_result->mac, &p_whd_result->BSSID, 6); + } +} + +static void scan_callback(whd_scan_result_t **result_ptr, void *user_data, whd_scan_status_t status) +{ + struct airoc_wifi_data *data = user_data; + whd_scan_result_t whd_scan_result; + struct wifi_scan_result zephyr_scan_result; + + if (status == WHD_SCAN_COMPLETED_SUCCESSFULLY || status == WHD_SCAN_ABORTED) { + data->scan_rslt_cb(data->iface, 0, NULL); + data->scan_rslt_cb = NULL; + /* NOTE: It is complete of scan packet, do not need to clean result_ptr, + * WHD will release result_ptr buffer + */ + return; + } + + /* We recived scan data so process it */ + if ((result_ptr != NULL) && (*result_ptr != NULL)) { + memcpy(&whd_scan_result, *result_ptr, sizeof(whd_scan_result_t)); + parse_scan_result(&whd_scan_result, &zephyr_scan_result); + data->scan_rslt_cb(data->iface, 0, &zephyr_scan_result); + } + memset(*result_ptr, 0, sizeof(whd_scan_result_t)); +} + +/* + * Implement WHD network buffers functions + */ +static whd_result_t airoc_wifi_host_buffer_get(whd_buffer_t *buffer, whd_buffer_dir_t direction, + uint16_t size, uint32_t timeout_ms) +{ + ARG_UNUSED(direction); + ARG_UNUSED(timeout_ms); + struct net_buf *buf; + + buf = net_buf_alloc_len(&airoc_pool, size, K_NO_WAIT); + if (buf == NULL) { + return WHD_BUFFER_ALLOC_FAIL; + } + *buffer = buf; + return WHD_SUCCESS; +} + +static void airoc_wifi_buffer_release(whd_buffer_t buffer, whd_buffer_dir_t direction) +{ + CY_UNUSED_PARAMETER(direction); + (void)net_buf_destroy((struct net_buf *)buffer); +} + +static uint8_t *airoc_wifi_buffer_get_current_piece_data_pointer(whd_buffer_t buffer) +{ + CY_ASSERT(buffer != NULL); + struct net_buf *buf = (struct net_buf *)buffer; + + return (uint8_t *)buf->data; +} + +static uint16_t airoc_wifi_buffer_get_current_piece_size(whd_buffer_t buffer) +{ + CY_ASSERT(buffer != NULL); + struct net_buf *buf = (struct net_buf *)buffer; + + return (uint16_t)buf->size; +} + +static whd_result_t airoc_wifi_buffer_set_size(whd_buffer_t buffer, unsigned short size) +{ + CY_ASSERT(buffer != NULL); + struct net_buf *buf = (struct net_buf *)buffer; + + buf->size = size; + return CY_RSLT_SUCCESS; +} + +static whd_result_t airoc_wifi_buffer_add_remove_at_front(whd_buffer_t *buffer, + int32_t add_remove_amount) +{ + CY_ASSERT(buffer != NULL); + struct net_buf **buf = (struct net_buf **)buffer; + + if (add_remove_amount > 0) { + (*buf)->len = (*buf)->size; + (*buf)->data = net_buf_pull(*buf, add_remove_amount); + } else { + (*buf)->data = net_buf_push(*buf, -add_remove_amount); + (*buf)->len = (*buf)->size; + } + return WHD_SUCCESS; +} + +static int airoc_mgmt_send(const struct device *dev, struct net_pkt *pkt) +{ + struct airoc_wifi_data *data = dev->data; + cy_rslt_t ret; + size_t pkt_len = net_pkt_get_len(pkt); + struct net_buf *buf = NULL; + + /* Read the packet payload */ + if (net_pkt_read(pkt, data->frame_buf, pkt_len) < 0) { + LOG_ERR("net_pkt_read failed"); + return -EIO; + } + + /* Allocate Network Buffer from pool with Packet Length + Data Header */ + buf = net_buf_alloc_len(&airoc_pool, pkt_len + sizeof(data_header_t), K_NO_WAIT); + if (buf == NULL) { + return -EIO; + } + + /* Reserve the buffer Headroom for WHD Data header */ + net_buf_reserve(buf, sizeof(data_header_t)); + + /* Copy the buffer to network Buffer pointer */ + (void)memcpy(buf->data, data->frame_buf, pkt_len); + + /* Call WHD API to send out the Packet */ + ret = whd_network_send_ethernet_data(airoc_if, (void *)buf); + if (ret != CY_RSLT_SUCCESS) { + LOG_ERR("whd_network_send_ethernet_data failed"); +#if defined(CONFIG_NET_STATISTICS_WIFI) + data->stats.errors.tx++; +#endif + return -EIO; + } + +#if defined(CONFIG_NET_STATISTICS_WIFI) + data->stats.bytes.sent += pkt_len; + data->stats.pkts.tx++; +#endif + + return 0; +} + +static void airoc_wifi_network_process_ethernet_data(whd_interface_t interface, whd_buffer_t buffer) +{ + struct net_pkt *pkt; + uint8_t *data = whd_buffer_get_current_piece_data_pointer(interface->whd_driver, buffer); + uint32_t len = whd_buffer_get_current_piece_size(interface->whd_driver, buffer); + bool net_pkt_unref_flag = false; + + if ((airoc_wifi_iface != NULL) && net_if_flag_is_set(airoc_wifi_iface, NET_IF_UP)) { + + pkt = net_pkt_rx_alloc_with_buffer(airoc_wifi_iface, len, AF_UNSPEC, 0, K_NO_WAIT); + + if (pkt != NULL) { + if (net_pkt_write(pkt, data, len) < 0) { + LOG_ERR("Failed to write pkt"); + net_pkt_unref_flag = true; + } + + if ((net_pkt_unref_flag) || (net_recv_data(airoc_wifi_iface, pkt) < 0)) { + LOG_ERR("Failed to push received data"); + net_pkt_unref_flag = true; + } + } else { + LOG_ERR("Failed to get net buffer"); + } + } + + /* Release a packet buffer */ + airoc_wifi_buffer_release(buffer, WHD_NETWORK_RX); + +#if defined(CONFIG_NET_STATISTICS_WIFI) + airoc_wifi_data.stats.bytes.received += len; + airoc_wifi_data.stats.pkts.rx++; +#endif + + if (net_pkt_unref_flag) { + net_pkt_unref(pkt); +#if defined(CONFIG_NET_STATISTICS_WIFI) + airoc_wifi_data.stats.errors.rx++; +#endif + } +} + +static void *link_events_handler(whd_interface_t ifp, const whd_event_header_t *event_header, + const uint8_t *event_data, void *handler_user_data) +{ + ARG_UNUSED(ifp); + ARG_UNUSED(event_data); + ARG_UNUSED(handler_user_data); + + k_msgq_put(&airoc_wifi_msgq, event_header, K_FOREVER); + return NULL; +} + +static void airoc_event_task(void) +{ + whd_event_header_t event_header; + + while (1) { + k_msgq_get(&airoc_wifi_msgq, &event_header, K_FOREVER); + + switch ((whd_event_num_t)event_header.event_type) { + case WLC_E_LINK: + break; + + case WLC_E_DEAUTH_IND: + case WLC_E_DISASSOC_IND: + net_if_dormant_on(airoc_wifi_iface); + break; + + default: + break; + } + } +} + +static void airoc_mgmt_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct airoc_wifi_data *data = dev->data; + struct ethernet_context *eth_ctx = net_if_l2_data(iface); + + eth_ctx->eth_if_type = L2_ETH_IF_TYPE_WIFI; + data->iface = iface; + airoc_wifi_iface = iface; + + /* Read WLAN MAC Address */ + if (whd_wifi_get_mac_address(airoc_sta_if, &airoc_sta_if->mac_addr) != WHD_SUCCESS) { + LOG_ERR("Failed to get mac address"); + } else { + (void)memcpy(&data->mac_addr, &airoc_sta_if->mac_addr, + sizeof(airoc_sta_if->mac_addr)); + } + + /* Assign link local address. */ + if (net_if_set_link_addr(iface, data->mac_addr, 6, NET_LINK_ETHERNET)) { + LOG_ERR("Failed to set link addr"); + } + + /* Initialize Ethernet L2 stack */ + ethernet_init(iface); + + /* Not currently connected to a network */ + net_if_dormant_on(iface); + + /* L1 network layer (physical layer) is up */ + net_if_carrier_on(data->iface); +} + +static int airoc_mgmt_scan(const struct device *dev, struct wifi_scan_params *params, + scan_result_cb_t cb) +{ + struct airoc_wifi_data *data = dev->data; + + if (data->scan_rslt_cb != NULL) { + LOG_INF("Scan callback in progress"); + return -EINPROGRESS; + } + + if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) { + return -EAGAIN; + } + + data->scan_rslt_cb = cb; + + /* Connect to the network */ + if (whd_wifi_scan(airoc_sta_if, params->scan_type, WHD_BSS_TYPE_ANY, &(data->ssid), NULL, + NULL, NULL, scan_callback, &(data->scan_result), data) != WHD_SUCCESS) { + LOG_ERR("Failed to start scan"); + k_sem_give(&data->sema_common); + return -EAGAIN; + } + + k_sem_give(&data->sema_common); + return 0; +} + +static int airoc_mgmt_connect(const struct device *dev, struct wifi_connect_req_params *params) +{ + struct airoc_wifi_data *data = (struct airoc_wifi_data *)dev->data; + whd_ssid_t ssid = {0}; + int ret = 0; + + if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) { + return -EAGAIN; + } + + if (data->is_sta_connected) { + LOG_ERR("Already connected"); + ret = -EALREADY; + goto error; + } + + if (data->is_ap_up) { + LOG_ERR("Network interface is busy AP. Please first disable AP."); + ret = -EBUSY; + goto error; + } + + ssid.length = params->ssid_length; + memcpy(ssid.value, params->ssid, params->ssid_length); + + whd_scan_result_t scan_result; + whd_scan_result_t usr_result = {0}; + + usr_result.SSID.length = ssid.length; + memcpy(usr_result.SSID.value, ssid.value, ssid.length); + + if (whd_wifi_scan(airoc_sta_if, WHD_SCAN_TYPE_ACTIVE, WHD_BSS_TYPE_ANY, NULL, NULL, NULL, + NULL, airoc_wifi_scan_cb_search, &scan_result, + &(usr_result)) != WHD_SUCCESS) { + LOG_ERR("Failed start scan"); + ret = -EAGAIN; + goto error; + } + + if (k_sem_take(&airoc_wifi_data.sema_scan, K_MSEC(AIROC_WIFI_SCAN_TIMEOUT_MS)) != 0) { + whd_wifi_stop_scan(airoc_sta_if); + ret = -EAGAIN; + goto error; + } + + if (usr_result.security == 0) { + ret = -EAGAIN; + LOG_ERR("Could not scan device"); + goto error; + } + + /* Connect to the network */ + if (whd_wifi_join(airoc_sta_if, &usr_result.SSID, usr_result.security, params->psk, + params->psk_length) != WHD_SUCCESS) { + LOG_ERR("Failed to connect with network"); + + ret = -EAGAIN; + goto error; + } + +error: + if (ret < 0) { + net_if_dormant_on(data->iface); + } else { + net_if_dormant_off(data->iface); + data->is_sta_connected = true; +#if defined(CONFIG_NET_DHCPV4) + net_dhcpv4_restart(data->iface); +#endif /* defined(CONFIG_NET_DHCPV4) */ + } + + wifi_mgmt_raise_connect_result_event(data->iface, ret); + k_sem_give(&data->sema_common); + return ret; +} + +static int airoc_mgmt_disconnect(const struct device *dev) +{ + int ret = 0; + struct airoc_wifi_data *data = (struct airoc_wifi_data *)dev->data; + + if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) { + return -EAGAIN; + } + + if (whd_wifi_leave(airoc_sta_if) != WHD_SUCCESS) { + k_sem_give(&data->sema_common); + ret = -EAGAIN; + } else { + data->is_sta_connected = false; + net_if_dormant_on(data->iface); + } + + wifi_mgmt_raise_disconnect_result_event(data->iface, ret); + k_sem_give(&data->sema_common); + + return ret; +} + +static void *airoc_wifi_ap_link_events_handler(whd_interface_t ifp, + const whd_event_header_t *event_header, + const uint8_t *event_data, void *handler_user_data) +{ + struct airoc_wifi_event_t airoc_event = { + .is_ap_event = 1, + .event_type = event_header->event_type + }; + + k_msgq_put(&airoc_wifi_msgq, &airoc_event, K_FOREVER); + + return NULL; +} + +static int airoc_mgmt_ap_enable(const struct device *dev, struct wifi_connect_req_params *params) +{ + struct airoc_wifi_data *data = dev->data; + whd_security_t security; + whd_ssid_t ssid; + uint8_t channel; + int ret = 0; + + if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) { + return -EAGAIN; + } + + if (data->is_sta_connected) { + LOG_ERR("Network interface is busy in STA mode. Please first disconnect STA."); + ret = -EBUSY; + goto error; + } + + if (data->is_ap_up) { + LOG_ERR("Already AP is on - first disable"); + ret = -EAGAIN; + goto error; + } + + if (!data->second_interface_init) { + if (whd_add_secondary_interface(data->whd_drv, NULL, &airoc_ap_if) != + CY_RSLT_SUCCESS) { + LOG_ERR("Error Unable to bring up the whd secondary interface"); + ret = -EAGAIN; + goto error; + } + data->second_interface_init = true; + } + + ssid.length = params->ssid_length; + memcpy(ssid.value, params->ssid, ssid.length); + + /* make sure to set valid channels for 2G and 5G: + * - 2G channels from 1 to 11, + * - 5G channels from 36 to 165 + */ + if (((params->channel > 0) && (params->channel < 12)) || + ((params->channel > 35) && (params->channel < 166))) { + channel = params->channel; + } else { + channel = 1; + LOG_WRN("Discard of setting unsupported channel: %u (will set 1)", + params->channel); + } + + if (params->psk_length == 0) { + security = WHD_SECURITY_OPEN; + } else { + security = WHD_SECURITY_WPA2_AES_PSK; + } + + if (whd_wifi_init_ap(airoc_ap_if, &ssid, security, (const uint8_t *)params->psk, + params->psk_length, channel) != 0) { + LOG_ERR("Failed to init whd ap interface"); + ret = -EAGAIN; + goto error; + } + + if (whd_wifi_start_ap(airoc_ap_if) != 0) { + LOG_ERR("Failed to start whd ap interface"); + ret = -EAGAIN; + goto error; + } + + /* set event handler */ + if (whd_management_set_event_handler(airoc_ap_if, ap_link_events, + airoc_wifi_ap_link_events_handler, NULL, + &ap_event_handler_index) != 0) { + whd_wifi_stop_ap(airoc_ap_if); + ret = -EAGAIN; + goto error; + } + + data->is_ap_up = true; + airoc_if = airoc_ap_if; +error: + + k_sem_give(&data->sema_common); + return ret; +} + +#if defined(CONFIG_NET_STATISTICS_WIFI) +static int airoc_mgmt_wifi_stats(const struct device *dev, struct net_stats_wifi *stats) +{ + struct airoc_wifi_data *data = dev->data; + + stats->bytes.received = data->stats.bytes.received; + stats->bytes.sent = data->stats.bytes.sent; + stats->pkts.rx = data->stats.pkts.rx; + stats->pkts.tx = data->stats.pkts.tx; + stats->errors.rx = data->stats.errors.rx; + stats->errors.tx = data->stats.errors.tx; + stats->broadcast.rx = data->stats.broadcast.rx; + stats->broadcast.tx = data->stats.broadcast.tx; + stats->multicast.rx = data->stats.multicast.rx; + stats->multicast.tx = data->stats.multicast.tx; + stats->sta_mgmt.beacons_rx = data->stats.sta_mgmt.beacons_rx; + stats->sta_mgmt.beacons_miss = data->stats.sta_mgmt.beacons_miss; + + return 0; +} +#endif + +static int airoc_mgmt_ap_disable(const struct device *dev) +{ + cy_rslt_t whd_ret; + struct airoc_wifi_data *data = dev->data; + + if (k_sem_take(&data->sema_common, K_MSEC(AIROC_WIFI_WAIT_SEMA_MS)) != 0) { + return -EAGAIN; + } + + if (whd_wifi_deregister_event_handler(airoc_ap_if, ap_event_handler_index)) { + LOG_ERR("Can't whd_wifi_deregister_event_handler"); + } + + whd_ret = whd_wifi_stop_ap(airoc_ap_if); + if (whd_ret == CY_RSLT_SUCCESS) { + data->is_ap_up = false; + airoc_if = airoc_sta_if; + } else { + LOG_ERR("Can't stop wifi ap: %u", whd_ret); + } + + k_sem_give(&data->sema_common); + + if (whd_ret != CY_RSLT_SUCCESS) { + return -ENODEV; + } + + return 0; +} + +static int airoc_init(const struct device *dev) +{ + int ret; + cy_rslt_t whd_ret; + struct airoc_wifi_data *data = dev->data; + + k_tid_t tid = k_thread_create( + &airoc_wifi_event_thread, airoc_wifi_event_stack, + CONFIG_AIROC_WIFI_EVENT_TASK_STACK_SIZE, (k_thread_entry_t)airoc_event_task, NULL, + NULL, NULL, CONFIG_AIROC_WIFI_EVENT_TASK_PRIO, K_INHERIT_PERMS, K_NO_WAIT); + + if (!tid) { + LOG_ERR("ERROR spawning tx thread"); + return -EAGAIN; + } + k_thread_name_set(tid, "airoc_event"); + + whd_ret = airoc_wifi_init_primary(dev, &airoc_sta_if, &airoc_wifi_netif_if_default, + &airoc_wifi_buffer_if_default); + if (whd_ret != CY_RSLT_SUCCESS) { + LOG_ERR("airoc_wifi_init_primary failed ret = %d \r\n", whd_ret); + return -EAGAIN; + } + airoc_if = airoc_sta_if; + + whd_ret = whd_management_set_event_handler(airoc_sta_if, sta_link_events, + link_events_handler, NULL, &sta_event_handler_index); + if (whd_ret != CY_RSLT_SUCCESS) { + LOG_ERR("whd_management_set_event_handler failed ret = %d \r\n", whd_ret); + return -EAGAIN; + } + + ret = k_sem_init(&data->sema_common, 1, 1); + if (ret != 0) { + LOG_ERR("k_sem_init(sema_common) failure"); + return ret; + } + + ret = k_sem_init(&data->sema_scan, 0, 1); + if (ret != 0) { + LOG_ERR("k_sem_init(sema_scan) failure"); + return ret; + } + + return 0; +} + +static const struct wifi_mgmt_ops airoc_wifi_mgmt = { + .scan = airoc_mgmt_scan, + .connect = airoc_mgmt_connect, + .disconnect = airoc_mgmt_disconnect, + .ap_enable = airoc_mgmt_ap_enable, + .ap_disable = airoc_mgmt_ap_disable, +#if defined(CONFIG_NET_STATISTICS_ETHERNET) + .get_stats = airoc_mgmt_wifi_stats, +#endif +}; + +static const struct net_wifi_mgmt_offload airoc_api = { + .wifi_iface.iface_api.init = airoc_mgmt_init, + .wifi_iface.send = airoc_mgmt_send, + .wifi_mgmt_api = &airoc_wifi_mgmt, +}; + +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/infineon/airoc_wifi.h b/drivers/wifi/infineon/airoc_wifi.h new file mode 100644 index 000000000000000..648423ab109a104 --- /dev/null +++ b/drivers/wifi/infineon/airoc_wifi.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +struct airoc_wifi_data { + struct sd_card card; + struct sdio_func sdio_func1; + struct sdio_func sdio_func2; + struct net_if *iface; + bool second_interface_init; + bool is_ap_up; + bool is_sta_connected; + uint8_t mac_addr[6]; + scan_result_cb_t scan_rslt_cb; + whd_ssid_t ssid; + whd_scan_result_t scan_result; + struct k_sem sema_common; + struct k_sem sema_scan; +#if defined(CONFIG_NET_STATISTICS_WIFI) + struct net_stats_wifi stats; +#endif + whd_driver_t whd_drv; + struct gpio_callback host_oob_pin_cb; + uint8_t frame_buf[NET_ETH_MAX_FRAME_SIZE]; +}; + +struct airoc_wifi_config { + const struct device *sdhc_dev; + struct gpio_dt_spec wifi_reg_on_gpio; + struct gpio_dt_spec wifi_host_wake_gpio; + struct gpio_dt_spec wifi_dev_wake_gpio; +}; + +/** + * \brief This function returns pointer type to handle instance + * of whd interface (whd_interface_t) which allocated in + * Zephyr AIROC driver (drivers/wifi/infineon/airoc_wifi.c) + */ + +whd_interface_t airoc_wifi_get_whd_interface(void); diff --git a/drivers/wifi/infineon/cybsp.h b/drivers/wifi/infineon/cybsp.h new file mode 100644 index 000000000000000..dfa23ffbae53f6e --- /dev/null +++ b/drivers/wifi/infineon/cybsp.h @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* This is enpty/stub file used in WHD */ diff --git a/drivers/wifi/simplelink/CMakeLists.txt b/drivers/wifi/simplelink/CMakeLists.txt index 8e9a24b7c828739..3dbe2a2807f2db8 100644 --- a/drivers/wifi/simplelink/CMakeLists.txt +++ b/drivers/wifi/simplelink/CMakeLists.txt @@ -3,6 +3,7 @@ if(CONFIG_WIFI_SIMPLELINK) zephyr_library_include_directories( ${ZEPHYR_BASE}/subsys/net/lib/tls_credentials + ${ZEPHYR_BASE}/subsys/net/lib/sockets ) zephyr_library_sources( simplelink_support.c diff --git a/drivers/wifi/simplelink/simplelink.c b/drivers/wifi/simplelink/simplelink.c index 6e89275ee6fcdb5..c4af70ce003bd8c 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 758e776bf7cc7c1..588a2e3e0dcd1d9 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 @@ -639,6 +640,7 @@ static void handle_wifi_con_state_changed(void *pvMsg) LOG_DBG("Connected (%u)", pstrWifiState->u8ErrCode); w1500_data.connected = true; + w1500_data.connecting = false; wifi_mgmt_raise_connect_result_event(w1500_data.iface, 0); break; @@ -966,8 +968,12 @@ static void winc1500_socket_cb(SOCKET sock, uint8 message, void *pvMsg) #endif /* LOG_LEVEL > LOG_LEVEL_OFF */ } -static void winc1500_thread(void) +static void winc1500_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + while (1) { while (m2m_wifi_handle_events(NULL) != 0) { } @@ -1168,7 +1174,7 @@ static int winc1500_init(const struct device *dev) /* monitoring thread for winc wifi callbacks */ k_thread_create(&winc1500_thread_data, winc1500_stack, CONFIG_WIFI_WINC1500_THREAD_STACK_SIZE, - (k_thread_entry_t)winc1500_thread, NULL, NULL, NULL, + winc1500_thread, NULL, NULL, NULL, K_PRIO_COOP(CONFIG_WIFI_WINC1500_THREAD_PRIO), 0, K_NO_WAIT); k_thread_name_set(&winc1500_thread_data, "WINC1500"); @@ -1182,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/Kconfig b/dts/Kconfig index 46d1b85b6ec8b53..0e71bd525c0c138 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -1,11 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -config HAS_DTS - bool - help - This option specifies that the target platform supports device tree - configuration. - menu "Devicetree Info" osource "$(KCONFIG_BINARY_DIR)/Kconfig.dts" diff --git a/dts/arc/synopsys/arc_hs4xd.dtsi b/dts/arc/synopsys/arc_hs4xd.dtsi index 18a555cfbd4867f..d6650e651a95650 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 bb127594e2ed72c..6388db825a0166c 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 7d04321e0ee5a0c..1c809d1b0f8b3f2 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 375eb745594bfb3..1d7c4cf238c990d 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 a701d2412ee97a2..117421c228fa952 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 3f722ae282f3acf..a3abd1093e9364d 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 80b004c84af649a..dfc2f59de3d700c 100644 --- a/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi +++ b/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi @@ -2,15 +2,27 @@ #include #include +#include #include +#include / { clocks { uartclk: apb-pclk { compatible = "fixed-clock"; - clock-frequency = <24000000>; + clock-frequency = ; #clock-cells = <0>; }; + xo32m: xo32m { + compatible = "ambiq,clkctrl"; + clock-frequency = ; + #clock-cells = <1>; + }; + xo32k: xo32k { + compatible = "ambiq,clkctrl"; + clock-frequency = ; + #clock-cells = <1>; + }; }; cpus { @@ -23,12 +35,6 @@ }; }; - /* MRAM region */ - flash0: flash@18000 { - compatible = "soc-nv-flash"; - reg = <0x00018000 0x1e8000>; - }; - /* TCM */ tcm: tcm@10000000 { compatible = "zephyr,memory-region"; @@ -43,6 +49,22 @@ }; soc { + compatible = "ambiq,apollo4p-blue", "ambiq,apollo4x", "simple-bus"; + + flash: flash-controller@18000 { + compatible = "ambiq,flash-controller"; + reg = <0x00018000 0x1e8000>; + + #address-cells = <1>; + #size-cells = <1>; + + /* MRAM region */ + flash0: flash@18000 { + compatible = "soc-nv-flash"; + reg = <0x00018000 0x1e8000>; + }; + }; + pwrcfg: pwrcfg@40021000 { compatible = "ambiq,pwrctrl"; reg = <0x40021000 0x400>; @@ -138,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 { @@ -207,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 f9dc33e458ae263..67d99418fd22850 100644 --- a/dts/arm/atmel/sam3x.dtsi +++ b/dts/arm/atmel/sam3x.dtsi @@ -37,6 +37,13 @@ status = "okay"; }; + supc: supc@400e1a10 { + compatible = "atmel,sam-supc"; + reg = <0x400e1a10 0x20>; + #wakeup-source-id-cells = <1>; + status = "okay"; + }; + sram0: memory@20070000 { compatible = "mmio-sram"; reg = <0x20070000 0x18000>; @@ -46,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>; @@ -246,6 +254,15 @@ clocks = <&pmc PMC_TYPE_PERIPHERAL 1>; user-nrst; }; + + rtc: rtc@400e1a60 { + compatible = "atmel,sam-rtc"; + reg = <0x400e1a60 0x100>; + interrupts = <2 0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 2>; + alarms-count = <1>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/atmel/sam4e.dtsi b/dts/arm/atmel/sam4e.dtsi index ede65163ed04bcc..c90fed140b3f61b 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>; }; }; }; @@ -47,6 +46,13 @@ status = "okay"; }; + supc: supc@400e1810 { + compatible = "atmel,sam-supc"; + reg = <0x400e1810 0x20>; + #wakeup-source-id-cells = <1>; + status = "okay"; + }; + sram0: memory@20000000 { compatible = "mmio-sram"; }; @@ -72,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>; }; }; @@ -171,6 +179,7 @@ mdio: mdio@40034000 { compatible = "atmel,sam-mdio"; reg = <0x40034000 0x4000>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 44>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -303,6 +312,15 @@ clocks = <&pmc PMC_TYPE_PERIPHERAL 16>; status = "disabled"; }; + + rtc: rtc@400e1860 { + compatible = "atmel,sam-rtc"; + reg = <0x400e1860 0x100>; + interrupts = <2 0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 2>; + alarms-count = <1>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/atmel/sam4e16c.dtsi b/dts/arm/atmel/sam4e16c.dtsi index c3c0226e9d47823..ffa4b475c9177ac 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 c3c0226e9d47823..ffa4b475c9177ac 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 1af988dfce51c60..d47729b0f627dd1 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 1af988dfce51c60..d47729b0f627dd1 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 1f11478044fac96..7f19f8d21a482a7 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 bbbc05e8f7facfa..64828f3a7d50cd9 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>; }; }; }; @@ -49,6 +48,13 @@ status = "okay"; }; + supc: supc@400e1410 { + compatible = "atmel,sam-supc"; + reg = <0x400e1410 0x20>; + #wakeup-source-id-cells = <1>; + status = "okay"; + }; + sram0: memory@20100000 { compatible = "mmio-sram"; }; @@ -56,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>; }; }; @@ -240,6 +247,15 @@ clocks = <&pmc PMC_TYPE_PERIPHERAL 10>; status = "disabled"; }; + + rtc: rtc@400e1460 { + compatible = "atmel,sam-rtc"; + reg = <0x400e1460 0x100>; + interrupts = <2 0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 2>; + alarms-count = <1>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/atmel/sam4s16b.dtsi b/dts/arm/atmel/sam4s16b.dtsi index 4ab4d64c4a64479..f671f6fccc48ec0 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 4ab4d64c4a64479..f671f6fccc48ec0 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 f85ca2b2a617b21..b57ddb0cec65a6e 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 f85ca2b2a617b21..b57ddb0cec65a6e 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 f85ca2b2a617b21..b57ddb0cec65a6e 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 36d0ba7729b8dac..1ea079b054cafc0 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 7fbe9118f18fd5f..959c4d591e203a5 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 36d0ba7729b8dac..1ea079b054cafc0 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 f047b4a073bb886..2e00a78b4d6dae5 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 f047b4a073bb886..2e00a78b4d6dae5 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 ae96e4b27ada68e..789e482b0f6662f 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 d3cdfbda77729e5..72b28386a4b4b76 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 5af30c4680bfafa..b64abc5de4554cf 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 1d11fa32c9736e7..c4b1762e5b3581e 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 02fae555c2571f7..878ad822d682a81 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>; }; }; }; @@ -57,6 +56,13 @@ status = "okay"; }; + supc: supc@400e1810 { + compatible = "atmel,sam-supc"; + reg = <0x400e1810 0x20>; + #wakeup-source-id-cells = <1>; + status = "okay"; + }; + eefc: flash-controller@400e0c00 { compatible = "atmel,sam-flash-controller"; reg = <0x400e0c00 0x200>; @@ -65,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 { @@ -333,6 +338,7 @@ mdio: mdio@40050000 { compatible = "atmel,sam-mdio"; reg = <0x40050000 0x4000>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 39>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -415,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>; @@ -428,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>; @@ -443,6 +449,15 @@ clocks = <&pmc PMC_TYPE_PERIPHERAL 1>; user-nrst; }; + + rtc: rtc@400e1860 { + compatible = "atmel,sam-rtc"; + reg = <0x400e1860 0x100>; + interrupts = <2 0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 2>; + alarms-count = <1>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/atmel/same70q19.dtsi b/dts/arm/atmel/same70q19.dtsi index e8f3329bd2e21a6..abf0e5b67e5a514 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 0815fdc2dfae356..cc97dc64458b385 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 494fdc0d0262af7..4138d6ca0667f01 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 8f13909f9117330..d6fe0fa4a2e74e3 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 b124cb7cb404b40..46c1d7a875693ae 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 966c5b27ca3fd1a..520c93981517730 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 e251f68feb671e1..10228d242a2390c 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 c26a88299ad8f7e..d425e524aa854dd 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 bd72c69835a431a..d59fa5be590638e 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 c7acf1b2530b57d..c55ac8b12843704 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 e413018022c6275..03df61fcdaef800 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 2c0e7e3b25d1470..85e38616e8b06df 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/cypress/psoc6.dtsi b/dts/arm/cypress/psoc6.dtsi index 4fc63f4b46f67c4..a6ab61e9949dde0 100644 --- a/dts/arm/cypress/psoc6.dtsi +++ b/dts/arm/cypress/psoc6.dtsi @@ -71,164 +71,164 @@ #address-cells = <1>; #size-cells = <1>; ranges = <0x40310000 0x40310000 0x2024>; + }; - hsiom: hsiom@40310000 { - compatible = "cypress,psoc6-hsiom"; - reg = <0x40310000 0x2024>; - interrupts = <15 1>, <16 1>; - status = "disabled"; - }; + hsiom: hsiom@40310000 { + compatible = "cypress,psoc6-hsiom"; + reg = <0x40310000 0x2024>; + interrupts = <15 1>, <16 1>; + status = "disabled"; + }; - gpio_prt0: gpio@40320000 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320000 0x80>; - interrupts = <0 1>; - gpio-controller; - ngpios = <6>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; - gpio_prt1: gpio@40320080 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320080 0x80>; - interrupts = <1 1>; - gpio-controller; - ngpios = <6>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; - gpio_prt2: gpio@40320100 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320100 0x80>; - interrupts = <2 1>; - gpio-controller; - ngpios = <8>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; - gpio_prt3: gpio@40320180 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320180 0x80>; - interrupts = <3 1>; - gpio-controller; - ngpios = <6>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; - gpio_prt4: gpio@40320200 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320200 0x80>; - interrupts = <4 1>; - gpio-controller; - ngpios = <4>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; - gpio_prt5: gpio@40320280 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320280 0x80>; - interrupts = <5 1>; - gpio-controller; - ngpios = <8>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; - gpio_prt6: gpio@40320300 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320300 0x80>; - interrupts = <6 1>; - gpio-controller; - ngpios = <8>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; - gpio_prt7: gpio@40320380 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320380 0x80>; - interrupts = <7 1>; - gpio-controller; - ngpios = <8>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; - gpio_prt8: gpio@40320400 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320400 0x80>; - interrupts = <8 1>; - gpio-controller; - ngpios = <8>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; - gpio_prt9: gpio@40320480 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320480 0x80>; - interrupts = <9 1>; - gpio-controller; - ngpios = <8>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; - gpio_prt10: gpio@40320500 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320500 0x80>; - interrupts = <10 1>; - gpio-controller; - ngpios = <8>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; - gpio_prt11: gpio@40320580 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320580 0x80>; - interrupts = <11 1>; - gpio-controller; - ngpios = <8>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; - gpio_prt12: gpio@40320600 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320600 0x80>; - interrupts = <12 1>; - gpio-controller; - ngpios = <8>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; - gpio_prt13: gpio@40320680 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320680 0x80>; - interrupts = <13 1>; - gpio-controller; - ngpios = <8>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; - gpio_prt14: gpio@40320700 { - compatible = "cypress,psoc6-gpio"; - reg = <0x40320700 0x80>; - interrupts = <14 1>; - gpio-controller; - ngpios = <2>; - #gpio-cells = <2>; - #cypress,pin-cells = <2>; - status = "disabled"; - }; + gpio_prt0: gpio@40320000 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320000 0x80>; + interrupts = <0 1>; + gpio-controller; + ngpios = <6>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; + }; + gpio_prt1: gpio@40320080 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320080 0x80>; + interrupts = <1 1>; + gpio-controller; + ngpios = <6>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; + }; + gpio_prt2: gpio@40320100 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320100 0x80>; + interrupts = <2 1>; + gpio-controller; + ngpios = <8>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; + }; + gpio_prt3: gpio@40320180 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320180 0x80>; + interrupts = <3 1>; + gpio-controller; + ngpios = <6>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; + }; + gpio_prt4: gpio@40320200 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320200 0x80>; + interrupts = <4 1>; + gpio-controller; + ngpios = <4>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; + }; + gpio_prt5: gpio@40320280 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320280 0x80>; + interrupts = <5 1>; + gpio-controller; + ngpios = <8>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; + }; + gpio_prt6: gpio@40320300 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320300 0x80>; + interrupts = <6 1>; + gpio-controller; + ngpios = <8>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; + }; + gpio_prt7: gpio@40320380 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320380 0x80>; + interrupts = <7 1>; + gpio-controller; + ngpios = <8>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; + }; + gpio_prt8: gpio@40320400 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320400 0x80>; + interrupts = <8 1>; + gpio-controller; + ngpios = <8>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; + }; + gpio_prt9: gpio@40320480 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320480 0x80>; + interrupts = <9 1>; + gpio-controller; + ngpios = <8>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; + }; + gpio_prt10: gpio@40320500 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320500 0x80>; + interrupts = <10 1>; + gpio-controller; + ngpios = <8>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; + }; + gpio_prt11: gpio@40320580 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320580 0x80>; + interrupts = <11 1>; + gpio-controller; + ngpios = <8>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; + }; + gpio_prt12: gpio@40320600 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320600 0x80>; + interrupts = <12 1>; + gpio-controller; + ngpios = <8>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; + }; + gpio_prt13: gpio@40320680 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320680 0x80>; + interrupts = <13 1>; + gpio-controller; + ngpios = <8>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; + }; + gpio_prt14: gpio@40320700 { + compatible = "cypress,psoc6-gpio"; + reg = <0x40320700 0x80>; + interrupts = <14 1>; + gpio-controller; + ngpios = <2>; + #gpio-cells = <2>; + #cypress,pin-cells = <2>; + status = "disabled"; }; spi0: spi@40610000 { 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 674016f5e98f338..98fad6847f0b4c2 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 3a3f1bfed491ba8..af54b98f71635e5 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 2229355de4308b3..7f4031340765f99 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 37665e54445d0bb..c897ad60f8f4042 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 e073dd8ff4e3776..a02dd5df866b02b 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 43dbe4b3a5de2ca..e9c5af1ab9fe503 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 ae878fac1ff092c..5304ebae045c8d2 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 fda4a6359930103..054a3848c05ee79 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 e4e5741730757e1..0b6ac33245c563e 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 e93f69691a8eb81..bfe5145e9fb741a 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 000000000000000..0d1b1fdef3f9030 --- /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 ef9a82f8b445843..0197c8c4d9e9d72 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 dc4d74b1a288446..bfc8d85c01bed70 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 eb3549aa29b28bf..48a8deff114a99a 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 66e3b3a0af61cb5..7bef0eb8d97068c 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 e85fddb56090474..d48f6d75830ac1d 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 c6d5b0e6b0b4c6b..b1aea0ba5a595d9 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 98c0c6e4e8df94f..c1f76b49382bdf7 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 000000000000000..1900a34abaddcd2 --- /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 dcd74a8b35ad299..9f074ec7529376a 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 5a0d2aa85abdaad..f2e35e981e4272c 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 8539b3928a4914e..d8c2f80ee656373 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 dd31946ff76b94d..000000000000000 --- 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 a77a11763e4a403..000000000000000 --- 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/psoc6/psoc6_01/psoc6_01.dtsi b/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi index 0a97178cfad2d4d..56957dddab0315c 100644 --- a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi +++ b/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi @@ -55,150 +55,151 @@ reg = <0x40310000 0x20000>; #address-cells = <1>; #size-cells = <0>; + }; - hsiom: hsiom@40310000 { - compatible = "infineon,cat1-hsiom"; - reg = <0x40310000 0x4000>; - interrupts = <15 6>, <16 6>; - status = "disabled"; - }; + hsiom: hsiom@40310000 { + compatible = "infineon,cat1-hsiom"; + reg = <0x40310000 0x4000>; + interrupts = <15 6>, <16 6>; + status = "disabled"; + }; - gpio_prt0: gpio@40320000 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320000 0x80>; - interrupts = <0 6>; - gpio-controller; - ngpios = <6>; - status = "disabled"; - #gpio-cells = <2>; - }; - gpio_prt1: gpio@40320080 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320080 0x80>; - interrupts = <1 6>; - gpio-controller; - ngpios = <6>; - status = "disabled"; - #gpio-cells = <2>; - }; - gpio_prt2: gpio@40320100 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320100 0x80>; - interrupts = <2 6>; - gpio-controller; - ngpios = <8>; - status = "disabled"; - #gpio-cells = <2>; - }; - gpio_prt3: gpio@40320180 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320180 0x80>; - interrupts = <3 6>; - gpio-controller; - ngpios = <6>; - status = "disabled"; - #gpio-cells = <2>; - }; - gpio_prt4: gpio@40320200 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320200 0x80>; - interrupts = <4 6>; - gpio-controller; - ngpios = <2>; - status = "disabled"; - #gpio-cells = <2>; - }; - gpio_prt5: gpio@40320280 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320280 0x80>; - interrupts = <5 6>; - gpio-controller; - ngpios = <8>; - status = "disabled"; - #gpio-cells = <2>; - }; - gpio_prt6: gpio@40320300 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320300 0x80>; - interrupts = <6 6>; - gpio-controller; - ngpios = <8>; - status = "disabled"; - #gpio-cells = <2>; - }; - gpio_prt7: gpio@40320380 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320380 0x80>; - interrupts = <7 6>; - gpio-controller; - ngpios = <8>; - status = "disabled"; - #gpio-cells = <2>; - }; - gpio_prt8: gpio@40320400 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320400 0x80>; - interrupts = <8 6>; - gpio-controller; - ngpios = <8>; - status = "disabled"; - #gpio-cells = <2>; - }; - gpio_prt9: gpio@40320480 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320480 0x80>; - interrupts = <9 6>; - gpio-controller; - ngpios = <8>; - status = "disabled"; - #gpio-cells = <2>; - }; - gpio_prt10: gpio@40320500 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320500 0x80>; - interrupts = <10 6>; - gpio-controller; - ngpios = <8>; - status = "disabled"; - #gpio-cells = <2>; - }; - gpio_prt11: gpio@40320580 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320580 0x80>; - interrupts = <11 6>; - gpio-controller; - ngpios = <8>; - status = "disabled"; - #gpio-cells = <2>; - }; - gpio_prt12: gpio@40320600 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320600 0x80>; - interrupts = <12 6>; - gpio-controller; - ngpios = <8>; - status = "disabled"; - #gpio-cells = <2>; - }; - gpio_prt13: gpio@40320680 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320680 0x80>; - interrupts = <13 6>; - gpio-controller; - ngpios = <8>; - status = "disabled"; - #gpio-cells = <2>; - }; - gpio_prt14: gpio@40320700 { - compatible = "infineon,cat1-gpio"; - reg = <0x40320700 0x80>; - interrupts = <14 6>; - gpio-controller; - ngpios = <2>; - status = "disabled"; - #gpio-cells = <2>; - }; + gpio_prt0: gpio@40320000 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320000 0x80>; + interrupts = <0 6>; + gpio-controller; + ngpios = <6>; + status = "disabled"; + #gpio-cells = <2>; + }; + gpio_prt1: gpio@40320080 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320080 0x80>; + interrupts = <1 6>; + gpio-controller; + ngpios = <6>; + status = "disabled"; + #gpio-cells = <2>; + }; + gpio_prt2: gpio@40320100 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320100 0x80>; + interrupts = <2 6>; + gpio-controller; + ngpios = <8>; + status = "disabled"; + #gpio-cells = <2>; + }; + gpio_prt3: gpio@40320180 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320180 0x80>; + interrupts = <3 6>; + gpio-controller; + ngpios = <6>; + status = "disabled"; + #gpio-cells = <2>; + }; + gpio_prt4: gpio@40320200 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320200 0x80>; + interrupts = <4 6>; + gpio-controller; + ngpios = <2>; + status = "disabled"; + #gpio-cells = <2>; + }; + gpio_prt5: gpio@40320280 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320280 0x80>; + interrupts = <5 6>; + gpio-controller; + ngpios = <8>; + status = "disabled"; + #gpio-cells = <2>; + }; + gpio_prt6: gpio@40320300 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320300 0x80>; + interrupts = <6 6>; + gpio-controller; + ngpios = <8>; + status = "disabled"; + #gpio-cells = <2>; + }; + gpio_prt7: gpio@40320380 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320380 0x80>; + interrupts = <7 6>; + gpio-controller; + ngpios = <8>; + status = "disabled"; + #gpio-cells = <2>; + }; + gpio_prt8: gpio@40320400 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320400 0x80>; + interrupts = <8 6>; + gpio-controller; + ngpios = <8>; + status = "disabled"; + #gpio-cells = <2>; + }; + gpio_prt9: gpio@40320480 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320480 0x80>; + interrupts = <9 6>; + gpio-controller; + ngpios = <8>; + status = "disabled"; + #gpio-cells = <2>; + }; + gpio_prt10: gpio@40320500 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320500 0x80>; + interrupts = <10 6>; + gpio-controller; + ngpios = <8>; + status = "disabled"; + #gpio-cells = <2>; + }; + gpio_prt11: gpio@40320580 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320580 0x80>; + interrupts = <11 6>; + gpio-controller; + ngpios = <8>; + status = "disabled"; + #gpio-cells = <2>; + }; + gpio_prt12: gpio@40320600 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320600 0x80>; + interrupts = <12 6>; + gpio-controller; + ngpios = <8>; + status = "disabled"; + #gpio-cells = <2>; + }; + gpio_prt13: gpio@40320680 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320680 0x80>; + interrupts = <13 6>; + gpio-controller; + ngpios = <8>; + status = "disabled"; + #gpio-cells = <2>; + }; + gpio_prt14: gpio@40320700 { + compatible = "infineon,cat1-gpio"; + reg = <0x40320700 0x80>; + interrupts = <14 6>; + gpio-controller; + ngpios = <2>; + status = "disabled"; + #gpio-cells = <2>; }; + uid: device_uid@16000600 { compatible = "infineon,cat1-uid"; reg = <0x16000600 0xb>; @@ -536,5 +537,12 @@ resolution = <16>; status = "disabled"; }; + + sdhc0: sdhc@40460000 { + compatible = "infineon,cat1-sdhc-sdio"; + reg = <0x40460000 0x2000>; + interrupts = <164 6>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi b/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi index a4109291dfd2894..c61ba9e0ca42323 100644 --- a/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi +++ b/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi @@ -541,5 +541,12 @@ resolution = <16>; status = "disabled"; }; + + sdhc0: sdhc@40460000 { + compatible = "infineon,cat1-sdhc-sdio"; + reg = <0x40460000 0x2000>; + interrupts = <164 6>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi b/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi index 8e8ada040d2c84e..14aefdc5ada5bc0 100644 --- a/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi +++ b/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi @@ -241,6 +241,12 @@ interrupts = <18 6>; status = "disabled"; }; + sdhc0: sdhc@40460000 { + compatible = "infineon,cat1-sdhc-sdio"; + reg = <0x40460000 0x2000>; + interrupts = <164 6>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi b/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi index 73282624e3f9406..d44b0583f70b8d1 100644 --- a/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi +++ b/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi @@ -247,6 +247,12 @@ interrupts = <18 6>; status = "disabled"; }; + sdhc0: sdhc@40460000 { + compatible = "infineon,cat1-sdhc-sdio"; + reg = <0x40460000 0x2000>; + interrupts = <164 6>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi index fd05d415d3a765b..4506e0c995fc9c3 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 8a84230511d8e0e..d368e397ea3c373 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 75988d493e78eea..e6bab488049d05e 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 bd5250050e97c44..ad8e1ea641357f1 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 54a5744be152ae3..cab68fbff007851 100644 --- a/dts/arm/infineon/xmc4xxx.dtsi +++ b/dts/arm/infineon/xmc4xxx.dtsi @@ -229,6 +229,60 @@ #pwm-cells = <3>; status = "disabled"; }; + + wdt0: watchdog@50008000 { + compatible = "infineon,xmc4xxx-watchdog"; + reg = <0x50008000 0x4000>; + 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 e2e852a4791117f..7e1f37267d5cecb 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/microchip/mec1727nsz.dtsi b/dts/arm/microchip/mec1727nsz.dtsi index 565e5f9ff45abf4..a7484a335bb200a 100644 --- a/dts/arm/microchip/mec1727nsz.dtsi +++ b/dts/arm/microchip/mec1727nsz.dtsi @@ -11,14 +11,55 @@ #include #include -#include "mec172xnsz.dtsi" #include "mec172x/mec172x-vw-routing.dtsi" -#include "mec172x/mec172xnsz-pinctrl.dtsi" + +#include +#include / { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m4"; + reg = <0>; + cpu-power-states = <&idle &suspend_to_ram>; + }; + + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1000000>; + }; + + suspend_to_ram: suspend_to_ram { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + min-residency-us = <2000000>; + }; + }; + }; + + flash0: flash@c0000 { + reg = <0x000C0000 0x58000>; + }; + flash1: flash@60000000 { reg = <0x60000000 0x80000>; }; + + sram0: memory@118000 { + compatible = "mmio-sram"; + reg = <0x00118000 0x10000>; + }; + + soc { + #include "mec172x_common.dtsi" + }; + }; &spi0 { @@ -44,6 +85,16 @@ }; }; +&nvic { + arm,num-irq-priority-bits = <3>; +}; + +&systick { + status = "disabled"; +}; + +#include "mec172x/mec172xnsz-pinctrl.dtsi" + &gpspi_wp_n_gpio076 { output-high; }; diff --git a/dts/arm/microchip/mec172x/mec172xnlj-pinctrl.dtsi b/dts/arm/microchip/mec172x/mec172xnlj-pinctrl.dtsi index ac5b43a67a39b2b..47502d289c6bf25 100644 --- a/dts/arm/microchip/mec172x/mec172xnlj-pinctrl.dtsi +++ b/dts/arm/microchip/mec172x/mec172xnlj-pinctrl.dtsi @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include "mec172xnsz-pinctrl.dtsi" &pinctrl { diff --git a/dts/arm/microchip/mec172x_common.dtsi b/dts/arm/microchip/mec172x_common.dtsi new file mode 100644 index 000000000000000..03a6a00fb4f9d2b --- /dev/null +++ b/dts/arm/microchip/mec172x_common.dtsi @@ -0,0 +1,1001 @@ +/* + * Copyright (c) 2021 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +ecs: ecs@4000fc00 { + reg = <0x4000fc00 0x200>; +}; +pcr: pcr@40080100 { + compatible = "microchip,xec-pcr"; + reg = <0x40080100 0x100 0x4000a400 0x100>; + reg-names = "pcrr", "vbatr"; + interrupts = <174 0>; + core-clock-div = <1>; + /* MEC172x allows sources to be different */ + pll-32k-src = ; + periph-32k-src = ; + clk32kmon-period-min = <1435>; + clk32kmon-period-max = <1495>; + clk32kmon-duty-cycle-var-max = <132>; + clk32kmon-valid-min = <4>; + xtal-enable-delay-ms = <300>; + pll-lock-timeout-ms = <30>; + /* pin configured only if one of the sources is set to PIN */ + pinctrl-0 = <&clk_32khz_in_gpio165>; + pinctrl-names = "default"; + #clock-cells = <3>; +}; +ecia: ecia@4000e000 { + compatible = "microchip,xec-ecia"; + reg = <0x4000e000 0x400>; + direct-capable-girqs = <13 14 15 16 17 18 19 20 21 23>; + clocks = <&pcr 1 0 MCHP_XEC_PCR_CLK_PERIPH>; + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0x0 0x4000e000 0x400>; + + girq8: girq8@0 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x0 0x14>; + interrupts = <0 0>; + girq-id = <0>; + sources = <0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 21 22 24 25 + 26 27 28 29>; + status = "disabled"; + }; + girq9: girq9@14 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x14 0x14>; + interrupts = <1 0>; + girq-id = <1>; + sources = <0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29>; + status = "disabled"; + }; + girq10: girq10@28 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x28 0x14>; + interrupts = <2 0>; + girq-id = <2>; + sources = <0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29 30>; + status = "disabled"; + }; + girq11: girq11@3c { + compatible = "microchip,xec-ecia-girq"; + reg = <0x3c 0x14>; + interrupts = <3 0>; + girq-id = <3>; + sources = <0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29 30>; + status = "disabled"; + }; + girq12: girq12@50 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x50 0x14>; + interrupts = <4 0>; + girq-id = <4>; + sources = <0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29 30>; + status = "disabled"; + }; + girq13: girq13@64 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x64 0x14>; + interrupts = <5 0>; + girq-id = <5>; + sources = <0 1 2 3 4>; + status = "disabled"; + }; + girq14: girq14@78 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x78 0x14>; + interrupts = <6 0>; + girq-id = <6>; + sources = <0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15>; + status = "disabled"; + }; + girq15: girq15@8c { + compatible = "microchip,xec-ecia-girq"; + reg = <0x8c 0x14>; + interrupts = <7 0>; + girq-id = <7>; + sources = <0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 22>; + status = "disabled"; + }; + girq16: girq16@a0 { + compatible = "microchip,xec-ecia-girq"; + reg = <0xa0 0x14>; + interrupts = <8 0>; + girq-id = <8>; + sources = <0 2 3>; + status = "disabled"; + }; + girq17: girq17@b4 { + compatible = "microchip,xec-ecia-girq"; + reg = <0xb4 0x14>; + interrupts = <9 0>; + girq-id = <9>; + sources = <0 1 2 3 4 8 9 10 11 12 13 14 15 + 16 17 20 21 22 23>; + status = "disabled"; + }; + girq18: girq18@c8 { + compatible = "microchip,xec-ecia-girq"; + reg = <0xc8 0x14>; + interrupts = <10 0>; + girq-id = <10>; + sources = <0 1 2 3 4 5 6 7 + 10 20 21 22 23 + 24 25 26 27 28>; + status = "disabled"; + }; + girq19: girq19@dc { + compatible = "microchip,xec-ecia-girq"; + reg = <0xdc 0x14>; + interrupts = <11 0>; + girq-id = <11>; + sources = <0 1 2 3 4 5 6 7 8 9 10>; + status = "disabled"; + }; + girq20: girq20@f0 { + compatible = "microchip,xec-ecia-girq"; + reg = <0xf0 0x14>; + interrupts = <12 0>; + girq-id = <12>; + sources = <3 9>; + status = "disabled"; + }; + girq21: girq21@104 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x104 0x14>; + interrupts = <13 0>; + girq-id = <13>; + sources = <2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 18 19 25 26>; + status = "disabled"; + }; + girq22: girq22@118 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x118 0x14>; + interrupts = <255 0>; + girq-id = <14>; + sources = <0 1 2 3 4 5 9 15>; + status = "disabled"; + }; + girq23: girq23@12c { + compatible = "microchip,xec-ecia-girq"; + reg = <0x12c 0x14>; + interrupts = <14 0>; + girq-id = <15>; + sources = <0 1 2 3 4 5 6 7 8 9 10 16 17>; + status = "disabled"; + }; + girq24: girq24@140 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x140 0x14>; + interrupts = <15 0>; + girq-id = <16>; + sources = <0 1 2 3 4 5 6 7 8 9 10 11 + 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27>; + status = "disabled"; + }; + girq25: girq25@154 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x154 0x14>; + interrupts = <16 0>; + girq-id = <17>; + sources = <0 1 2 3 4 5 6 7 8 9 10 11 + 12 13 14 15>; + status = "disabled"; + }; + girq26: girq26@168 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x168 0x14>; + interrupts = <17 0>; + girq-id = <18>; + sources = <0 1 2 3 4 5 6 12 13>; + status = "disabled"; + }; +}; +pinctrl: pin-controller@40081000 { + compatible = "microchip,xec-pinctrl"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x40081000 0x1000>; + + gpio_000_036: gpio@40081000 { + compatible = "microchip,xec-gpio-v2"; + reg = < 0x40081000 0x80 0x40081300 0x04 + 0x40081380 0x04 0x400813fc 0x04>; + interrupts = <3 2>; + gpio-controller; + port-id = <0>; + girq-id = <11>; + #gpio-cells=<2>; + }; + gpio_040_076: gpio@40081080 { + compatible = "microchip,xec-gpio-v2"; + reg = < 0x40081080 0x80 0x40081304 0x04 + 0x40081384 0x04 0x400813f8 0x4>; + interrupts = <2 2>; + gpio-controller; + port-id = <1>; + girq-id = <10>; + #gpio-cells=<2>; + }; + gpio_100_136: gpio@40081100 { + compatible = "microchip,xec-gpio-v2"; + reg = < 0x40081100 0x80 0x40081308 0x04 + 0x40081388 0x04 0x400813f4 0x04>; + gpio-controller; + interrupts = <1 2>; + port-id = <2>; + girq-id = <9>; + #gpio-cells=<2>; + }; + gpio_140_176: gpio@40081180 { + compatible = "microchip,xec-gpio-v2"; + reg = < 0x40081180 0x80 0x4008130c 0x04 + 0x4008138c 0x04 0x400813f0 0x04>; + gpio-controller; + interrupts = <0 2>; + port-id = <3>; + girq-id = <8>; + #gpio-cells=<2>; + }; + gpio_200_236: gpio@40081200 { + compatible = "microchip,xec-gpio-v2"; + reg = < 0x40081200 0x80 0x40081310 0x04 + 0x40081390 0x04 0x400813ec 0x04>; + gpio-controller; + interrupts = <4 2>; + port-id = <4>; + girq-id = <12>; + #gpio-cells=<2>; + }; + gpio_240_276: gpio@40081280 { + compatible = "microchip,xec-gpio-v2"; + reg = < 0x40081280 0x80 0x40081314 0x04 + 0x40081394 0x04 0x400813e8 0x04>; + gpio-controller; + interrupts = <17 2>; + port-id = <5>; + girq-id = <26>; + #gpio-cells=<2>; + }; +}; +wdog: watchdog@40000400 { + compatible = "microchip,xec-watchdog"; + reg = <0x40000400 0x400>; + interrupts = <171 0>; + girqs = <21 2>; + pcrs = <1 9>; +}; +rtimer: timer@40007400 { + compatible = "microchip,xec-rtos-timer"; + reg = <0x40007400 0x10>; + interrupts = <111 0>; + girqs = <23 10>; +}; +timer0: timer@40000c00 { + compatible = "microchip,xec-timer"; + clock-frequency = <48000000>; + reg = <0x40000c00 0x20>; + interrupts = <136 0>; + girqs = <23 0>; + pcrs = <1 30>; + max-value = <0xFFFF>; + prescaler = <0>; + status = "disabled"; +}; +timer1: timer@40000c20 { + compatible = "microchip,xec-timer"; + clock-frequency = <48000000>; + reg = <0x40000c20 0x20>; + interrupts = <137 0>; + girqs = <23 1>; + pcrs = <1 31>; + max-value = <0xFFFF>; + prescaler = <0>; + status = "disabled"; +}; +timer2: timer@40000c40 { + compatible = "microchip,xec-timer"; + clock-frequency = <48000000>; + reg = <0x40000c40 0x20>; + interrupts = <138 0>; + girqs = <23 2>; + pcrs = <3 21>; + max-value = <0xFFFF>; + prescaler = <0>; + status = "disabled"; +}; +timer3: timer@40000c60 { + compatible = "microchip,xec-timer"; + clock-frequency = <48000000>; + reg = <0x40000c60 0x20>; + interrupts = <139 0>; + girqs = <23 3>; + pcrs = <3 22>; + max-value = <0xFFFF>; + prescaler = <0>; + status = "disabled"; +}; +/* + * NOTE: When RTOS timer used as kernel timer, timer4 used + * to provide high speed busy wait counter. Keep disabled to + * prevent counter driver from claiming it. + */ +timer4: timer@40000c80 { + compatible = "microchip,xec-timer"; + clock-frequency = <48000000>; + reg = <0x40000c80 0x20>; + interrupts = <140 0>; + girqs = <23 4>; + pcrs = <3 23>; + max-value = <0xFFFFFFFF>; + prescaler = <0>; + status = "disabled"; +}; +timer5: timer@40000ca0 { + compatible = "microchip,xec-timer"; + clock-frequency = <48000000>; + reg = <0x40000ca0 0x20>; + interrupts = <141 0>; + girqs = <23 5>; + pcrs = <3 24>; + max-value = <0xFFFFFFFF>; + prescaler = <0>; + status = "disabled"; +}; +cntr0: timer@40000d00 { + reg = <0x40000d00 0x20>; + interrupts = <142 0>; + girqs = <23 6>; + pcrs = <4 2>; + status = "disabled"; +}; +cntr1: timer@40000d20 { + reg = <0x40000d20 0x20>; + interrupts = <143 0>; + girqs = <23 7>; + pcrs = <4 3>; + status = "disabled"; +}; +cntr2: timer@40000d40 { + reg = <0x40000d40 0x20>; + interrupts = <144 0>; + girqs = <23 8>; + pcrs = <4 3>; + status = "disabled"; +}; +cntr3: timer@40000d60 { + reg = <0x40000d60 0x20>; + interrupts = <145 0>; + girqs = <23 9>; + pcrs = <4 4>; + status = "disabled"; +}; +cctmr0: timer@40001000 { + reg = <0x40001000 0x40>; + interrupts = <146 0>, <147 0>, <148 0>, <149 0>, + <150 0>, <151 0>, <152 0>, <153 0>, + <154 0>; + girqs = <18 20>, <18 21>, <18 22>, <18 23>, <18 24>, + <18 25>, <18 26>, <18 27>, <18 28>; + pcrs = <3 30>; + status = "disabled"; +}; +hibtimer0: timer@40009800 { + reg = <0x40009800 0x20>; + interrupts = <112 0>; + girqs = <23 16>; +}; +hibtimer1: timer@40009820 { + reg = <0x40009820 0x20>; + interrupts = <113 0>; + girqs = <23 17>; +}; +weektmr0: timer@4000ac80 { + reg = <0x4000ac80 0x80>; + interrupts = <114 0>, <115 0>, <116 0>, + <117 0>, <118 0>; + girqs = <21 3>, <21 4>, <21 5>, <21 6>, <21 7>; + status = "disabled"; +}; +bbram: bb-ram@4000a800 { + compatible = "microchip,xec-bbram"; + reg = <0x4000a800 0x100>; + reg-names = "memory"; +}; +vci0: vci@4000ae00 { + reg = <0x4000ae00 0x40>; + interrupts = <121 0>, <122 0>, <123 0>, + <124 0>, <125 0>; + girqs = <21 10>, <21 11>, <21 12>, <21 13>, <21 14>; + status = "disabled"; +}; +dmac: dmac@40002400 { + compatible = "microchip,xec-dmac"; + reg = <0x40002400 0xc00>; + interrupts = <24 1>, <25 1>, <26 1>, <27 1>, + <28 1>, <29 1>, <30 1>, <31 1>, + <32 1>, <33 1>, <34 1>, <35 1>, + <36 1>, <37 1>, <38 1>, <39 1>; + girqs = < MCHP_XEC_ECIA(14, 0, 6, 24) + MCHP_XEC_ECIA(14, 1, 6, 25) + MCHP_XEC_ECIA(14, 2, 6, 26) + MCHP_XEC_ECIA(14, 3, 6, 27) + MCHP_XEC_ECIA(14, 4, 6, 28) + MCHP_XEC_ECIA(14, 5, 6, 29) + MCHP_XEC_ECIA(14, 6, 6, 30) + MCHP_XEC_ECIA(14, 7, 6, 31) + MCHP_XEC_ECIA(14, 8, 6, 32) + MCHP_XEC_ECIA(14, 9, 6, 33) + MCHP_XEC_ECIA(14, 10, 6, 34) + MCHP_XEC_ECIA(14, 11, 6, 35) + MCHP_XEC_ECIA(14, 12, 6, 36) + MCHP_XEC_ECIA(14, 13, 6, 37) + MCHP_XEC_ECIA(14, 14, 6, 38) + MCHP_XEC_ECIA(14, 15, 6, 39) >; + pcrs = <1 6>; + #dma-cells = <2>; + dma-channels = <16>; + dma-requests = <16>; + status = "disabled"; +}; +i2c_smb_0: i2c@40004000 { + compatible = "microchip,xec-i2c-v2"; + reg = <0x40004000 0x80>; + clock-frequency = ; + interrupts = <20 1>; + girqs = <13 0>; + pcrs = <1 10>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +}; +i2c_smb_1: i2c@40004400 { + compatible = "microchip,xec-i2c-v2"; + reg = <0x40004400 0x80>; + clock-frequency = ; + interrupts = <21 1>; + girqs = <13 1>; + pcrs = <3 13>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +}; +i2c_smb_2: i2c@40004800 { + compatible = "microchip,xec-i2c-v2"; + reg = <0x40004800 0x80>; + clock-frequency = ; + interrupts = <22 1>; + girqs = <13 2>; + pcrs = <3 14>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +}; +i2c_smb_3: i2c@40004c00 { + compatible = "microchip,xec-i2c-v2"; + reg = <0x40004C00 0x80>; + clock-frequency = ; + interrupts = <23 1>; + girqs = <13 3>; + pcrs = <3 15>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +}; +i2c_smb_4: i2c@40005000 { + compatible = "microchip,xec-i2c-v2"; + reg = <0x40005000 0x80>; + clock-frequency = ; + interrupts = <158 1>; + girqs = <13 4>; + pcrs = <3 20>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +}; +ps2_0: ps2@40009000 { + compatible = "microchip,xec-ps2"; + reg = <0x40009000 0x40>; + interrupts = <100 1>; + girqs = <18 10>, <21 18>; + pcrs = <3 5>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +}; +pwm0: pwm@40005800 { + compatible = "microchip,xec-pwm"; + reg = <0x40005800 0x20>; + pcrs = <1 4>; + status = "disabled"; + #pwm-cells = <3>; +}; +pwm1: pwm@40005810 { + compatible = "microchip,xec-pwm"; + reg = <0x40005810 0x20>; + pcrs = <1 20>; + status = "disabled"; + #pwm-cells = <3>; +}; +pwm2: pwm@40005820 { + compatible = "microchip,xec-pwm"; + reg = <0x40005820 0x20>; + pcrs = <1 21>; + status = "disabled"; + #pwm-cells = <3>; +}; +pwm3: pwm@40005830 { + compatible = "microchip,xec-pwm"; + reg = <0x40005830 0x20>; + pcrs = <1 22>; + status = "disabled"; + #pwm-cells = <3>; +}; +pwm4: pwm@40005840 { + compatible = "microchip,xec-pwm"; + reg = <0x40005840 0x20>; + pcrs = <1 23>; + status = "disabled"; + #pwm-cells = <3>; +}; +pwm5: pwm@40005850 { + compatible = "microchip,xec-pwm"; + reg = <0x40005850 0x20>; + pcrs = <1 24>; + status = "disabled"; + #pwm-cells = <3>; +}; +pwm6: pwm@40005860 { + compatible = "microchip,xec-pwm"; + reg = <0x40005860 0x20>; + pcrs = <1 25>; + status = "disabled"; + #pwm-cells = <3>; +}; +pwm7: pwm@40005870 { + compatible = "microchip,xec-pwm"; + reg = <0x40005870 0x20>; + pcrs = <1 26>; + status = "disabled"; + #pwm-cells = <3>; +}; +pwm8: pwm@40005880 { + compatible = "microchip,xec-pwm"; + reg = <0x40005880 0x20>; + pcrs = <1 27>; + status = "disabled"; + #pwm-cells = <3>; +}; +tach0: tach@40006000 { + compatible = "microchip,xec-tach"; + reg = <0x40006000 0x10>; + interrupts = <71 4>; + girqs = <17 1>; + pcrs = <1 2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +}; +tach1: tach@40006010 { + compatible = "microchip,xec-tach"; + reg = <0x40006010 0x10>; + interrupts = <72 4>; + girqs = <17 2>; + pcrs = <1 11>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +}; +tach2: tach@40006020 { + compatible = "microchip,xec-tach"; + reg = <0x40006020 0x10>; + interrupts = <73 4>; + girqs = <17 3>; + pcrs = <1 12>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +}; +tach3: tach@40006030 { + compatible = "microchip,xec-tach"; + reg = <0x40006030 0x10>; + interrupts = <159 4>; + girqs = <17 4>; + pcrs = <1 13>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +}; +rpmfan0: rpmfan@4000a000 { + reg = <0x4000a000 0x80>; + interrupts = <74 1>, <75 1>; + girqs = <17 20>, <17 21>; + pcrs = <3 12>; + status = "disabled"; +}; +rpmfan1: rpmfan@4000a080 { + reg = <0x4000a080 0x80>; + interrupts = <76 1>, <77 1>; + girqs = <17 22>, <17 23>; + pcrs = <4 7>; + status = "disabled"; +}; +adc0: adc@40007c00 { + compatible = "microchip,xec-adc"; + reg = <0x40007c00 0x90>; + interrupts = <78 0>, <79 0>; + girqs = <17 8>, <17 9>; + pcrs = <3 3>; + status = "disabled"; + #io-channel-cells = <1>; + clktime = <32>; +}; +kscan0: kscan@40009c00 { + compatible = "microchip,xec-kscan"; + reg = <0x40009c00 0x18>; + interrupts = <135 0>; + girqs = <21 25>; + pcrs = <3 11>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; +}; +peci0: peci@40006400 { + compatible = "microchip,xec-peci"; + reg = <0x40006400 0x80>; + interrupts = <70 4>; + girqs = <17 0>; + pcrs = <1 1>; + #address-cells = <1>; + #size-cells = <0>; +}; +spi0: spi@40070000 { + reg = <0x40070000 0x400>; + interrupts = <91 2>; + girqs = < MCHP_XEC_ECIA(18, 1, 10, 91) >; + clocks = <&pcr 4 8 MCHP_XEC_PCR_CLK_PERIPH>; + clock-frequency = <12000000>; + lines = <1>; + chip-select = <0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +}; +spi1: spi@40009400 { + reg = <0x40009400 0x80>; + interrupts = <92 2>, <93 2>; + girqs = <18 2>, <18 3>; + pcrs = <3 9>; + status = "disabled"; +}; +spi2: spi@40009480 { + reg = <0x40009480 0x80>; + interrupts = <94 2>, <95 2>; + girqs = <18 4>, <18 5>; + pcrs = <4 22>; + status = "disabled"; +}; +prochot0: prochot@40003400 { + reg = <0x40003400 0x20>; + interrupts = <87 0>; + girqs = <17 17>; + pcrs = <4 13>; + status = "disabled"; +}; +rcid0: rcid@40001400 { + reg = <0x40001400 0x80>; + interrupts = <80 0>; + girqs = <17 10>; + pcrs = <4 10>; + status = "disabled"; +}; +rcid1: rcid@40001480 { + reg = <0x40001480 0x80>; + interrupts = <81 0>; + girqs = <17 11>; + pcrs = <4 11>; + status = "disabled"; +}; +rcid2: rcid@40001500 { + reg = <0x40001500 0x80>; + interrupts = <82 0>; + girqs = <17 12>; + pcrs = <4 12>; + status = "disabled"; +}; +spip0: spip@40007000 { + reg = <0x40007000 0x100>; + interrupts = <90 0>; + girqs = <18 0>; + pcrs = <4 16>; + status = "disabled"; +}; +bbled0: bbled@4000b800 { + reg = <0x4000b800 0x100>; + interrupts = <83 0>; + girqs = <17 13>; + pcrs = <3 16>; + status = "disabled"; +}; +bbled1: bbled@4000b900 { + reg = <0x4000b900 0x100>; + interrupts = <84 0>; + girqs = <17 14>; + pcrs = <3 17>; + status = "disabled"; +}; +bbled2: bbled@4000ba00 { + reg = <0x4000ba00 0x100>; + interrupts = <85 0>; + girqs = <17 15>; + pcrs = <3 18>; + status = "disabled"; +}; +bbled3: bbled@4000bb00 { + reg = <0x4000bb00 0x100>; + interrupts = <86 0>; + girqs = <17 16>; + pcrs = <3 25>; + status = "disabled"; +}; +bclink0: bclink@4000cd00 { + reg = <0x4000cd00 0x20>; + interrupts = <96 0>, <97 0>; + girqs = <18 7>, <18 6>; + pcrs = <3 19>; + status = "disabled"; +}; +tfdp0: tfdp@40008c00 { + reg = <0x40008c00 0x10>; + pcrs = <1 7>; + status = "disabled"; +}; +glblcfg0: glblcfg@400fff00 { + reg = <0x400fff00 0x40>; + pcrs = <2 12>; + status = "disabled"; +}; +uart0: uart@400f2400 { + compatible = "microchip,xec-uart"; + reg = <0x400f2400 0x400>; + interrupts = <40 1>; + clock-frequency = <1843200>; + current-speed = <38400>; + girqs = <15 0>; + pcrs = <2 1>; + ldn = <9>; + status = "disabled"; +}; +uart1: uart@400f2800 { + compatible = "microchip,xec-uart"; + reg = <0x400f2800 0x400>; + interrupts = <41 1>; + clock-frequency = <1843200>; + current-speed = <38400>; + girqs = <15 1>; + pcrs = <2 2>; + ldn = <10>; + status = "disabled"; +}; +espi0: espi@400f3400 { + compatible = "microchip,xec-espi-v2"; + /* reg tuple contains one 32-bit address cell and one + * 32-bit length(size) cell. + */ + #address-cells = <1>; + #size-cells = <1>; + reg = < 0x400f3400 0x400 + 0x400f3800 0x400 + 0x400f9c00 0x400>; + reg-names = "io", "mem", "vw"; + interrupts = <103 3>, <104 3>, <105 3>, <106 3>, + <107 3>, <108 3>, <109 3>, <110 2>, + <156 3>; + interrupt-names = "pc", "bm1", "bm2", "ltr", "oob_up", + "oob_dn", "fc", "rst", "vw_chan_en"; + girqs = < MCHP_XEC_ECIA(19, 0, 11, 103) + MCHP_XEC_ECIA(19, 1, 11, 104) + MCHP_XEC_ECIA(19, 2, 11, 105) + MCHP_XEC_ECIA(19, 3, 11, 106) + MCHP_XEC_ECIA(19, 4, 11, 107) + MCHP_XEC_ECIA(19, 5, 11, 108) + MCHP_XEC_ECIA(19, 6, 11, 109) + MCHP_XEC_ECIA(19, 7, 11, 110) + MCHP_XEC_ECIA(19, 8, 11, 156) >; + pcrs = <2 19>; + status = "disabled"; + + espi_saf0: espi_saf@40008000 { + compatible = "microchip,xec-espi-saf-v2"; + reg = <0x40008000 0x400>, <0x40070000 0x400>, + <0x40071000 0x400>; + reg-names = "safbr", "safqspi", "safcomm"; + interrupts = <166 3>, <167 3>; + interrupt-names = "done", "err"; + girqs = < MCHP_XEC_ECIA(19, 9, 11, 166) >, + < MCHP_XEC_ECIA(19, 10, 11, 167) >; + pcrs = <2 27>; + status = "disabled"; + }; + + mbox0: mbox@400f0000 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f0000 0x200>; + interrupts = <60 3>; + girqs = < MCHP_XEC_ECIA(15, 20, 7, 60) >; + pcrs = <2 17>; + ldn = <0>; + status = "disabled"; + }; + kbc0: kbc@400f0400 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f0400 0x400>; + interrupts = <58 3>, <59 3>; + interrupt-names = "kbc_obe", "kbc_ibf"; + girqs = < MCHP_XEC_ECIA(15, 18, 7, 58) + MCHP_XEC_ECIA(15, 19, 7, 59) >; + ldn = <1>; + status = "disabled"; + }; + acpi_ec0: acpi_ec@400f0800 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f0800 0x400>; + interrupts = <45 3>, <46 3>; + interrupt-names = "acpi_ibf", "acpi_obe"; + girqs = < MCHP_XEC_ECIA(15, 5, 7, 45) + MCHP_XEC_ECIA(15, 6, 7, 46) >; + ldn = <2>; + status = "disabled"; + }; + acpi_ec1: acpi_ec@400f0c00 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f0c00 0x400>; + interrupts = <47 3>, <48 3>; + interrupt-names = "acpi_ibf", "acpi_obe"; + girqs = < MCHP_XEC_ECIA(15, 7, 7, 47) + MCHP_XEC_ECIA(15, 8, 7, 48) >; + ldn = <3>; + status = "disabled"; + }; + acpi_ec2: acpi_ec@400f1000 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f1000 0x400>; + interrupts = <49 3>, <50 3>; + interrupt-names = "acpi_ibf", "acpi_obe"; + girqs = < MCHP_XEC_ECIA(15, 9, 7, 49) + MCHP_XEC_ECIA(15, 10, 7, 50) >; + ldn = <4>; + status = "disabled"; + }; + acpi_ec3: acpi_ec@400f1400 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f1400 0x400>; + interrupts = <51 3>, <52 3>; + interrupt-names = "acpi_ibf", "acpi_obe"; + girqs = < MCHP_XEC_ECIA(15, 11, 7, 51) + MCHP_XEC_ECIA(15, 12, 7, 52) >; + ldn = <5>; + status = "disabled"; + }; + acpi_ec4: acpi_ec@400f1800 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f1800 0x400>; + interrupts = <53 3>, <54 3>; + interrupt-names = "acpi_ibf", "acpi_obe"; + girqs = < MCHP_XEC_ECIA(15, 13, 7, 53) + MCHP_XEC_ECIA(15, 14, 7, 54) >; + ldn = <6>; + status = "disabled"; + }; + acpi_pm1: acpi_pm1@400f1c00 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f1c00 0x400>; + interrupts = <55 3>, <56 3>, <57 3>; + interrupt-names = "pm1_ctl", "pm1_en", "pm1_sts"; + girqs = < MCHP_XEC_ECIA(15, 15, 7, 55) + MCHP_XEC_ECIA(15, 16, 7, 56) + MCHP_XEC_ECIA(15, 17, 7, 57) >; + ldn = <7>; + status = "disabled"; + }; + port92: port92@400f2000 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f2000 0x400>; + ldn = <8>; + status = "disabled"; + }; + emi0: emi@400f4000 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f4000 0x400>; + interrupts = <42 3>; + girqs = < MCHP_XEC_ECIA(15, 2, 7, 42) >; + ldn = <16>; + status = "disabled"; + }; + emi1: emi@400f4400 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f4400 0x400>; + interrupts = <43 3>; + girqs = < MCHP_XEC_ECIA(15, 3, 7, 43) >; + ldn = <17>; + status = "disabled"; + }; + emi2: emi@400f4800 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f4800 0x400>; + interrupts = <44 3>; + girqs = < MCHP_XEC_ECIA(15, 4, 7, 44) >; + ldn = <18>; + status = "disabled"; + }; + rtc0: rtc@400f5000 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f5000 0x100>; + interrupts = <119 3>, <120 3>; + girqs = < MCHP_XEC_ECIA(21, 8, 13, 119) + MCHP_XEC_ECIA(21, 9, 13, 120) >; + pcrs = <2 18>; + ldn = <20>; + status = "disabled"; + }; + /* Capture writes to host I/O 0x80 - 0x83 */ + p80bd0: p80bd@400f8000 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f8000 0x400>; + interrupts = <62 0>; + girqs = < MCHP_XEC_ECIA(15, 22, 7, 62) >; + pcrs = <2 25>; + ldn = <32>; + status = "disabled"; + }; + /* Capture writes to an 8-bit I/O and map to one of 0x80 to 0x83 */ + p80bd0_alias: p80bd@400f8400 { + compatible = "microchip,xec-espi-host-dev"; + reg = <0x400f8400 0x400>; + ldn = <33>; + host-io = <0x90>; + /* map 0x90 to 0x80 */ + host-io-addr-mask = <0x01>; + status = "disabled"; + }; +}; + +symcr: symcr@40100000 { + compatible = "microchip,xec-symcr"; + reg = <0x40100000 0x1000>; + interrupts = <68 1>; + clocks = <&pcr 3 26 MCHP_XEC_PCR_CLK_PERIPH>; + girqs = <16 3>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <1>; +}; + +rom_api: rom_api@1f000 { + reg = <0x1f000 0x1000>; + status = "disabled"; +}; diff --git a/dts/arm/microchip/mec172xnlj.dtsi b/dts/arm/microchip/mec172xnlj.dtsi index 968c1e95c36409f..00d27b422c09aaa 100644 --- a/dts/arm/microchip/mec172xnlj.dtsi +++ b/dts/arm/microchip/mec172xnlj.dtsi @@ -4,11 +4,68 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "mec172xnsz.dtsi" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mec172x/mec172x-vw-routing.dtsi" / { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m4"; + reg = <0>; + cpu-power-states = <&idle &suspend_to_ram>; + }; + + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1000000>; + }; + + suspend_to_ram: suspend_to_ram { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + min-residency-us = <2000000>; + }; + }; + }; + + flash0: flash@c0000 { + reg = <0x000C0000 0x58000>; + }; + + sram0: memory@118000 { + compatible = "mmio-sram"; + reg = <0x00118000 0x10000>; + }; soc { + #include "mec172x_common.dtsi" + + eeprom: eeprom@40002c00 { + compatible = "microchip,xec-eeprom"; + reg = <0x40002c00 0x400>; + interrupts = <155 2>; + size = <8192>; + girqs = <18 13>; + pcrs = <4 14>; + status = "disabled"; + }; + pwm9: pwm@40005890 { compatible = "microchip,xec-pwm"; reg = <0x40005890 0x20>; @@ -32,6 +89,14 @@ status = "disabled"; #pwm-cells = <3>; }; + }; }; +&nvic { + arm,num-irq-priority-bits = <3>; +}; + +&systick { + status = "disabled"; +}; diff --git a/dts/arm/microchip/mec172xnsz.dtsi b/dts/arm/microchip/mec172xnsz.dtsi index 8a95e8ec80045d4..cbb84f218779f98 100644 --- a/dts/arm/microchip/mec172xnsz.dtsi +++ b/dts/arm/microchip/mec172xnsz.dtsi @@ -54,464 +54,8 @@ }; soc { - ecs: ecs@4000fc00 { - reg = <0x4000fc00 0x200>; - }; - pcr: pcr@40080100 { - compatible = "microchip,xec-pcr"; - reg = <0x40080100 0x100 0x4000a400 0x100>; - reg-names = "pcrr", "vbatr"; - interrupts = <174 0>; - core-clock-div = <1>; - /* MEC172x allows sources to be different */ - pll-32k-src = ; - periph-32k-src = ; - clk32kmon-period-min = <1435>; - clk32kmon-period-max = <1495>; - clk32kmon-duty-cycle-var-max = <132>; - clk32kmon-valid-min = <4>; - xtal-enable-delay-ms = <300>; - pll-lock-timeout-ms = <30>; - /* pin configured only if one of the sources is set to PIN */ - pinctrl-0 = <&clk_32khz_in_gpio165>; - pinctrl-names = "default"; - #clock-cells = <3>; - }; - ecia: ecia@4000e000 { - compatible = "microchip,xec-ecia"; - reg = <0x4000e000 0x400>; - direct-capable-girqs = <13 14 15 16 17 18 19 20 21 23>; - clocks = <&pcr 1 0 MCHP_XEC_PCR_CLK_PERIPH>; - #address-cells = <1>; - #size-cells = <1>; - - ranges = <0x0 0x4000e000 0x400>; + #include "mec172x_common.dtsi" - girq8: girq8@0 { - compatible = "microchip,xec-ecia-girq"; - reg = <0x0 0x14>; - interrupts = <0 0>; - girq-id = <0>; - sources = <0 1 2 3 4 5 6 7 - 8 9 10 11 12 13 14 15 - 16 17 18 21 22 24 25 - 26 27 28 29>; - status = "disabled"; - }; - girq9: girq9@14 { - compatible = "microchip,xec-ecia-girq"; - reg = <0x14 0x14>; - interrupts = <1 0>; - girq-id = <1>; - sources = <0 1 2 3 4 5 6 7 - 8 9 10 11 12 13 14 15 - 16 17 18 19 20 21 22 23 - 24 25 26 27 28 29>; - status = "disabled"; - }; - girq10: girq10@28 { - compatible = "microchip,xec-ecia-girq"; - reg = <0x28 0x14>; - interrupts = <2 0>; - girq-id = <2>; - sources = <0 1 2 3 4 5 6 7 - 8 9 10 11 12 13 14 15 - 16 17 18 19 20 21 22 23 - 24 25 26 27 28 29 30>; - status = "disabled"; - }; - girq11: girq11@3c { - compatible = "microchip,xec-ecia-girq"; - reg = <0x3c 0x14>; - interrupts = <3 0>; - girq-id = <3>; - sources = <0 1 2 3 4 5 6 7 - 8 9 10 11 12 13 14 15 - 16 17 18 19 20 21 22 23 - 24 25 26 27 28 29 30>; - status = "disabled"; - }; - girq12: girq12@50 { - compatible = "microchip,xec-ecia-girq"; - reg = <0x50 0x14>; - interrupts = <4 0>; - girq-id = <4>; - sources = <0 1 2 3 4 5 6 7 - 8 9 10 11 12 13 14 15 - 16 17 18 19 20 21 22 23 - 24 25 26 27 28 29 30>; - status = "disabled"; - }; - girq13: girq13@64 { - compatible = "microchip,xec-ecia-girq"; - reg = <0x64 0x14>; - interrupts = <5 0>; - girq-id = <5>; - sources = <0 1 2 3 4>; - status = "disabled"; - }; - girq14: girq14@78 { - compatible = "microchip,xec-ecia-girq"; - reg = <0x78 0x14>; - interrupts = <6 0>; - girq-id = <6>; - sources = <0 1 2 3 4 5 6 7 - 8 9 10 11 12 13 14 15>; - status = "disabled"; - }; - girq15: girq15@8c { - compatible = "microchip,xec-ecia-girq"; - reg = <0x8c 0x14>; - interrupts = <7 0>; - girq-id = <7>; - sources = <0 1 2 3 4 5 6 7 - 8 9 10 11 12 13 14 15 - 16 17 18 19 20 22>; - status = "disabled"; - }; - girq16: girq16@a0 { - compatible = "microchip,xec-ecia-girq"; - reg = <0xa0 0x14>; - interrupts = <8 0>; - girq-id = <8>; - sources = <0 2 3>; - status = "disabled"; - }; - girq17: girq17@b4 { - compatible = "microchip,xec-ecia-girq"; - reg = <0xb4 0x14>; - interrupts = <9 0>; - girq-id = <9>; - sources = <0 1 2 3 4 8 9 10 11 12 13 14 15 - 16 17 20 21 22 23>; - status = "disabled"; - }; - girq18: girq18@c8 { - compatible = "microchip,xec-ecia-girq"; - reg = <0xc8 0x14>; - interrupts = <10 0>; - girq-id = <10>; - sources = <0 1 2 3 4 5 6 7 - 10 20 21 22 23 - 24 25 26 27 28>; - status = "disabled"; - }; - girq19: girq19@dc { - compatible = "microchip,xec-ecia-girq"; - reg = <0xdc 0x14>; - interrupts = <11 0>; - girq-id = <11>; - sources = <0 1 2 3 4 5 6 7 8 9 10>; - status = "disabled"; - }; - girq20: girq20@f0 { - compatible = "microchip,xec-ecia-girq"; - reg = <0xf0 0x14>; - interrupts = <12 0>; - girq-id = <12>; - sources = <3 9>; - status = "disabled"; - }; - girq21: girq21@104 { - compatible = "microchip,xec-ecia-girq"; - reg = <0x104 0x14>; - interrupts = <13 0>; - girq-id = <13>; - sources = <2 3 4 5 6 7 8 9 10 11 12 13 14 15 - 18 19 25 26>; - status = "disabled"; - }; - girq22: girq22@118 { - compatible = "microchip,xec-ecia-girq"; - reg = <0x118 0x14>; - interrupts = <255 0>; - girq-id = <14>; - sources = <0 1 2 3 4 5 9 15>; - status = "disabled"; - }; - girq23: girq23@12c { - compatible = "microchip,xec-ecia-girq"; - reg = <0x12c 0x14>; - interrupts = <14 0>; - girq-id = <15>; - sources = <0 1 2 3 4 5 6 7 8 9 10 16 17>; - status = "disabled"; - }; - girq24: girq24@140 { - compatible = "microchip,xec-ecia-girq"; - reg = <0x140 0x14>; - interrupts = <15 0>; - girq-id = <16>; - sources = <0 1 2 3 4 5 6 7 8 9 10 11 - 12 13 14 15 16 17 18 19 - 20 21 22 23 24 25 26 27>; - status = "disabled"; - }; - girq25: girq25@154 { - compatible = "microchip,xec-ecia-girq"; - reg = <0x154 0x14>; - interrupts = <16 0>; - girq-id = <17>; - sources = <0 1 2 3 4 5 6 7 8 9 10 11 - 12 13 14 15>; - status = "disabled"; - }; - girq26: girq26@168 { - compatible = "microchip,xec-ecia-girq"; - reg = <0x168 0x14>; - interrupts = <17 0>; - girq-id = <18>; - sources = <0 1 2 3 4 5 6 12 13>; - status = "disabled"; - }; - }; - pinctrl: pin-controller@40081000 { - compatible = "microchip,xec-pinctrl"; - #address-cells = <1>; - #size-cells = <1>; - reg = <0x40081000 0x1000>; - - gpio_000_036: gpio@40081000 { - compatible = "microchip,xec-gpio-v2"; - reg = < 0x40081000 0x80 0x40081300 0x04 - 0x40081380 0x04 0x400813fc 0x04>; - interrupts = <3 2>; - gpio-controller; - port-id = <0>; - girq-id = <11>; - #gpio-cells=<2>; - }; - gpio_040_076: gpio@40081080 { - compatible = "microchip,xec-gpio-v2"; - reg = < 0x40081080 0x80 0x40081304 0x04 - 0x40081384 0x04 0x400813f8 0x4>; - interrupts = <2 2>; - gpio-controller; - port-id = <1>; - girq-id = <10>; - #gpio-cells=<2>; - }; - gpio_100_136: gpio@40081100 { - compatible = "microchip,xec-gpio-v2"; - reg = < 0x40081100 0x80 0x40081308 0x04 - 0x40081388 0x04 0x400813f4 0x04>; - gpio-controller; - interrupts = <1 2>; - port-id = <2>; - girq-id = <9>; - #gpio-cells=<2>; - }; - gpio_140_176: gpio@40081180 { - compatible = "microchip,xec-gpio-v2"; - reg = < 0x40081180 0x80 0x4008130c 0x04 - 0x4008138c 0x04 0x400813f0 0x04>; - gpio-controller; - interrupts = <0 2>; - port-id = <3>; - girq-id = <8>; - #gpio-cells=<2>; - }; - gpio_200_236: gpio@40081200 { - compatible = "microchip,xec-gpio-v2"; - reg = < 0x40081200 0x80 0x40081310 0x04 - 0x40081390 0x04 0x400813ec 0x04>; - gpio-controller; - interrupts = <4 2>; - port-id = <4>; - girq-id = <12>; - #gpio-cells=<2>; - }; - gpio_240_276: gpio@40081280 { - compatible = "microchip,xec-gpio-v2"; - reg = < 0x40081280 0x80 0x40081314 0x04 - 0x40081394 0x04 0x400813e8 0x04>; - gpio-controller; - interrupts = <17 2>; - port-id = <5>; - girq-id = <26>; - #gpio-cells=<2>; - }; - }; - wdog: watchdog@40000400 { - compatible = "microchip,xec-watchdog"; - reg = <0x40000400 0x400>; - interrupts = <171 0>; - girqs = <21 2>; - pcrs = <1 9>; - }; - rtimer: timer@40007400 { - compatible = "microchip,xec-rtos-timer"; - reg = <0x40007400 0x10>; - interrupts = <111 0>; - girqs = <23 10>; - }; - timer0: timer@40000c00 { - compatible = "microchip,xec-timer"; - clock-frequency = <48000000>; - reg = <0x40000c00 0x20>; - interrupts = <136 0>; - girqs = <23 0>; - pcrs = <1 30>; - max-value = <0xFFFF>; - prescaler = <0>; - status = "disabled"; - }; - timer1: timer@40000c20 { - compatible = "microchip,xec-timer"; - clock-frequency = <48000000>; - reg = <0x40000c20 0x20>; - interrupts = <137 0>; - girqs = <23 1>; - pcrs = <1 31>; - max-value = <0xFFFF>; - prescaler = <0>; - status = "disabled"; - }; - timer2: timer@40000c40 { - compatible = "microchip,xec-timer"; - clock-frequency = <48000000>; - reg = <0x40000c40 0x20>; - interrupts = <138 0>; - girqs = <23 2>; - pcrs = <3 21>; - max-value = <0xFFFF>; - prescaler = <0>; - status = "disabled"; - }; - timer3: timer@40000c60 { - compatible = "microchip,xec-timer"; - clock-frequency = <48000000>; - reg = <0x40000c60 0x20>; - interrupts = <139 0>; - girqs = <23 3>; - pcrs = <3 22>; - max-value = <0xFFFF>; - prescaler = <0>; - status = "disabled"; - }; - /* - * NOTE: When RTOS timer used as kernel timer, timer4 used - * to provide high speed busy wait counter. Keep disabled to - * prevent counter driver from claiming it. - */ - timer4: timer@40000c80 { - compatible = "microchip,xec-timer"; - clock-frequency = <48000000>; - reg = <0x40000c80 0x20>; - interrupts = <140 0>; - girqs = <23 4>; - pcrs = <3 23>; - max-value = <0xFFFFFFFF>; - prescaler = <0>; - status = "disabled"; - }; - timer5: timer@40000ca0 { - compatible = "microchip,xec-timer"; - clock-frequency = <48000000>; - reg = <0x40000ca0 0x20>; - interrupts = <141 0>; - girqs = <23 5>; - pcrs = <3 24>; - max-value = <0xFFFFFFFF>; - prescaler = <0>; - status = "disabled"; - }; - cntr0: timer@40000d00 { - reg = <0x40000d00 0x20>; - interrupts = <142 0>; - girqs = <23 6>; - pcrs = <4 2>; - status = "disabled"; - }; - cntr1: timer@40000d20 { - reg = <0x40000d20 0x20>; - interrupts = <143 0>; - girqs = <23 7>; - pcrs = <4 3>; - status = "disabled"; - }; - cntr2: timer@40000d40 { - reg = <0x40000d40 0x20>; - interrupts = <144 0>; - girqs = <23 8>; - pcrs = <4 3>; - status = "disabled"; - }; - cntr3: timer@40000d60 { - reg = <0x40000d60 0x20>; - interrupts = <145 0>; - girqs = <23 9>; - pcrs = <4 4>; - status = "disabled"; - }; - cctmr0: timer@40001000 { - reg = <0x40001000 0x40>; - interrupts = <146 0>, <147 0>, <148 0>, <149 0>, - <150 0>, <151 0>, <152 0>, <153 0>, - <154 0>; - girqs = <18 20>, <18 21>, <18 22>, <18 23>, <18 24>, - <18 25>, <18 26>, <18 27>, <18 28>; - pcrs = <3 30>; - status = "disabled"; - }; - hibtimer0: timer@40009800 { - reg = <0x40009800 0x20>; - interrupts = <112 0>; - girqs = <23 16>; - }; - hibtimer1: timer@40009820 { - reg = <0x40009820 0x20>; - interrupts = <113 0>; - girqs = <23 17>; - }; - weektmr0: timer@4000ac80 { - reg = <0x4000ac80 0x80>; - interrupts = <114 0>, <115 0>, <116 0>, - <117 0>, <118 0>; - girqs = <21 3>, <21 4>, <21 5>, <21 6>, <21 7>; - status = "disabled"; - }; - bbram: bb-ram@4000a800 { - compatible = "microchip,xec-bbram"; - reg = <0x4000a800 0x100>; - reg-names = "memory"; - }; - vci0: vci@4000ae00 { - reg = <0x4000ae00 0x40>; - interrupts = <121 0>, <122 0>, <123 0>, - <124 0>, <125 0>; - girqs = <21 10>, <21 11>, <21 12>, <21 13>, <21 14>; - status = "disabled"; - }; - dmac: dmac@40002400 { - compatible = "microchip,xec-dmac"; - reg = <0x40002400 0xc00>; - interrupts = <24 1>, <25 1>, <26 1>, <27 1>, - <28 1>, <29 1>, <30 1>, <31 1>, - <32 1>, <33 1>, <34 1>, <35 1>, - <36 1>, <37 1>, <38 1>, <39 1>; - girqs = < MCHP_XEC_ECIA(14, 0, 6, 24) - MCHP_XEC_ECIA(14, 1, 6, 25) - MCHP_XEC_ECIA(14, 2, 6, 26) - MCHP_XEC_ECIA(14, 3, 6, 27) - MCHP_XEC_ECIA(14, 4, 6, 28) - MCHP_XEC_ECIA(14, 5, 6, 29) - MCHP_XEC_ECIA(14, 6, 6, 30) - MCHP_XEC_ECIA(14, 7, 6, 31) - MCHP_XEC_ECIA(14, 8, 6, 32) - MCHP_XEC_ECIA(14, 9, 6, 33) - MCHP_XEC_ECIA(14, 10, 6, 34) - MCHP_XEC_ECIA(14, 11, 6, 35) - MCHP_XEC_ECIA(14, 12, 6, 36) - MCHP_XEC_ECIA(14, 13, 6, 37) - MCHP_XEC_ECIA(14, 14, 6, 38) - MCHP_XEC_ECIA(14, 15, 6, 39) >; - pcrs = <1 6>; - #dma-cells = <2>; - dma-channels = <16>; - dma-requests = <16>; - status = "disabled"; - }; eeprom: eeprom@40002c00 { compatible = "microchip,xec-eeprom"; reg = <0x40002c00 0x400>; @@ -521,543 +65,6 @@ pcrs = <4 14>; status = "disabled"; }; - i2c_smb_0: i2c@40004000 { - compatible = "microchip,xec-i2c-v2"; - reg = <0x40004000 0x80>; - clock-frequency = ; - interrupts = <20 1>; - girqs = <13 0>; - pcrs = <1 10>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - i2c_smb_1: i2c@40004400 { - compatible = "microchip,xec-i2c-v2"; - reg = <0x40004400 0x80>; - clock-frequency = ; - interrupts = <21 1>; - girqs = <13 1>; - pcrs = <3 13>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - i2c_smb_2: i2c@40004800 { - compatible = "microchip,xec-i2c-v2"; - reg = <0x40004800 0x80>; - clock-frequency = ; - interrupts = <22 1>; - girqs = <13 2>; - pcrs = <3 14>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - i2c_smb_3: i2c@40004c00 { - compatible = "microchip,xec-i2c-v2"; - reg = <0x40004C00 0x80>; - clock-frequency = ; - interrupts = <23 1>; - girqs = <13 3>; - pcrs = <3 15>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - i2c_smb_4: i2c@40005000 { - compatible = "microchip,xec-i2c-v2"; - reg = <0x40005000 0x80>; - clock-frequency = ; - interrupts = <158 1>; - girqs = <13 4>; - pcrs = <3 20>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - ps2_0: ps2@40009000 { - compatible = "microchip,xec-ps2"; - reg = <0x40009000 0x40>; - interrupts = <100 1>; - girqs = <18 10>, <21 18>; - pcrs = <3 5>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - pwm0: pwm@40005800 { - compatible = "microchip,xec-pwm"; - reg = <0x40005800 0x20>; - pcrs = <1 4>; - status = "disabled"; - #pwm-cells = <3>; - }; - pwm1: pwm@40005810 { - compatible = "microchip,xec-pwm"; - reg = <0x40005810 0x20>; - pcrs = <1 20>; - status = "disabled"; - #pwm-cells = <3>; - }; - pwm2: pwm@40005820 { - compatible = "microchip,xec-pwm"; - reg = <0x40005820 0x20>; - pcrs = <1 21>; - status = "disabled"; - #pwm-cells = <3>; - }; - pwm3: pwm@40005830 { - compatible = "microchip,xec-pwm"; - reg = <0x40005830 0x20>; - pcrs = <1 22>; - status = "disabled"; - #pwm-cells = <3>; - }; - pwm4: pwm@40005840 { - compatible = "microchip,xec-pwm"; - reg = <0x40005840 0x20>; - pcrs = <1 23>; - status = "disabled"; - #pwm-cells = <3>; - }; - pwm5: pwm@40005850 { - compatible = "microchip,xec-pwm"; - reg = <0x40005850 0x20>; - pcrs = <1 24>; - status = "disabled"; - #pwm-cells = <3>; - }; - pwm6: pwm@40005860 { - compatible = "microchip,xec-pwm"; - reg = <0x40005860 0x20>; - pcrs = <1 25>; - status = "disabled"; - #pwm-cells = <3>; - }; - pwm7: pwm@40005870 { - compatible = "microchip,xec-pwm"; - reg = <0x40005870 0x20>; - pcrs = <1 26>; - status = "disabled"; - #pwm-cells = <3>; - }; - pwm8: pwm@40005880 { - compatible = "microchip,xec-pwm"; - reg = <0x40005880 0x20>; - pcrs = <1 27>; - status = "disabled"; - #pwm-cells = <3>; - }; - tach0: tach@40006000 { - compatible = "microchip,xec-tach"; - reg = <0x40006000 0x10>; - interrupts = <71 4>; - girqs = <17 1>; - pcrs = <1 2>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - tach1: tach@40006010 { - compatible = "microchip,xec-tach"; - reg = <0x40006010 0x10>; - interrupts = <72 4>; - girqs = <17 2>; - pcrs = <1 11>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - tach2: tach@40006020 { - compatible = "microchip,xec-tach"; - reg = <0x40006020 0x10>; - interrupts = <73 4>; - girqs = <17 3>; - pcrs = <1 12>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - tach3: tach@40006030 { - compatible = "microchip,xec-tach"; - reg = <0x40006030 0x10>; - interrupts = <159 4>; - girqs = <17 4>; - pcrs = <1 13>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - rpmfan0: rpmfan@4000a000 { - reg = <0x4000a000 0x80>; - interrupts = <74 1>, <75 1>; - girqs = <17 20>, <17 21>; - pcrs = <3 12>; - status = "disabled"; - }; - rpmfan1: rpmfan@4000a080 { - reg = <0x4000a080 0x80>; - interrupts = <76 1>, <77 1>; - girqs = <17 22>, <17 23>; - pcrs = <4 7>; - status = "disabled"; - }; - adc0: adc@40007c00 { - compatible = "microchip,xec-adc"; - reg = <0x40007c00 0x90>; - interrupts = <78 0>, <79 0>; - girqs = <17 8>, <17 9>; - pcrs = <3 3>; - status = "disabled"; - #io-channel-cells = <1>; - clktime = <32>; - }; - kscan0: kscan@40009c00 { - compatible = "microchip,xec-kscan"; - reg = <0x40009c00 0x18>; - interrupts = <135 0>; - girqs = <21 25>; - pcrs = <3 11>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - peci0: peci@40006400 { - compatible = "microchip,xec-peci"; - reg = <0x40006400 0x80>; - interrupts = <70 4>; - girqs = <17 0>; - pcrs = <1 1>; - #address-cells = <1>; - #size-cells = <0>; - }; - spi0: spi@40070000 { - reg = <0x40070000 0x400>; - interrupts = <91 2>; - girqs = < MCHP_XEC_ECIA(18, 1, 10, 91) >; - clocks = <&pcr 4 8 MCHP_XEC_PCR_CLK_PERIPH>; - clock-frequency = <12000000>; - lines = <1>; - chip-select = <0>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - spi1: spi@40009400 { - reg = <0x40009400 0x80>; - interrupts = <92 2>, <93 2>; - girqs = <18 2>, <18 3>; - pcrs = <3 9>; - status = "disabled"; - }; - spi2: spi@40009480 { - reg = <0x40009480 0x80>; - interrupts = <94 2>, <95 2>; - girqs = <18 4>, <18 5>; - pcrs = <4 22>; - status = "disabled"; - }; - prochot0: prochot@40003400 { - reg = <0x40003400 0x20>; - interrupts = <87 0>; - girqs = <17 17>; - pcrs = <4 13>; - status = "disabled"; - }; - rcid0: rcid@40001400 { - reg = <0x40001400 0x80>; - interrupts = <80 0>; - girqs = <17 10>; - pcrs = <4 10>; - status = "disabled"; - }; - rcid1: rcid@40001480 { - reg = <0x40001480 0x80>; - interrupts = <81 0>; - girqs = <17 11>; - pcrs = <4 11>; - status = "disabled"; - }; - rcid2: rcid@40001500 { - reg = <0x40001500 0x80>; - interrupts = <82 0>; - girqs = <17 12>; - pcrs = <4 12>; - status = "disabled"; - }; - spip0: spip@40007000 { - reg = <0x40007000 0x100>; - interrupts = <90 0>; - girqs = <18 0>; - pcrs = <4 16>; - status = "disabled"; - }; - bbled0: bbled@4000b800 { - reg = <0x4000b800 0x100>; - interrupts = <83 0>; - girqs = <17 13>; - pcrs = <3 16>; - status = "disabled"; - }; - bbled1: bbled@4000b900 { - reg = <0x4000b900 0x100>; - interrupts = <84 0>; - girqs = <17 14>; - pcrs = <3 17>; - status = "disabled"; - }; - bbled2: bbled@4000ba00 { - reg = <0x4000ba00 0x100>; - interrupts = <85 0>; - girqs = <17 15>; - pcrs = <3 18>; - status = "disabled"; - }; - bbled3: bbled@4000bb00 { - reg = <0x4000bb00 0x100>; - interrupts = <86 0>; - girqs = <17 16>; - pcrs = <3 25>; - status = "disabled"; - }; - bclink0: bclink@4000cd00 { - reg = <0x4000cd00 0x20>; - interrupts = <96 0>, <97 0>; - girqs = <18 7>, <18 6>; - pcrs = <3 19>; - status = "disabled"; - }; - tfdp0: tfdp@40008c00 { - reg = <0x40008c00 0x10>; - pcrs = <1 7>; - status = "disabled"; - }; - glblcfg0: glblcfg@400fff00 { - reg = <0x400fff00 0x40>; - pcrs = <2 12>; - status = "disabled"; - }; - uart0: uart@400f2400 { - compatible = "microchip,xec-uart"; - reg = <0x400f2400 0x400>; - interrupts = <40 1>; - clock-frequency = <1843200>; - current-speed = <38400>; - girqs = <15 0>; - pcrs = <2 1>; - ldn = <9>; - status = "disabled"; - }; - uart1: uart@400f2800 { - compatible = "microchip,xec-uart"; - reg = <0x400f2800 0x400>; - interrupts = <41 1>; - clock-frequency = <1843200>; - current-speed = <38400>; - girqs = <15 1>; - pcrs = <2 2>; - ldn = <10>; - status = "disabled"; - }; - espi0: espi@400f3400 { - compatible = "microchip,xec-espi-v2"; - /* reg tuple contains one 32-bit address cell and one - * 32-bit length(size) cell. - */ - #address-cells = <1>; - #size-cells = <1>; - reg = < 0x400f3400 0x400 - 0x400f3800 0x400 - 0x400f9c00 0x400>; - reg-names = "io", "mem", "vw"; - interrupts = <103 3>, <104 3>, <105 3>, <106 3>, - <107 3>, <108 3>, <109 3>, <110 2>, - <156 3>; - interrupt-names = "pc", "bm1", "bm2", "ltr", "oob_up", - "oob_dn", "fc", "rst", "vw_chan_en"; - girqs = < MCHP_XEC_ECIA(19, 0, 11, 103) - MCHP_XEC_ECIA(19, 1, 11, 104) - MCHP_XEC_ECIA(19, 2, 11, 105) - MCHP_XEC_ECIA(19, 3, 11, 106) - MCHP_XEC_ECIA(19, 4, 11, 107) - MCHP_XEC_ECIA(19, 5, 11, 108) - MCHP_XEC_ECIA(19, 6, 11, 109) - MCHP_XEC_ECIA(19, 7, 11, 110) - MCHP_XEC_ECIA(19, 8, 11, 156) >; - pcrs = <2 19>; - status = "disabled"; - - espi_saf0: espi_saf@40008000 { - compatible = "microchip,xec-espi-saf-v2"; - reg = <0x40008000 0x400>, <0x40070000 0x400>, - <0x40071000 0x400>; - reg-names = "safbr", "safqspi", "safcomm"; - interrupts = <166 3>, <167 3>; - interrupt-names = "done", "err"; - girqs = < MCHP_XEC_ECIA(19, 9, 11, 166) >, - < MCHP_XEC_ECIA(19, 10, 11, 167) >; - pcrs = <2 27>; - status = "disabled"; - }; - - mbox0: mbox@400f0000 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f0000 0x200>; - interrupts = <60 3>; - girqs = < MCHP_XEC_ECIA(15, 20, 7, 60) >; - pcrs = <2 17>; - ldn = <0>; - status = "disabled"; - }; - kbc0: kbc@400f0400 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f0400 0x400>; - interrupts = <58 3>, <59 3>; - interrupt-names = "kbc_obe", "kbc_ibf"; - girqs = < MCHP_XEC_ECIA(15, 18, 7, 58) - MCHP_XEC_ECIA(15, 19, 7, 59) >; - ldn = <1>; - status = "disabled"; - }; - acpi_ec0: acpi_ec@400f0800 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f0800 0x400>; - interrupts = <45 3>, <46 3>; - interrupt-names = "acpi_ibf", "acpi_obe"; - girqs = < MCHP_XEC_ECIA(15, 5, 7, 45) - MCHP_XEC_ECIA(15, 6, 7, 46) >; - ldn = <2>; - status = "disabled"; - }; - acpi_ec1: acpi_ec@400f0c00 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f0c00 0x400>; - interrupts = <47 3>, <48 3>; - interrupt-names = "acpi_ibf", "acpi_obe"; - girqs = < MCHP_XEC_ECIA(15, 7, 7, 47) - MCHP_XEC_ECIA(15, 8, 7, 48) >; - ldn = <3>; - status = "disabled"; - }; - acpi_ec2: acpi_ec@400f1000 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f1000 0x400>; - interrupts = <49 3>, <50 3>; - interrupt-names = "acpi_ibf", "acpi_obe"; - girqs = < MCHP_XEC_ECIA(15, 9, 7, 49) - MCHP_XEC_ECIA(15, 10, 7, 50) >; - ldn = <4>; - status = "disabled"; - }; - acpi_ec3: acpi_ec@400f1400 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f1400 0x400>; - interrupts = <51 3>, <52 3>; - interrupt-names = "acpi_ibf", "acpi_obe"; - girqs = < MCHP_XEC_ECIA(15, 11, 7, 51) - MCHP_XEC_ECIA(15, 12, 7, 52) >; - ldn = <5>; - status = "disabled"; - }; - acpi_ec4: acpi_ec@400f1800 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f1800 0x400>; - interrupts = <53 3>, <54 3>; - interrupt-names = "acpi_ibf", "acpi_obe"; - girqs = < MCHP_XEC_ECIA(15, 13, 7, 53) - MCHP_XEC_ECIA(15, 14, 7, 54) >; - ldn = <6>; - status = "disabled"; - }; - acpi_pm1: acpi_pm1@400f1c00 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f1c00 0x400>; - interrupts = <55 3>, <56 3>, <57 3>; - interrupt-names = "pm1_ctl", "pm1_en", "pm1_sts"; - girqs = < MCHP_XEC_ECIA(15, 15, 7, 55) - MCHP_XEC_ECIA(15, 16, 7, 56) - MCHP_XEC_ECIA(15, 17, 7, 57) >; - ldn = <7>; - status = "disabled"; - }; - port92: port92@400f2000 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f2000 0x400>; - ldn = <8>; - status = "disabled"; - }; - emi0: emi@400f4000 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f4000 0x400>; - interrupts = <42 3>; - girqs = < MCHP_XEC_ECIA(15, 2, 7, 42) >; - ldn = <16>; - status = "disabled"; - }; - emi1: emi@400f4400 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f4400 0x400>; - interrupts = <43 3>; - girqs = < MCHP_XEC_ECIA(15, 3, 7, 43) >; - ldn = <17>; - status = "disabled"; - }; - emi2: emi@400f4800 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f4800 0x400>; - interrupts = <44 3>; - girqs = < MCHP_XEC_ECIA(15, 4, 7, 44) >; - ldn = <18>; - status = "disabled"; - }; - rtc0: rtc@400f5000 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f5000 0x100>; - interrupts = <119 3>, <120 3>; - girqs = < MCHP_XEC_ECIA(21, 8, 13, 119) - MCHP_XEC_ECIA(21, 9, 13, 120) >; - pcrs = <2 18>; - ldn = <20>; - status = "disabled"; - }; - /* Capture writes to host I/O 0x80 - 0x83 */ - p80bd0: p80bd@400f8000 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f8000 0x400>; - interrupts = <62 0>; - girqs = < MCHP_XEC_ECIA(15, 22, 7, 62) >; - pcrs = <2 25>; - ldn = <32>; - status = "disabled"; - }; - /* Capture writes to an 8-bit I/O and map to one of 0x80 to 0x83 */ - p80bd0_alias: p80bd@400f8400 { - compatible = "microchip,xec-espi-host-dev"; - reg = <0x400f8400 0x400>; - ldn = <33>; - host-io = <0x90>; - /* map 0x90 to 0x80 */ - host-io-addr-mask = <0x01>; - status = "disabled"; - }; - }; - - symcr: symcr@40100000 { - compatible = "microchip,xec-symcr"; - reg = <0x40100000 0x1000>; - interrupts = <68 1>; - clocks = <&pcr 3 26 MCHP_XEC_PCR_CLK_PERIPH>; - girqs = <16 3>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <1>; - }; - - rom_api: rom_api@1f000 { - reg = <0x1f000 0x1000>; - status = "disabled"; - }; }; }; diff --git a/dts/arm/nordic/nrf51822.dtsi b/dts/arm/nordic/nrf51822.dtsi index 222ccd4854c3c05..020711a7e7f7f9f 100644 --- a/dts/arm/nordic/nrf51822.dtsi +++ b/dts/arm/nordic/nrf51822.dtsi @@ -131,11 +131,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 +317,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 dd7845588e7dfe2..a54e8eca9c68eef 100644 --- a/dts/arm/nordic/nrf52805.dtsi +++ b/dts/arm/nordic/nrf52805.dtsi @@ -132,11 +132,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 +312,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; diff --git a/dts/arm/nordic/nrf52810.dtsi b/dts/arm/nordic/nrf52810.dtsi index 82f5afb99f6d2c7..ce5a2bce77981b5 100644 --- a/dts/arm/nordic/nrf52810.dtsi +++ b/dts/arm/nordic/nrf52810.dtsi @@ -136,11 +136,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 +338,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; diff --git a/dts/arm/nordic/nrf52811.dtsi b/dts/arm/nordic/nrf52811.dtsi index 9e03d5edb320f86..9c9a3fa6b771655 100644 --- a/dts/arm/nordic/nrf52811.dtsi +++ b/dts/arm/nordic/nrf52811.dtsi @@ -167,11 +167,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 +373,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; diff --git a/dts/arm/nordic/nrf52820.dtsi b/dts/arm/nordic/nrf52820.dtsi index 71ff85afbeb98ef..c210a7c23aa5500 100644 --- a/dts/arm/nordic/nrf52820.dtsi +++ b/dts/arm/nordic/nrf52820.dtsi @@ -180,11 +180,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 +390,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; diff --git a/dts/arm/nordic/nrf52832.dtsi b/dts/arm/nordic/nrf52832.dtsi index 69de3aa591ad190..2e1fd68946b4a56 100644 --- a/dts/arm/nordic/nrf52832.dtsi +++ b/dts/arm/nordic/nrf52832.dtsi @@ -179,11 +179,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 +466,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; diff --git a/dts/arm/nordic/nrf52833.dtsi b/dts/arm/nordic/nrf52833.dtsi index 8003649385cf334..d55f0f6df9e05d1 100644 --- a/dts/arm/nordic/nrf52833.dtsi +++ b/dts/arm/nordic/nrf52833.dtsi @@ -186,11 +186,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 +522,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; gpio1: gpio@50000300 { @@ -532,6 +534,7 @@ ngpios = <10>; status = "disabled"; port = <1>; + gpiote-instance = <&gpiote>; }; }; }; diff --git a/dts/arm/nordic/nrf52840.dtsi b/dts/arm/nordic/nrf52840.dtsi index 24710e8e0ff2e93..e833835198b8ebf 100644 --- a/dts/arm/nordic/nrf52840.dtsi +++ b/dts/arm/nordic/nrf52840.dtsi @@ -181,11 +181,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 +526,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; gpio1: gpio@50000300 { @@ -536,6 +538,7 @@ ngpios = <16>; status = "disabled"; port = <1>; + gpiote-instance = <&gpiote>; }; cryptocell: crypto@5002a000 { diff --git a/dts/arm/nordic/nrf5340_cpuapp.dtsi b/dts/arm/nordic/nrf5340_cpuapp.dtsi index 77762990e133886..bc6b5316519d499 100644 --- a/dts/arm/nordic/nrf5340_cpuapp.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp.dtsi @@ -84,6 +84,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 { @@ -104,10 +114,3 @@ &nvic { 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" diff --git a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi index e7aa0309f70dbcb..94e764ec52cfaf2 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 5cfe561e6139df8..000000000000000 --- 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 9a730a3940688b9..a543ffe906b1ef9 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 b5278745e5d5fce..aa97c3370678b05 100644 --- a/dts/arm/nordic/nrf5340_cpuappns.dtsi +++ b/dts/arm/nordic/nrf5340_cpuappns.dtsi @@ -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 */ @@ -64,12 +77,3 @@ &nvic { 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 {}; diff --git a/dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi b/dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi index e4f38769d8fac36..80d5706232f6519 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 63c7e920f81806e..d930cf603c0b5a7 100644 --- a/dts/arm/nordic/nrf5340_cpunet.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet.dtsi @@ -108,11 +108,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 { @@ -192,6 +193,7 @@ reg = <0x41013000 0x1000>; clock-frequency = ; interrupts = <19 NRF_DEFAULT_IRQ_PRIORITY>; + easydma-maxcnt-bits = <16>; status = "disabled"; }; @@ -317,6 +319,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; gpio1: gpio@418c0800 { @@ -327,6 +330,7 @@ ngpios = <16>; status = "disabled"; port = <1>; + gpiote-instance = <&gpiote>; }; }; diff --git a/dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi b/dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi index c8047ebf9051fe1..19eb682ddfc61d6 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/nrf54l15_cpuapp.dtsi b/dts/arm/nordic/nrf54l15_cpuapp.dtsi new file mode 100644 index 000000000000000..7e90c8b12138bf3 --- /dev/null +++ b/dts/arm/nordic/nrf54l15_cpuapp.dtsi @@ -0,0 +1,90 @@ +/* + * 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>; + }; + + 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 000000000000000..786c21ab215c4e2 --- /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 000000000000000..4fb7768bd3f3e3d --- /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 "nrf_common.dtsi" + +/ { + 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 46024011166918c..81be475d7759700 100644 --- a/dts/arm/nordic/nrf91.dtsi +++ b/dts/arm/nordic/nrf91.dtsi @@ -22,7 +22,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; @@ -60,11 +59,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 { diff --git a/dts/arm/nordic/nrf9151_laca.dtsi b/dts/arm/nordic/nrf9151_laca.dtsi new file mode 100644 index 000000000000000..9ed202740170406 --- /dev/null +++ b/dts/arm/nordic/nrf9151_laca.dtsi @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&flash0 { + reg = <0x00000000 DT_SIZE_K(1024)>; +}; + +&sram0 { + reg = <0x20000000 DT_SIZE_K(256)>; +}; + +/ { + soc { + compatible = "nordic,nrf9151-laca", "nordic,nrf9120", + "nordic,nrf91", "simple-bus"; + }; +}; diff --git a/dts/arm/nordic/nrf9151ns_laca.dtsi b/dts/arm/nordic/nrf9151ns_laca.dtsi new file mode 100644 index 000000000000000..ac31c6e19c6054a --- /dev/null +++ b/dts/arm/nordic/nrf9151ns_laca.dtsi @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&flash0 { + reg = <0x00000000 DT_SIZE_K(1024)>; +}; + +&sram0 { + reg = <0x20000000 DT_SIZE_K(256)>; +}; + +/ { + soc { + compatible = "nordic,nrf9151-laca", "nordic,nrf9120", + "nordic,nrf91", "simple-bus"; + }; +}; diff --git a/dts/arm/nordic/nrf91_peripherals.dtsi b/dts/arm/nordic/nrf91_peripherals.dtsi index 2e437eb082dd903..b6ed30990be39dd 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 910f45ec70619d3..22510b0cfac45b6 100644 --- a/dts/arm/nordic/nrf91ns.dtsi +++ b/dts/arm/nordic/nrf91ns.dtsi @@ -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>; }; }; diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi index 2355a6fd82a9111..d73a888d21b4019 100644 --- a/dts/arm/nuvoton/m46x.dtsi +++ b/dts/arm/nuvoton/m46x.dtsi @@ -10,6 +10,8 @@ #include #include #include +#include +#include / { chosen { @@ -428,6 +430,179 @@ #pwm-cells = <3>; status = "disabled"; }; + + canfd0: canfd@40020000 { + compatible = "nuvoton,numaker-canfd"; + reg = <0x40020000 0x200>, <0x40020200 0x1800>; + reg-names = "m_can", "message_ram"; + interrupts = <112 0>, <113 0>; + interrupt-names = "int0", "int1"; + resets = <&rst NUMAKER_CANFD0_RST>; + clocks = <&pcc NUMAKER_CANFD0_MODULE + NUMAKER_CLK_CLKSEL0_CANFD0SEL_HCLK + NUMAKER_CLK_CLKDIV5_CANFD0(1)>; + bosch,mram-cfg = <0x0 12 10 3 3 3 3 3>; + status = "disabled"; + sample-point = <875>; + sample-point-data = <875>; + }; + + canfd1: canfd@40024000 { + compatible = "nuvoton,numaker-canfd"; + reg = <0x40024000 0x200>, <0x40024200 0x1800>; + reg-names = "m_can", "message_ram"; + interrupts = <114 0>, <115 0>; + interrupt-names = "int0", "int1"; + resets = <&rst NUMAKER_CANFD1_RST>; + clocks = <&pcc NUMAKER_CANFD1_MODULE + NUMAKER_CLK_CLKSEL0_CANFD1SEL_HCLK + NUMAKER_CLK_CLKDIV5_CANFD1(1)>; + bosch,mram-cfg = <0x0 12 10 3 3 3 3 3>; + status = "disabled"; + sample-point = <875>; + sample-point-data = <875>; + }; + + canfd2: canfd@40028000 { + compatible = "nuvoton,numaker-canfd"; + reg = <0x40028000 0x200>, <0x40028200 0x1800>; + reg-names = "m_can", "message_ram"; + interrupts = <120 0>, <121 0>; + interrupt-names = "int0", "int1"; + resets = <&rst NUMAKER_CANFD2_RST>; + clocks = <&pcc NUMAKER_CANFD2_MODULE + NUMAKER_CLK_CLKSEL0_CANFD2SEL_HCLK + NUMAKER_CLK_CLKDIV5_CANFD2(1)>; + bosch,mram-cfg = <0x0 12 10 3 3 3 3 3>; + status = "disabled"; + sample-point = <875>; + sample-point-data = <875>; + }; + + canfd3: canfd@4002c000 { + compatible = "nuvoton,numaker-canfd"; + reg = <0x4002c000 0x200>, <0x4002c200 0x1800>; + reg-names = "m_can", "message_ram"; + interrupts = <122 0>, <123 0>; + interrupt-names = "int0", "int1"; + resets = <&rst NUMAKER_CANFD3_RST>; + clocks = <&pcc NUMAKER_CANFD3_MODULE + NUMAKER_CLK_CLKSEL0_CANFD3SEL_HCLK + NUMAKER_CLK_CLKDIV5_CANFD3(1)>; + bosch,mram-cfg = <0x0 12 10 3 3 3 3 3>; + status = "disabled"; + sample-point = <875>; + sample-point-data = <875>; + }; + + emac: ethernet@40012000 { + compatible = "nuvoton,numaker-ethernet"; + reg = <0x40012000 0x105C>; + interrupts = <66 0>; + resets = <&rst NUMAKER_EMAC0_RST>; + phy-addr = <1>; + 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>; + }; }; }; diff --git a/dts/arm/nuvoton/npcx/npcx.dtsi b/dts/arm/nuvoton/npcx/npcx.dtsi index c1a77c4fe699290..6c9a82f01457c57 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 54616fbeed4d808..004ca5332afeaa1 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 { @@ -318,6 +340,7 @@ }; soc-id { + family-id = <0x23>; chip-id = <0x0a>; revision-reg = <0x0000FFFC 4>; }; diff --git a/dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi b/dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi index c795a41736b31fb..af45fa59ddb0829 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 529d5bdef3537d7..be00312759680c9 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 e9acb4a097828ce..2b219c48edecbde 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 4d0cb7dc69e3dd0..e3004ab879dd3c8 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 2fe2b1f75c9b4c9..2ba0b78fdda2999 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/npcx4m3f.dtsi b/dts/arm/nuvoton/npcx4m3f.dtsi index 327e8754c771897..334cd2db653a94a 100644 --- a/dts/arm/nuvoton/npcx4m3f.dtsi +++ b/dts/arm/nuvoton/npcx4m3f.dtsi @@ -22,7 +22,7 @@ }; soc-id { - device-id = <0x2d>; + device-id = <0x25>; }; }; diff --git a/dts/arm/nuvoton/npcx4m8f.dtsi b/dts/arm/nuvoton/npcx4m8f.dtsi index 9baf3c255f9b302..ac141ab31b96b0c 100644 --- a/dts/arm/nuvoton/npcx4m8f.dtsi +++ b/dts/arm/nuvoton/npcx4m8f.dtsi @@ -22,7 +22,7 @@ }; soc-id { - device-id = <0x2b>; + device-id = <0x23>; }; }; diff --git a/dts/arm/nuvoton/npcx9mfp.dtsi b/dts/arm/nuvoton/npcx9mfp.dtsi new file mode 100644 index 000000000000000..fb646513f43bb11 --- /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 4afe8e138a637d5..df4636bc72acb02 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>; }; }; }; @@ -155,10 +154,6 @@ status = "disabled"; }; - /* - * For now only UART4 is supported and - * tested with the serial driver - */ uart4: uart@30a60000 { compatible = "nxp,imx-iuart"; reg = <0x30a60000 0x10000>; @@ -167,6 +162,14 @@ status = "disabled"; }; + uart1: uart@30860000 { + compatible = "nxp,imx-iuart"; + reg = <0x30860000 0x10000>; + interrupts = <26 3>; + clocks = <&ccm IMX_CCM_UART1_CLK 0x7c 24>; + status = "disabled"; + }; + mailbox0: mailbox@30ab0000 { compatible = "nxp,imx-mu"; reg = <0x30ab0000 DT_SIZE_K(64)>; diff --git a/dts/arm/nxp/nxp_k22fx512.dtsi b/dts/arm/nxp/nxp_k22fx512.dtsi new file mode 100644 index 000000000000000..4b2962019c0921a --- /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 f5eaa94d81945eb..87c69d17f5e4dcf 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 ca7a25b765eb5fe..c579a9176984ef8 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 9e4ee4841dbd0c6..304bf2e68d9474e 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>; @@ -240,11 +240,10 @@ }; usbhs: usbhs@144000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,lpcip3511"; reg = <0x94000 0x1000>; interrupts = <47 1>; num-bidir-endpoints = <6>; - usb-controller-index = "LpcIp3511Hs0"; status = "disabled"; }; }; diff --git a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi index c429a4bd4ef8382..6ec0240b2f1c808 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>; }; }; }; @@ -284,11 +283,10 @@ }; usbhs: usbhs@144000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,lpcip3511"; reg = <0x94000 0x1000>; interrupts = <47 1>; num-bidir-endpoints = <6>; - usb-controller-index = "LpcIp3511Hs0"; status = "disabled"; }; }; diff --git a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi index 381a0b073913aa9..18ca28d03e8457a 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>; @@ -443,12 +443,11 @@ }; usbfs: usbfs@84000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,lpcip3511"; reg = <0x84000 0x1000>; interrupts = <28 0>; num-bidir-endpoints = <5>; maximum-speed = "full-speed"; - usb-controller-index = "LpcIp3511Fs0"; status = "disabled"; }; diff --git a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi index c7c7d238dc7862f..00cbb8fa0a592f3 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 { @@ -325,21 +324,19 @@ }; usbfs: usbfs@84000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,lpcip3511"; reg = <0x84000 0x1000>; interrupts = <28 1>; num-bidir-endpoints = <5>; maximum-speed = "full-speed"; - usb-controller-index = "LpcIp3511Fs0"; status = "disabled"; }; usbhs: usbhs@94000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,lpcip3511"; reg = <0x94000 0x1000>; interrupts = <47 1>; num-bidir-endpoints = <6>; - usb-controller-index = "LpcIp3511Hs0"; status = "disabled"; }; @@ -412,6 +409,38 @@ prescaler = <2>; #pwm-cells = <3>; }; + + mrt: mrt@d000 { + compatible = "nxp,mrt"; + reg = <0xd000 0x100>; + interrupts = <9 0>; + num-channels = <4>; + num-bits = <24>; + clocks = <&syscon MCUX_MRT_CLK>; + #address-cells = <1>; + #size-cells = <0>; + + mrt_channel0: mrt_channel@0 { + compatible = "nxp,mrt-channel"; + reg = <0>; + status = "disabled"; + }; + mrt_channel1: mrt_channel@1 { + compatible = "nxp,mrt-channel"; + reg = <1>; + status = "disabled"; + }; + mrt_channel2: mrt_channel@2 { + compatible = "nxp,mrt-channel"; + reg = <2>; + status = "disabled"; + }; + mrt_channel3: mrt_channel@3 { + compatible = "nxp,mrt-channel"; + reg = <3>; + status = "disabled"; + }; + }; }; &nvic { diff --git a/dts/arm/nxp/nxp_rt1010.dtsi b/dts/arm/nxp/nxp_rt1010.dtsi index 00b1ce14b4edd5d..84d47e0f35eb527 100644 --- a/dts/arm/nxp/nxp_rt1010.dtsi +++ b/dts/arm/nxp/nxp_rt1010.dtsi @@ -6,6 +6,15 @@ #include +&flexram { + flexram,num-ram-banks = <4>; + /* default fuse */ + flexram,bank-spec = , + , + , + ; +}; + &sysclk { clock-frequency = <500000000>; }; @@ -234,13 +243,12 @@ /* Fixup USB it has different base addr and interrupt numbers on RT1010 */ /delete-node/ usbd@402e0000; usb1: usbd@400e4000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,ehci"; reg = <0x400e4000 0x200>; interrupts = <25 1>; interrupt-names = "usb_otg"; clocks = <&usbclk>; num-bidir-endpoints = <8>; - usb-controller-index = "Ehci0"; status = "disabled"; }; @@ -272,6 +280,8 @@ #pinmux-cells = <2>; reg = <0x401e0000 0x4000>; clocks = <&ccm IMX_CCM_SAI1_CLK 0x7C 18>; + /* Source clock from Audio PLL */ + clock-mux = <2>; /* Audio PLL Output Frequency is determined by: * (Fref * (DIV_SELECT + NUM/DENOM)) / POST_DIV * = (24MHz * (32 + 77 / 100)) / 1 = 786.48 MHz @@ -310,6 +320,8 @@ #pinmux-cells = <2>; reg = <0x401e8000 0x4000>; clocks = <&ccm IMX_CCM_SAI3_CLK 0x7C 22>; + /* Source clock from Audio PLL */ + clock-mux = <2>; pre-div = <0>; podf = <63>; pll-clocks = <&anatop 0x70 0xC000 0>, diff --git a/dts/arm/nxp/nxp_rt1015.dtsi b/dts/arm/nxp/nxp_rt1015.dtsi index 05aeeb86be13dae..bf905168e101d9b 100644 --- a/dts/arm/nxp/nxp_rt1015.dtsi +++ b/dts/arm/nxp/nxp_rt1015.dtsi @@ -7,6 +7,18 @@ #include +&flexram { + 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 = , + , + , + , + ; +}; + &sysclk { clock-frequency = <500000000>; }; @@ -16,7 +28,7 @@ }; &dtcm { - reg = <0x20000000 DT_SIZE_K(32)>; + reg = <0x20000000 DT_SIZE_K(64)>; }; &ocram { diff --git a/dts/arm/nxp/nxp_rt1020.dtsi b/dts/arm/nxp/nxp_rt1020.dtsi index 6b2a26f5242a810..b42a17960fa66dd 100644 --- a/dts/arm/nxp/nxp_rt1020.dtsi +++ b/dts/arm/nxp/nxp_rt1020.dtsi @@ -7,6 +7,19 @@ #include +&flexram { + flexram,num-ram-banks = <8>; + /* default fuse */ + flexram,bank-spec = , + , + , + , + , + , + , + ; +}; + &sysclk { clock-frequency = <500000000>; }; diff --git a/dts/arm/nxp/nxp_rt1024.dtsi b/dts/arm/nxp/nxp_rt1024.dtsi index c8332df17e08bc5..62262bb211873ff 100644 --- a/dts/arm/nxp/nxp_rt1024.dtsi +++ b/dts/arm/nxp/nxp_rt1024.dtsi @@ -7,6 +7,19 @@ #include +&flexram { + flexram,num-ram-banks = <8>; + /* default fuse */ + flexram,bank-spec = , + , + , + , + , + , + , + ; +}; + &sysclk { clock-frequency = <500000000>; }; diff --git a/dts/arm/nxp/nxp_rt1040.dtsi b/dts/arm/nxp/nxp_rt1040.dtsi index 110680f44a75999..c4aa2d578917446 100644 --- a/dts/arm/nxp/nxp_rt1040.dtsi +++ b/dts/arm/nxp/nxp_rt1040.dtsi @@ -6,6 +6,10 @@ #include +&flexram { + flexram,num-ram-banks = <16>; +}; + &sysclk { clock-frequency = <500000000>; }; diff --git a/dts/arm/nxp/nxp_rt1050.dtsi b/dts/arm/nxp/nxp_rt1050.dtsi index 16b2669b416a981..0a66b9b791ec259 100644 --- a/dts/arm/nxp/nxp_rt1050.dtsi +++ b/dts/arm/nxp/nxp_rt1050.dtsi @@ -5,6 +5,27 @@ */ #include +&flexram { + flexram,num-ram-banks = <16>; + /* default fuse */ + flexram,bank-spec = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; +}; + &ccm { arm-podf { clock-div = <2>; diff --git a/dts/arm/nxp/nxp_rt1060.dtsi b/dts/arm/nxp/nxp_rt1060.dtsi index 62e01a5f60923ac..8a9cba715e0c411 100644 --- a/dts/arm/nxp/nxp_rt1060.dtsi +++ b/dts/arm/nxp/nxp_rt1060.dtsi @@ -6,14 +6,33 @@ #include -/* i.MX rt1060 has two continuous on-chip RAM, one is part of the - * FlexRAM mapped at 0x20280000 (vs 0x20280000 on rt1050) and is - * configurable (256KB by defaults), the other one is dedicated 512KB - * ram (OCRAM2) mapped at 0x20200000. In order to have a continuous - * region, we describe them in one 768Kb unique node. - */ -&ocram { - reg = <0x20200000 DT_SIZE_K(768)>; +&flexram { + /* FlexRAM OCRAM is at a different address on RT1060 */ + /delete-node/ ocram@20200000; + ocram: ocram@20280000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20280000 DT_SIZE_K(256)>; + zephyr,memory-region = "OCRAM"; + }; + + flexram,num-ram-banks = <16>; + /* default fuse */ + flexram,bank-spec = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; &ccm { @@ -26,9 +45,9 @@ }; }; -/* i.MX rt1060 has a second Ethernet controller. */ / { soc { + /* i.MX rt1060 has a second Ethernet controller. */ enet2: ethernet@402d4000 { compatible = "nxp,kinetis-ethernet"; reg = <0x402D4000 0x628>; @@ -42,6 +61,13 @@ interrupt-names = "IEEE1588_TMR"; }; }; + + /* RT1060 has a dedicated OCRAM region */ + ocram2: ocram@20200000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20200000 DT_SIZE_K(512)>; + zephyr,memory-region = "OCRAM2"; + }; }; }; diff --git a/dts/arm/nxp/nxp_rt1064.dtsi b/dts/arm/nxp/nxp_rt1064.dtsi index fcb909e0cfcd630..73ed88277382d69 100644 --- a/dts/arm/nxp/nxp_rt1064.dtsi +++ b/dts/arm/nxp/nxp_rt1064.dtsi @@ -7,6 +7,27 @@ #include +&flexram { + flexram,num-ram-banks = <16>; + /* default fuse */ + flexram,bank-spec = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; +}; + &flexspi2 { status = "okay"; reg = <0x402a4000 0x4000>, <0x70000000 DT_SIZE_M(4)>; diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index fede96dece645d4..73e108f10057803 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, NXP + * Copyright 2017,2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,7 @@ #include #include #include +#include / { chosen { @@ -34,7 +35,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; itm: itm@e0000000 { @@ -87,13 +87,17 @@ soc { flexram: flexram@400b0000 { - compatible = "nxp,imx-flexram"; + compatible = "nxp,flexram"; reg = <0x400b0000 0x4000>; interrupts = <38 0>; #address-cells = <1>; #size-cells = <1>; + status = "okay"; + + flexram,bank-size = <32>; + itcm: itcm@0 { compatible = "zephyr,memory-region", "nxp,imx-itcm"; reg = <0x00000000 DT_SIZE_K(128)>; @@ -790,24 +794,22 @@ }; usb1: usbd@402e0000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,ehci"; reg = <0x402E0000 0x200>; interrupts = <113 1>; interrupt-names = "usb_otg"; clocks = <&usbclk>; num-bidir-endpoints = <8>; - usb-controller-index = "Ehci0"; status = "disabled"; }; usb2: usbd@402e0200 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,ehci"; reg = <0x402E0200 0x200>; interrupts = <112 1>; interrupt-names = "usb_otg"; clocks = <&usbclk>; num-bidir-endpoints = <8>; - usb-controller-index = "Ehci1"; status = "disabled"; }; @@ -937,11 +939,13 @@ #pinmux-cells = <2>; reg = <0x40384000 0x4000>; clocks = <&ccm IMX_CCM_SAI1_CLK 0x7C 18>; + /* Source clock from Audio PLL */ + clock-mux = <2>; /* Audio PLL Output Frequency is determined by: * (Fref * (DIV_SELECT + NUM/DENOM)) / POST_DIV * = (24MHz * (32 + 77 / 100)) / 1 = 786.48 MHz */ - pll-clocks = <&anatop 0x70 0xC000 0>, + pll-clocks = <&anatop 0x70 0xC000 0>, <&anatop 0x70 0x7F 32>, <&anatop 0x70 0x180000 1>, <&anatop 0x80 0x3FFFFFFF 77>, @@ -975,6 +979,8 @@ #pinmux-cells = <2>; reg = <0x40388000 0x4000>; clocks = <&ccm IMX_CCM_SAI2_CLK 0x7C 20>; + /* Source clock from Audio PLL */ + clock-mux = <2>; pre-div = <0>; podf = <63>; pll-clocks = <&anatop 0x70 0xC000 0x0>, @@ -1000,6 +1006,8 @@ #pinmux-cells = <2>; reg = <0x4038C000 0x4000>; clocks = <&ccm IMX_CCM_SAI3_CLK 0x7C 22>; + /* Source clock from Audio PLL */ + clock-mux = <2>; pre-div = <0>; podf = <63>; pll-clocks = <&anatop 0x70 0xC000 0>, diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index d3448a029b9d802..9e92a3e022605d5 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, NXP + * Copyright 2021,2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -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>; }; }; @@ -749,24 +747,22 @@ }; usb1: usbd@40430000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,ehci"; reg = <0x40430000 0x200>; interrupts = <136 1>; interrupt-names = "usb_otg"; clocks = <&xtal>; num-bidir-endpoints = <8>; - usb-controller-index = "Ehci0"; status = "disabled"; }; usb2: usbd@4042c000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,ehci"; reg = <0x4042c000 0x200>; interrupts = <135 1>; interrupt-names = "usb_otg"; clocks = <&xtal>; num-bidir-endpoints = <8>; - usb-controller-index = "Ehci1"; status = "disabled"; }; @@ -990,6 +986,8 @@ #pinmux-cells = <2>; reg = <0x40404000 0x4000>; clocks = <&ccm IMX_CCM_SAI1_CLK 0x2004 4>; + /* Source from audio PLL */ + clock-mux = <4>; pre-div = <0>; podf = <4>; pll-clocks = <&anatop 0 0 0>, @@ -1011,6 +1009,8 @@ #pinmux-cells = <2>; reg = <0x40408000 0x4000>; clocks = <&ccm IMX_CCM_SAI2_CLK 0x2084 4>; + /* Source from audio PLL */ + clock-mux = <4>; pre-div = <0>; podf = <63>; pll-clocks = <&anatop 0 0 0>, @@ -1032,6 +1032,8 @@ #pinmux-cells = <2>; reg = <0x4040c000 0x4000>; clocks = <&ccm IMX_CCM_SAI3_CLK 0x2104 4>; + /* Source from audio PLL */ + clock-mux = <4>; pre-div = <0>; podf = <63>; pll-clocks = <&anatop 0 0 0>, @@ -1053,6 +1055,8 @@ #pinmux-cells = <2>; reg = <0x40c40000 0x4000>; clocks = <&ccm IMX_CCM_SAI4_CLK 0x2184 6>; + /* Source from audio PLL */ + clock-mux = <6>; pre-div = <0>; podf = <63>; pll-clocks = <&anatop 0 0 0>, diff --git a/dts/arm/nxp/nxp_rt11xx_cm4.dtsi b/dts/arm/nxp/nxp_rt11xx_cm4.dtsi index 1348bba30029700..4fab1c307f3c173 100644 --- a/dts/arm/nxp/nxp_rt11xx_cm4.dtsi +++ b/dts/arm/nxp/nxp_rt11xx_cm4.dtsi @@ -54,7 +54,7 @@ }; mailbox_b: mailbox@40c4c000 { - compatible = "nxp,imx-mu-rev2"; + compatible = "nxp,imx-mu"; reg = <0x40c4c000 0x4000>; interrupts = <118 0>; rdc = <0>; diff --git a/dts/arm/nxp/nxp_rt11xx_cm7.dtsi b/dts/arm/nxp/nxp_rt11xx_cm7.dtsi index 63a7fc78319ee8c..88d1035ddc39f4c 100644 --- a/dts/arm/nxp/nxp_rt11xx_cm7.dtsi +++ b/dts/arm/nxp/nxp_rt11xx_cm7.dtsi @@ -1,10 +1,11 @@ /* - * Copyright (c) 2021, NXP + * Copyright 2021-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ #include +#include / { cpus { @@ -22,12 +23,35 @@ /delete-node/ dma-controller@40c14000; flexram: flexram@40028000 { + compatible = "nxp,flexram"; + reg = <0x40028000 0x4000>; interrupts = <50 0>; #address-cells = <1>; #size-cells = <1>; + flexram,bank-size = <32>; + flexram,num-ram-banks = <16>; + flexram,has-magic-addr; + /* same as default fuse value */ + flexram,bank-spec = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + itcm: itcm@0 { compatible = "zephyr,memory-region", "nxp,imx-itcm"; reg = <0x00000000 DT_SIZE_K(256)>; @@ -39,6 +63,8 @@ reg = <0x20000000 DT_SIZE_K(256)>; zephyr,memory-region = "DTCM"; }; + + /* no ocram node for this bank-spec */ }; /* @@ -77,7 +103,7 @@ }; mailbox_a: mailbox@40c48000 { - compatible = "nxp,imx-mu-rev2"; + compatible = "nxp,imx-mu"; reg = <0x40c48000 0x4000>; interrupts = <118 0>; rdc = <0>; diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index 9165b26441e1afe..d84d89b8528ecab 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>; }; }; @@ -338,11 +337,10 @@ }; usbhs: usbhs@144000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,lpcip3511"; reg = <0x144000 0x1000>; interrupts = <50 1>; num-bidir-endpoints = <6>; - usb-controller-index = "LpcIp3511Hs0"; status = "disabled"; }; @@ -390,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>; @@ -402,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 { @@ -579,6 +647,38 @@ #mbox-cells = <1>; status = "disabled"; }; + + mrt: mrt@2d000 { + compatible = "nxp,mrt"; + reg = <0x2d000 0x100>; + interrupts = <9 0>; + num-channels = <4>; + num-bits = <24>; + clocks = <&clkctl1 MCUX_MRT_CLK>; + #address-cells = <1>; + #size-cells = <0>; + + mrt_channel0: mrt_channel@0 { + compatible = "nxp,mrt-channel"; + reg = <0>; + status = "disabled"; + }; + mrt_channel1: mrt_channel@1 { + compatible = "nxp,mrt-channel"; + reg = <1>; + status = "disabled"; + }; + mrt_channel2: mrt_channel@2 { + compatible = "nxp,mrt-channel"; + reg = <2>; + status = "disabled"; + }; + mrt_channel3: mrt_channel@3 { + compatible = "nxp,mrt-channel"; + reg = <3>; + status = "disabled"; + }; + }; }; &flexspi { diff --git a/dts/arm/nxp/nxp_rt6xx_common.dtsi b/dts/arm/nxp/nxp_rt6xx_common.dtsi index 843c1739cd29efd..62e8865b731088e 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>; }; }; @@ -259,11 +258,10 @@ }; usbhs: usbhs@144000 { - compatible = "nxp,mcux-usbd"; + compatible = "nxp,lpcip3511"; reg = <0x144000 0x1000>; interrupts = <50 1>; num-bidir-endpoints = <6>; - usb-controller-index = "LpcIp3511Hs0"; status = "disabled"; }; @@ -313,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 { @@ -459,6 +461,38 @@ #address-cells = <3>; #size-cells = <0>; }; + + mrt: mrt@2d000 { + compatible = "nxp,mrt"; + reg = <0x2d000 0x100>; + interrupts = <9 0>; + num-channels = <4>; + num-bits = <24>; + clocks = <&clkctl1 MCUX_MRT_CLK>; + #address-cells = <1>; + #size-cells = <0>; + + mrt_channel0: mrt_channel@0 { + compatible = "nxp,mrt-channel"; + reg = <0>; + status = "disabled"; + }; + mrt_channel1: mrt_channel@1 { + compatible = "nxp,mrt-channel"; + reg = <1>; + status = "disabled"; + }; + mrt_channel2: mrt_channel@2 { + compatible = "nxp,mrt-channel"; + reg = <2>; + status = "disabled"; + }; + mrt_channel3: mrt_channel@3 { + compatible = "nxp,mrt-channel"; + reg = <3>; + status = "disabled"; + }; + }; }; &flexspi { diff --git a/dts/arm/nxp/nxp_s32k146.dtsi b/dts/arm/nxp/nxp_s32k146.dtsi new file mode 100644 index 000000000000000..bfbb1558349a3ca --- /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 000000000000000..10c3d207bf7b3ad --- /dev/null +++ b/dts/arm/nxp/nxp_s32k1xx.dtsi @@ -0,0 +1,321 @@ +/* + * 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"; + }; + }; +}; diff --git a/dts/arm/nxp/nxp_s32k344_m7.dtsi b/dts/arm/nxp/nxp_s32k344_m7.dtsi index 60196628a57537d..0289b24f42ea697 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 56677ed2865a5d7..920f519da0f54e3 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 */ @@ -7,6 +7,7 @@ #include #include #include +#include / { cpus { @@ -692,27 +693,31 @@ 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 = , ; - interrupt-names = "RX_TX_DATA_IRQ", "INT_ERROR_IRQ"; + interrupt-names = "rx_tx", "error"; clocks = <&clock NXP_S32_P5_CANXL_PE_CLK>; }; 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 = , ; - interrupt-names = "RX_TX_DATA_IRQ", "INT_ERROR_IRQ"; + interrupt-names = "rx_tx", "error"; clocks = <&clock NXP_S32_P5_CANXL_PE_CLK>; }; }; diff --git a/dts/arm/quicklogic/quicklogic_eos_s3.dtsi b/dts/arm/quicklogic/quicklogic_eos_s3.dtsi index f29b1c482ffdc3c..bdc4ecfe87de36a 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/r7fa4m1ab3cfm.dtsi b/dts/arm/renesas/ra/r7fa4m1ab3cfm.dtsi new file mode 100644 index 000000000000000..4836a58a0afe600 --- /dev/null +++ b/dts/arm/renesas/ra/r7fa4m1ab3cfm.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define RA_SOC_PINS 64 +#define RA_SOC_HAS_MSTPCRE 1 +#define RA_SOC_MSTPD5_CHANNELS 1 + +#include +#include diff --git a/dts/arm/renesas/ra/ra-cm4-common.dtsi b/dts/arm/renesas/ra/ra-cm4-common.dtsi new file mode 100644 index 000000000000000..4ef18141e6c44e2 --- /dev/null +++ b/dts/arm/renesas/ra/ra-cm4-common.dtsi @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * 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-m4"; + reg = <0>; + }; + }; + + clocks { + mosc: mosc { + compatible = "fixed-clock"; + clock-frequency = <1200000>; + status = "disabled"; + #clock-cells = <0>; + }; + + sosc: sosc { + compatible = "fixed-clock"; + clock-frequency = <32768>; + status = "disabled"; + #clock-cells = <0>; + }; + + hoco: hoco { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + status = "okay"; + #clock-cells = <0>; + }; + + moco: moco { + compatible = "fixed-clock"; + clock-frequency = <8000000>; + status = "okay"; + #clock-cells = <0>; + }; + + loco: loco { + compatible = "fixed-clock"; + clock-frequency = <32768>; + status = "okay"; + #clock-cells = <0>; + }; + + pll: pll { + compatible = "fixed-factor-clock"; + status = "disabled"; + clocks = <&mosc>; + clock-div = <2>; + clock-mult = <8>; + #clock-cells = <0>; + }; + }; + + sram0: memory0@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(32)>; + }; + + soc { + interrupt-parent = <&icu>; + icu: interrupt-controller@40006000 { + compatible = "renesas,ra-interrupt-controller-unit"; + reg = <0x40006000 0x40>; + reg-names = "icu"; + interrupt-controller; + #interrupt-cells = <3>; + }; + + cgc: cgc@4001e000 { + compatible = "renesas,ra-clock-generation-circuit"; + reg = <0x4001e000 0x40 0x40047000 0x10>; + reg-names = "system", "mstp"; + #clock-cells = <1>; + + clock-source = <&moco>; + iclk-div = <16>; + pclka-div = <16>; + pclkb-div = <16>; + pclkc-div = <16>; + pclkd-div = <16>; + fclk-div = <16>; + }; + + fcu: flash-controller@4001c000 { + compatible = "renesas,ra-flash-controller"; + reg = <0x4001c000 0x44>; + reg-names = "fcache"; + + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash0@0 { + compatible = "soc-nv-flash"; + reg = <0x00000000 DT_SIZE_K(256)>; + }; + + flash1: flash1@40100000 { + compatible = "soc-nv-flash"; + reg = <0x40100000 DT_SIZE_K(8)>; + }; + }; + + ioport0: gpio@40040000 { + compatible = "renesas,ra-gpio"; + reg = <0x40040000 0x20>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + interrupts = , + , + , + , + , + ; + interrupt-names = "port-irq2", "port-irq3", "port-irq6", + "port-irq7", "port-irq10", "port-irq15"; + port-irq2-pins = <2>; + port-irq3-pins = <4>; + port-irq6-pins = <0>; + port-irq7-pins = <1 15>; + port-irq10-pins = <5>; + port-irq15-pins = <11>; + status = "disabled"; + }; + + ioport1: gpio@40040020 { + compatible = "renesas,ra-gpio"; + reg = <0x40040020 0x20>; + gpio-controller; + #gpio-cells = <2>; + interrupts = , + , + , + , + ; + interrupt-names = "port-irq0", "port-irq1", "port-irq2", + "port-irq3", "port-irq4"; + port-irq0-pins = <5>; + port-irq1-pins = <1>; + port-irq2-pins = <0>; + port-irq3-pins = <10>; + port-irq4-pins = <11>; + ngpios = <16>; + status = "disabled"; + }; + + ioport2: gpio@40040040 { + compatible = "renesas,ra-gpio"; + reg = <0x40040040 0x20>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + interrupts = , + , + , + , + ; + interrupt-names = "port-irq0", "port-irq1", "port-irq2", + "port-irq3", "port-irq9"; + port-irq0-pins = <6>; + port-irq1-pins = <5>; + port-irq2-pins = <13>; + port-irq3-pins = <12>; + status = "disabled"; + }; + + ioport3: gpio@40040060 { + compatible = "renesas,ra-gpio"; + reg = <0x40040060 0x20>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + interrupts = , + , + , + ; + interrupt-names = "port-irq5", "port-irq6", "port-irq8", "port-irq9"; + port-irq5-pins = <2>; + port-irq6-pins = <1>; + port-irq8-pins = <5>; + port-irq9-pins = <4>; + status = "disabled"; + }; + + ioport4: gpio@40040080 { + compatible = "renesas,ra-gpio"; + reg = <0x40040080 0x20>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + interrupts = , + , + , + , + , + , + ; + interrupt-names = "port-irq0", "port-irq4", "port-irq5", "port-irq6", + "port-irq7", "port-irq8", "port-irq9"; + port-irq0-pins = <0>; + port-irq4-pins = <2 11>; + port-irq5-pins = <1 10>; + port-irq6-pins = <9>; + port-irq7-pins = <8>; + port-irq8-pins = <15>; + port-irq9-pins = <14>; + status = "disabled"; + }; + + ioport5: gpio@400400a0 { + compatible = "renesas,ra-gpio"; + reg = <0x400400a0 0x20>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + interrupts = , + , + ; + interrupt-names = "port-irq11", "port-irq12", "port-irq14"; + port-irq11-pins = <1>; + port-irq12-pins = <2>; + port-irq14-pins = <5>; + status = "disabled"; + }; + + pinctrl: pinctrl@40040800 { + compatible = "renesas,ra-pinctrl"; + reg = <0x40040800 0x500 0x40040d03 0x1>; + reg-names = "pfs", "pmisc_pwpr"; + status = "okay"; + }; + + sci0: sci@40070000 { + compatible = "renesas,ra-sci"; + reg = <0x40070000 0x20>; + interrupts = , + , + , + , + , + ; + interrupt-names = "rxi", "txi", "tei", "eri", "am", "rxi-or-eri"; + clocks = <&cgc RA_CLOCK_SCI(0)>; + #clock-cells = <1>; + status = "disabled"; + uart { + compatible = "renesas,ra-uart-sci"; + status = "disabled"; + }; + }; + + sci1: sci@40070020 { + compatible = "renesas,ra-sci"; + reg = <0x40070020 0x20>; + interrupts = , + , + , + , + ; + interrupt-names = "rxi", "txi", "tei", "eri", "am"; + clocks = <&cgc RA_CLOCK_SCI(1)>; + #clock-cells = <1>; + status = "disabled"; + uart { + compatible = "renesas,ra-uart-sci"; + status = "disabled"; + }; + }; + + sci9: sci@40070120 { + compatible = "renesas,ra-sci"; + reg = <0x40070120 0x20>; + interrupts = , + , + , + , + ; + interrupt-names = "rxi", "txi", "tei", "eri", "am"; + clocks = <&cgc RA_CLOCK_SCI(9)>; + #clock-cells = <1>; + status = "disabled"; + uart { + compatible = "renesas,ra-uart-sci"; + status = "disabled"; + }; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <4>; +}; diff --git a/dts/arm/renesas/ra/ra4-cm4-common.dtsi b/dts/arm/renesas/ra/ra4-cm4-common.dtsi new file mode 100644 index 000000000000000..1d2397f85dec190 --- /dev/null +++ b/dts/arm/renesas/ra/ra4-cm4-common.dtsi @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + ioport6: gpio@400400c0 { + compatible = "renesas,ra-gpio"; + reg = <0x400400c0 0x20>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport7: gpio@400400e0 { + compatible = "renesas,ra-gpio"; + reg = <0x400400e0 0x20>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport8: gpio@40040100 { + compatible = "renesas,ra-gpio"; + reg = <0x40040100 0x20>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + ioport9: gpio@40040120 { + compatible = "renesas,ra-gpio"; + reg = <0x40040120 0x20>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + sci2: sci@40070040 { + compatible = "renesas,ra-sci"; + reg = <0x40070040 0x20>; + interrupts = , + , + , + , + ; + interrupt-names = "rxi", "txi", "tei", "eri", "am"; + clocks = <&cgc RA_CLOCK_SCI(2)>; + #clock-cells = <1>; + status = "disabled"; + uart { + compatible = "renesas,ra-uart-sci"; + status = "disabled"; + }; + }; + }; +}; diff --git a/dts/arm/renesas/rcar/gen4/r8a779f0.dtsi b/dts/arm/renesas/rcar/gen4/r8a779f0.dtsi new file mode 100644 index 000000000000000..0b1667aa4a1b75d --- /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 000000000000000..1ce2ec9151c61b2 --- /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/rz/rzt2m.dtsi b/dts/arm/renesas/rz/rzt2m.dtsi new file mode 100644 index 000000000000000..9c6c1688d63d34a --- /dev/null +++ b/dts/arm/renesas/rz/rzt2m.dtsi @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "renesas,rzt2m-dev"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-r52"; + reg = <0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-r52"; + reg = <1>; + }; + }; + + arch_timer: timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + interrupt-parent = <&gic>; + }; + + soc { + compatible = "renesas,rzt2m-soc"; + + interrupt-parent = <&gic>; + + gic: interrupt-controller@94000000 { + compatible = "arm,gic-v3", "arm,gic"; + reg = <0x94000000 0x10000>, + <0x94100000 0x80000>; + interrupt-controller; + #interrupt-cells = <4>; + status = "okay"; + }; + + cpu0_atcm: memory@0 { + compatible = "mmio-sram"; + reg = <0x00000000 DT_SIZE_K(512)>; + }; + + cpu0_btcm: memory@100000 { + compatible = "mmio-sram"; + reg = <0x00100000 DT_SIZE_K(64)>; + }; + + sram0: memory@10000000 { + compatible = "mmio-sram"; + reg = <0x10000000 DT_SIZE_M(2)>; + }; + + gsc: gsc@c0060000 { + /* Global System Counter */ + compatible = "syscon"; + reg = <0xc0060000 0x30>; + reg-io-width = <4>; + }; + + prcrn: prcrn@80281a10 { + /* Non-safety area */ + compatible = "syscon"; + reg = <0x80281a10 0x10>; + reg-io-width = <4>; + }; + + prcrs: prcrs@81281a00 { + /* Safety area */ + compatible = "syscon"; + reg = <0x81281a00 0x10>; + reg-io-width = <4>; + }; + + uart0: serial@80001000 { + compatible = "renesas,rzt2m-uart"; + reg = <0x80001000 0x1000>; + current-speed = <115200>; + interrupts = , + , + , + ; + interrupt-names = "rx_err", "rx", "tx", "tx_end"; + status = "disabled"; + }; + + uart3: serial@80001c00 { + compatible = "renesas,rzt2m-uart"; + reg = <0x80001c00 0x1000>; + current-speed = <115200>; + interrupts = , + , + , + ; + interrupt-names = "rx_err", "rx", "tx", "tx_end"; + status = "disabled"; + }; + + pinctrl: pinctrl@800a0000 { + compatible = "renesas,rzt2m-pinctrl"; + reg = <0x800a0000 0x1000 0x81030c00 0x1000>; + reg-names = "port_nsr", "ptadr"; + #address-cells = <1>; + #size-cells = <0>; + + gpio19: gpio@13 { + compatible = "renesas,rzt2m-gpio"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + reg = <0x13>; + }; + + gpio20: gpio@14 { + compatible = "renesas,rzt2m-gpio"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + reg = <0x14>; + }; + + gpio23: gpio@17 { + compatible = "renesas,rzt2m-gpio"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + reg = <0x17>; + }; + }; + }; +}; diff --git a/dts/arm/renesas/smartbond/da14695.dtsi b/dts/arm/renesas/smartbond/da14695.dtsi new file mode 100644 index 000000000000000..37d75e4ecc48a43 --- /dev/null +++ b/dts/arm/renesas/smartbond/da14695.dtsi @@ -0,0 +1,12 @@ +/* Copyright (c) 2023 Renesas Electronics Corporation and/or its affiliates */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "da1469x.dtsi" + +&sram0 { + reg = <0x20000000 DT_SIZE_K(512)>; +}; + +&gpio1 { + ngpios = <12>; +}; diff --git a/dts/arm/renesas/smartbond/da1469x.dtsi b/dts/arm/renesas/smartbond/da1469x.dtsi index fa6ccd6bb250874..72f7e6fa89ffd1a 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 { @@ -149,6 +195,14 @@ }; }; + rtc: rtc@50000400 { + compatible = "renesas,smartbond-rtc"; + reg = <0x50000400 0x98>; + interrupts = <18 0>; + alarms-count = <1>; + status = "disabled"; + }; + wdog: watchdog@50000700 { compatible = "renesas,smartbond-watchdog"; reg = <0x50000700 0x8>; @@ -199,6 +253,22 @@ status = "disabled"; }; + uart2: uart@50020100 { + compatible = "renesas,smartbond-uart"; + reg = <0x50020100 0x100>; + periph-clock-config = <0x02>; + interrupts = <6 0>; + status = "disabled"; + }; + + uart3: uart@50020200 { + compatible = "renesas,smartbond-uart"; + reg = <0x50020200 0x100>; + periph-clock-config = <0x08>; + interrupts = <7 0>; + status = "disabled"; + }; + adc: adc@50030900 { compatible = "renesas,smartbond-adc"; reg = <0x50030900 0x1C>; @@ -207,7 +277,6 @@ #io-channel-cells = <1>; }; - sdadc: sdadc@50020800 { compatible = "renesas,smartbond-sdadc"; reg = <0x50020800 0x1C>; @@ -217,6 +286,13 @@ #io-channel-cells = <1>; }; + crypto: crypto@30040000 { + compatible = "renesas,smartbond-crypto"; + reg = <0x30040000 0x200>; + interrupts = <29 0>; + status = "disabled"; + }; + trng: trng@50040c00 { compatible = "renesas,smartbond-trng"; reg = <0x50040c00 0x0C>; @@ -273,6 +349,16 @@ interrupts = <15 0>, <21 0>; status = "disabled"; }; + + dma: dma@50040800 { + compatible = "renesas,smartbond-dma"; + reg = <0x50040800 0x110>; + interrupts = <1 0>; + status = "disabled"; + dma-channels = <8>; + block-count = <1>; + #dma-cells = <0>; + }; }; }; diff --git a/dts/arm/rpi_pico/rp2040.dtsi b/dts/arm/rpi_pico/rp2040.dtsi index fd83297fa5a2943..72c71bfcfdcc251 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-pinctrl.dtsi b/dts/arm/silabs/efr32bg2x-pinctrl.dtsi index 388423e10d057bd..fb5fc1b8484083d 100644 --- a/dts/arm/silabs/efr32bg2x-pinctrl.dtsi +++ b/dts/arm/silabs/efr32bg2x-pinctrl.dtsi @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include &pinctrl { diff --git a/dts/arm/silabs/efr32bg2x.dtsi b/dts/arm/silabs/efr32bg2x.dtsi index e1f3726e4297670..70df9708d116ac2 100644 --- a/dts/arm/silabs/efr32bg2x.dtsi +++ b/dts/arm/silabs/efr32bg2x.dtsi @@ -5,11 +5,11 @@ */ #include -#include #include #include #include #include +#include / { chosen { @@ -17,6 +17,16 @@ zephyr,entropy = &trng; }; + clocks { + clk_hfxo: clk-hfxo { + #clock-cells = <0>; + compatible = "silabs,hfxo"; + clock-frequency = ; + ctune = <120>; + precision = <50>; + }; + }; + cpus { #address-cells = <1>; #size-cells = <0>; diff --git a/dts/arm/silabs/efr32mg12p432f1024gl125.dtsi b/dts/arm/silabs/efr32mg12p432f1024gl125.dtsi new file mode 100644 index 000000000000000..d3da9a5d8947421 --- /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 4ada3f6ff60da31..217830f7265ae0f 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 1ee015b7334c94f..860cedddeda5f0c 100644 --- a/dts/arm/silabs/efr32mg24.dtsi +++ b/dts/arm/silabs/efr32mg24.dtsi @@ -10,6 +10,7 @@ #include #include #include +#include / { chosen { @@ -17,6 +18,16 @@ zephyr,entropy = &se; }; + clocks { + clk_hfxo: clk-hfxo { + #clock-cells = <0>; + compatible = "silabs,hfxo"; + clock-frequency = ; + ctune = <140>; + precision = <50>; + }; + }; + cpus { #address-cells = <1>; #size-cells = <0>; diff --git a/dts/arm/st/c0/stm32c0.dtsi b/dts/arm/st/c0/stm32c0.dtsi index ef71f835ba2ab19..fd37b14b5f93b07 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 e9e521cd47e70c3..0371ac75ac6e105 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 775b3b3ebe4277b..9044da82c0ad426 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 45165c31e2b38e4..51d23418207d120 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 665945738a82214..6962a67ba109513 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 b70130db3089dc1..dc9f140370ec1c1 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 845cd6fb5a21790..9c9137569198411 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 a426a84ea3ea1aa..e4a64b24304240b 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 59f4b2f70776c1f..5d2c40be20b1e53 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 4c1de5611ee2786..8d30e7d31d1892c 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 01e5d4233df1bd1..5fa8d11b150deb0 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 000000000000000..040566c0b2298fb --- /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 fd857c1a8fde941..76131f723490cc6 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 9c42331c36e13f6..73c4de1eafac3a0 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 36cbd9c8fed7f7b..010868a00f2a411 100644 --- a/dts/arm/st/f4/stm32f4.dtsi +++ b/dts/arm/st/f4/stm32f4.dtsi @@ -22,16 +22,33 @@ / { chosen { zephyr,flash-controller = &flash; + zephyr,cortex-m-idle-timer = &rtc; }; cpus { #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <0>; + cpu-power-states = <&stop>; + }; + + power-states { + stop: stop { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + /* It is really hard to establish these numbers precisely. + * We are basing on RTC as a wakeup source with 62,5us tick. + * It requires a proper margin. Additionally, sys_clock_announce + * works within system tick boundaries (100us by default), + * which also introduces some shift. + */ + min-residency-us = <400>; + exit-latency-us = <300>; + }; }; }; @@ -582,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 2df24d0c8d2080f..cfd98d4bb4d75f4 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 000000000000000..0784e99265b4d31 --- /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 000000000000000..79491e4008b0ae8 --- /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 e47698a1deaa655..f8b5448a7880e38 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 d63ddd881baa5b4..551e3af6f3fbe4e 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 fccf74e73558ff2..b53203be760188c 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 5f37fc667dbf64e..bfa023d027d3e12 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 f9c26bb0ddea7a1..861c70f2d5b9d02 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 621214b080cfe19..f6a8ae129e005b6 100644 --- a/dts/arm/st/g0/stm32g0b1.dtsi +++ b/dts/arm/st/g0/stm32g0b1.dtsi @@ -14,7 +14,7 @@ clocks { clk_hsi48: clk-hsi48 { #clock-cells = <0>; - compatible = "fixed-clock"; + compatible = "st,stm32-hsi48-clock"; clock-frequency = ; status = "disabled"; }; @@ -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 feec71388aa9ac0..d42ff353a731bc8 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 97565c33e732ff7..0cdcc317f0a68b8 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 865d3700d96963a..1e616accc776e4c 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 d8a93a58619b376..dff30f083da6703 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 66ed8d3d927af05..1285f10b1ebe253 100644 --- a/dts/arm/st/h5/stm32h562.dtsi +++ b/dts/arm/st/h5/stm32h562.dtsi @@ -90,6 +90,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 +308,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 +317,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 58a01b962b2d0c4..64ccfbf7241ae76 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 f1b0836f6e83007..1a2b917bc1e01f8 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 7f85387ca06e662..8ff4353855ae0e2 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/h7/stm32h7b0.dtsi b/dts/arm/st/h7/stm32h7b0.dtsi new file mode 100644 index 000000000000000..043c3fee302f092 --- /dev/null +++ b/dts/arm/st/h7/stm32h7b0.dtsi @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Charles Dias + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* + * STM32H7B0 line contains the same peripherals as STM32H7A3, + * with addition of CRYPTO/HASH and OTFDEC peripherals. + */ +/ { + soc { + compatible = "st,stm32h7b0", "st,stm32h7", "simple-bus"; + + cryp: cryp@48021000 { + compatible = "st,stm32-cryp"; + reg = <0x48021000 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000010>; + interrupts = <79 0>; + interrupt-names = "cryp"; + status = "disabled"; + }; + }; +}; diff --git a/dts/arm/st/h7/stm32h7b0Xb.dtsi b/dts/arm/st/h7/stm32h7b0Xb.dtsi new file mode 100644 index 000000000000000..884e22edc8e928a --- /dev/null +++ b/dts/arm/st/h7/stm32h7b0Xb.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 Charles Dias + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +/ { + soc { + flash-controller@52002000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(128)>; + }; + }; + }; +}; diff --git a/dts/arm/st/h7/stm32h7b3.dtsi b/dts/arm/st/h7/stm32h7b3.dtsi index a104f58a192bd56..f8b583b9d751ee4 100644 --- a/dts/arm/st/h7/stm32h7b3.dtsi +++ b/dts/arm/st/h7/stm32h7b3.dtsi @@ -5,23 +5,13 @@ */ #include -#include +#include /* - * STM32H7B3 line contains the same peripherals as STM32H7A3, - * with addition of CRYPTO/HASH and OTFDEC peripherals + * STM32H7B3 line contains the same peripherals as STM32H7B0. */ / { soc { compatible = "st,stm32h7b3", "st,stm32h7", "simple-bus"; - - cryp: cryp@48021000 { - compatible = "st,stm32-cryp"; - reg = <0x48021000 0x400>; - clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000010>; - interrupts = <79 0>; - interrupt-names = "cryp"; - status = "disabled"; - }; }; }; diff --git a/dts/arm/st/l0/stm32l0.dtsi b/dts/arm/st/l0/stm32l0.dtsi index b05dbff210dfe96..7bb62de1f22f7be 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/stm32l010.dtsi b/dts/arm/st/l0/stm32l010.dtsi index db206db37217925..503bbf3bd0fe708 100644 --- a/dts/arm/st/l0/stm32l010.dtsi +++ b/dts/arm/st/l0/stm32l010.dtsi @@ -9,9 +9,5 @@ / { soc { compatible = "st,stm32l010", "st,stm32l0", "simple-bus"; - - eeprom: eeprom@8080000{ - reg = <0x08080000 512>; - }; }; }; diff --git a/dts/arm/st/l0/stm32l010X4.dtsi b/dts/arm/st/l0/stm32l010X4.dtsi new file mode 100644 index 000000000000000..e1e25f4d5dc68e2 --- /dev/null +++ b/dts/arm/st/l0/stm32l010X4.dtsi @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 OS Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(2)>; + }; + + soc { + eeprom: eeprom@8080000{ + reg = <0x08080000 128>; + }; + + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(16)>; + }; + }; + }; +}; diff --git a/dts/arm/st/l0/stm32l010X6.dtsi b/dts/arm/st/l0/stm32l010X6.dtsi new file mode 100644 index 000000000000000..df6ad2c514f29db --- /dev/null +++ b/dts/arm/st/l0/stm32l010X6.dtsi @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 OS Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(8)>; + }; + + soc { + eeprom: eeprom@8080000{ + reg = <0x08080000 256>; + }; + + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(32)>; + }; + }; + }; +}; diff --git a/dts/arm/st/l0/stm32l010X8.dtsi b/dts/arm/st/l0/stm32l010X8.dtsi new file mode 100644 index 000000000000000..2d0b4a2e220515c --- /dev/null +++ b/dts/arm/st/l0/stm32l010X8.dtsi @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 OS Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(8)>; + }; + + soc { + eeprom: eeprom@8080000{ + reg = <0x08080000 256>; + }; + + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(64)>; + }; + }; + }; +}; diff --git a/dts/arm/st/l0/stm32l010Xb.dtsi b/dts/arm/st/l0/stm32l010Xb.dtsi index 57433c87972f93b..9b35bbe9f7be0c9 100644 --- a/dts/arm/st/l0/stm32l010Xb.dtsi +++ b/dts/arm/st/l0/stm32l010Xb.dtsi @@ -13,6 +13,10 @@ }; soc { + eeprom: eeprom@8080000{ + reg = <0x08080000 512>; + }; + flash-controller@40022000 { flash0: flash@8000000 { reg = <0x08000000 DT_SIZE_K(128)>; diff --git a/dts/arm/st/l0/stm32l011X4.dtsi b/dts/arm/st/l0/stm32l011X4.dtsi index e42fa1af64cf851..e2d7b5eafd3c526 100644 --- a/dts/arm/st/l0/stm32l011X4.dtsi +++ b/dts/arm/st/l0/stm32l011X4.dtsi @@ -18,5 +18,9 @@ reg = <0x08000000 DT_SIZE_K(16)>; }; }; + + eeprom: eeprom@8080000{ + reg = <0x08080000 512>; + }; }; }; diff --git a/dts/arm/st/l0/stm32l051.dtsi b/dts/arm/st/l0/stm32l051.dtsi index e6209dc531bba01..9c5bfa1b02841eb 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 56d88c5bd51acc8..95a8fdc84249b4b 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/l0/stm32l081.dtsi b/dts/arm/st/l0/stm32l081.dtsi new file mode 100644 index 000000000000000..05a473a3e1bed7b --- /dev/null +++ b/dts/arm/st/l0/stm32l081.dtsi @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Caspar Friedrich + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + compatible = "st,stm32l081", "st,stm32l0", "simple-bus"; + }; +}; diff --git a/dts/arm/st/l0/stm32l081Xz.dtsi b/dts/arm/st/l0/stm32l081Xz.dtsi new file mode 100644 index 000000000000000..d6f28ceecceb490 --- /dev/null +++ b/dts/arm/st/l0/stm32l081Xz.dtsi @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Caspar Friedrich + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(20)>; + }; + + soc { + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(192)>; + }; + }; + }; +}; diff --git a/dts/arm/st/l1/stm32l1.dtsi b/dts/arm/st/l1/stm32l1.dtsi index 0203f740c8310ce..53dbd64492d248f 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 f2b8c1a2ff67343..7dcabdf877cd7cf 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 f516ccdc57cba4e..152340889fdf110 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 9a9892a0f4d0986..7fb1d7b4bd4e91f 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 c754097bec9810d..c0e1f0e18bee370 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 b566db4336ad505..c22e4ef0820a329 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 c1f5b5978a082ed..53a7fe28f02c230 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 12d74f6859bef60..4bba5f13ecced27 100644 --- a/dts/arm/st/l4/stm32l496.dtsi +++ b/dts/arm/st/l4/stm32l496.dtsi @@ -54,6 +54,7 @@ interrupts = <86 0>, <87 0>, <88 0>, <89 0>; interrupt-names = "TX", "RX0", "RX1", "SCE"; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x04000000>; //RCC_APB1ENR1_CAN2EN + master-can-reg = <0x40006400>; status = "disabled"; sample-point = <875>; }; @@ -81,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 03973dcf077d16a..648fa936a5fa9cb 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 c8c943193539957..f9c37b33cd8c5ed 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 f70a96b6ead4575..2eec4faa4da306c 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 7363181e6631872..43f4830bf729bdd 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 401aa5ace795abe..3bc16eb120e8f81 100644 --- a/dts/arm/st/u5/stm32u595.dtsi +++ b/dts/arm/st/u5/stm32u595.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 PSICONTROl nv + * Copyright (c) 2023 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -58,5 +59,58 @@ interrupt-names = "event", "error"; status = "disabled"; }; + + /* Available in STM32U59x/5Ax/5Fx/5Gx SoCs */ + adc2: adc@42028100 { + compatible = "st,stm32-adc"; + reg = <0x42028100 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000400>; + interrupts = <37 0>; + status = "disabled"; + #io-channel-cells = <1>; + resolutions = ; + sampling-times = <5 6 12 20 36 68 391 814>; + st,adc-clock-source = ; + st,adc-sequencer = ; + }; + + /* + * Available in STM32U59x/5Ax/5Fx/5Gx SoCs + * dual mode: adc1 and adc2 coupled + */ + adc1_2: adc@42028300 { + compatible = "st,stm32-adc"; + reg = <0x42028300 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000400>; + interrupts = <37 0>; + status = "disabled"; + #io-channel-cells = <1>; + resolutions = ; + sampling-times = <5 6 12 20 36 68 391 814>; + st,adc-clock-source = ; + 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/u5/stm32u5a9.dtsi b/dts/arm/st/u5/stm32u5a9.dtsi new file mode 100644 index 000000000000000..13cd1e1401d151f --- /dev/null +++ b/dts/arm/st/u5/stm32u5a9.dtsi @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + compatible = "st,stm32u5a9", "st,stm32u5", "simple-bus"; + }; +}; diff --git a/dts/arm/st/u5/stm32u5a9Xj.dtsi b/dts/arm/st/u5/stm32u5a9Xj.dtsi new file mode 100644 index 000000000000000..1b9b7cadd75e1f7 --- /dev/null +++ b/dts/arm/st/u5/stm32u5a9Xj.dtsi @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + sram0: memory@20000000 { + /* SRAM1 + SRAM2 + SRAM3 + SRAM5 */ + /* 768K + 64K + 832K + 832K */ + reg = <0x20000000 DT_SIZE_K(2496)>; + }; + sram1: memory@28000000 { + /* SRAM4, low-power background autonomous mode */ + reg = <0x28000000 DT_SIZE_K(16)>; + }; + + soc { + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_M(4)>; + }; + }; + }; +}; diff --git a/dts/arm/st/wb/stm32wb.dtsi b/dts/arm/st/wb/stm32wb.dtsi index 63687c09e8da782..d76f2f243f7435e 100644 --- a/dts/arm/st/wb/stm32wb.dtsi +++ b/dts/arm/st/wb/stm32wb.dtsi @@ -501,6 +501,14 @@ clocks = <&rcc STM32_CLOCK_BUS_AHB3 0x00040000>; status = "disabled"; }; + + aes1: aes@50060000 { + compatible = "st,stm32-aes"; + reg = <0x50060000 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00010000>; + interrupts = <51 0>; + status = "disabled"; + }; }; die_temp: dietemp { @@ -539,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 c93b042babfdb1c..4ae45491f7fc284 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -6,6 +6,7 @@ #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include @@ -20,6 +22,7 @@ chosen { zephyr,entropy = &rng; zephyr,flash-controller = &flash; + st,lptim-stdby-timer = &rtc; }; cpus { @@ -30,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>; }; }; @@ -54,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>; + }; }; }; @@ -61,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>; @@ -188,6 +206,14 @@ }; }; + rtc: rtc@46007800 { + compatible = "st,stm32-rtc"; + reg = <0x46007800 0x400>; + interrupts = <2 0>; + clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00200000>; + status = "disabled"; + }; + iwdg: watchdog@40003000 { compatible = "st,stm32-watchdog"; reg = <0x40003000 0x400>; @@ -425,11 +451,49 @@ 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"; }; + + gpdma1: dma@40020000 { + compatible = "st,stm32u5-dma"; + #dma-cells = <3>; + reg = <0x40020000 0x1000>; + interrupts = <29 0 30 0 31 0 32 0 33 0 34 0 35 0 36 0>; + clocks = <&rcc STM32_CLOCK_BUS_AHB1 0x1>; + dma-channels = <8>; + dma-requests = <52>; + dma-offset = <0>; + 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"; }; }; diff --git a/dts/arm/st/wba/stm32wba52.dtsi b/dts/arm/st/wba/stm32wba52.dtsi new file mode 100644 index 000000000000000..ef4f4d0f1808750 --- /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 f4ddcbbc9e73e4a..ecae645171b4aa5 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 000000000000000..b8a8c6125a705f5 --- /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 000000000000000..f5c23f031e95808 --- /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 85c40256e51c145..3dc4b3fcc3f390f 100644 --- a/dts/arm/st/wl/stm32wl.dtsi +++ b/dts/arm/st/wl/stm32wl.dtsi @@ -207,6 +207,18 @@ clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>; prescaler = <32768>; status = "disabled"; + + /* In STM32WL, the backup registers are defined as part of the TAMP + * peripheral. This peripheral is not implemented in Zephyr yet, however, + * the reference manual states that tamp_pclk is connected to rtc_pclk. + * It makes sense to have BBRAM instantiated as a child of RTC, so that + * the driver can verify that its parent device (RTC) is ready. + */ + bbram: backup_regs { + compatible = "st,stm32-bbram"; + st,backup-regs = <20>; + status = "disabled"; + }; }; iwdg: watchdog@40003000 { @@ -247,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"; }; @@ -510,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/ti/am62x_m4.dtsi b/dts/arm/ti/am62x_m4.dtsi index 22de7a14f82bfa8..8d5e5a14c40b8ba 100644 --- a/dts/arm/ti/am62x_m4.dtsi +++ b/dts/arm/ti/am62x_m4.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include / { @@ -54,6 +55,16 @@ reg-shift = <2>; status = "disabled"; }; + + gpio0: gpio@4201010 { + compatible = "ti,davinci-gpio"; + reg = <0x4201010 0x100>; + #address-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <24>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/xilinx/zynqmp.dtsi b/dts/arm/xilinx/zynqmp.dtsi index 84c1c574d22997e..65abc4505435767 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/broadcom/bcm2711.dtsi b/dts/arm64/broadcom/bcm2711.dtsi index 716e29006e7b42f..038d8dc4d6c7884 100644 --- a/dts/arm64/broadcom/bcm2711.dtsi +++ b/dts/arm64/broadcom/bcm2711.dtsi @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include +#include + #include #include @@ -19,9 +22,10 @@ }; }; + interrupt-parent = <&gic>; + timer { compatible = "arm,armv8-timer"; - interrupt-parent = <&gic>; interrupts = , ; + #address-cells = <1>; + #size-cells = <0>; + + /* GPIO 0 ~ 27 */ + gpio0: gpio@0 { + compatible = "brcm,bcm2711-gpio"; + reg = <0>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + ngpios = <28>; + status = "disabled"; + }; + + /* GPIO 28 ~ 45 */ + gpio1: gpio@1c { + compatible = "brcm,bcm2711-gpio"; + reg = <28>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + ngpios = <18>; + status = "disabled"; + }; + }; + uart1: uart@fe215040 { compatible = "brcm,bcm2711-aux-uart"; reg = <0xfe215040 0x40>; - clock-frequency = <500000000>; - interrupt-parent = <&gic>; + clock-frequency = ; interrupts = ; + IRQ_DEFAULT_PRIORITY>; status = "disabled"; }; }; diff --git a/dts/arm64/intel/intel_socfpga_agilex.dtsi b/dts/arm64/intel/intel_socfpga_agilex.dtsi index 19957a19988faf1..e3b3e9b17caa81e 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 6a98aa34df924f8..21cf2e68ed05ee7 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_mimx8mm_a53.dtsi b/dts/arm64/nxp/nxp_mimx8mm_a53.dtsi index 605729969db61e3..b7d80992d8ebe8a 100644 --- a/dts/arm64/nxp/nxp_mimx8mm_a53.dtsi +++ b/dts/arm64/nxp/nxp_mimx8mm_a53.dtsi @@ -17,7 +17,6 @@ chosen { zephyr,console = &uart2; zephyr,shell-uart = &uart2; - zephyr,sram = &sram0; }; cpus { diff --git a/dts/arm64/nxp/nxp_mimx8mn_a53.dtsi b/dts/arm64/nxp/nxp_mimx8mn_a53.dtsi index d76cc40438e1288..8902380f46a8bad 100644 --- a/dts/arm64/nxp/nxp_mimx8mn_a53.dtsi +++ b/dts/arm64/nxp/nxp_mimx8mn_a53.dtsi @@ -17,7 +17,6 @@ chosen { zephyr,console = &uart2; zephyr,shell-uart = &uart2; - zephyr,sram = &sram0; }; cpus { diff --git a/dts/arm64/nxp/nxp_mimx93_a55.dtsi b/dts/arm64/nxp/nxp_mimx93_a55.dtsi index 1e73bff224fb09f..4592209c902c745 100644 --- a/dts/arm64/nxp/nxp_mimx93_a55.dtsi +++ b/dts/arm64/nxp/nxp_mimx93_a55.dtsi @@ -7,19 +7,15 @@ #include #include #include -#include +#include +#include #include +#include / { #address-cells = <1>; #size-cells = <1>; - chosen { - zephyr,console = &uart2; - zephyr,shell-uart = &uart2; - zephyr,sram = &sram0; - }; - cpus { #address-cells = <1>; #size-cells = <0>; @@ -76,18 +72,58 @@ }; ccm: ccm@44450000 { - compatible = "nxp,imx-ccm"; + compatible = "nxp,imx-ccm-rev2"; reg = <0x44450000 DT_SIZE_K(64)>; #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)>; interrupts = ; interrupt-names = "irq_0"; interrupt-parent = <&gic>; - clocks = <&ccm IMX_CCM_LPUART_CLK 0x6c 24>; + clocks = <&ccm IMX_CCM_LPUART1_CLK 0x6c 24>; status = "disabled"; }; @@ -97,7 +133,311 @@ interrupts = ; interrupt-names = "irq_0"; interrupt-parent = <&gic>; - clocks = <&ccm IMX_CCM_LPUART_CLK 0x6c 24>; + 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/arm64/rockchip/rk3568.dtsi b/dts/arm64/rockchip/rk3568.dtsi new file mode 100644 index 000000000000000..360851987a2ed7b --- /dev/null +++ b/dts/arm64/rockchip/rk3568.dtsi @@ -0,0 +1,89 @@ +/* + * Copyright 2020 NXP + * Copyright 2022 HNU-ESNL + * Copyright 2022 openEuler SIG-Zephyr + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + + +/ { + #address-cells = <1>; + #size-cells = <1>; + + compatible = "rockchip,rk3568"; + interrupt-parent = <&gic>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@000 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + enable-method = "psci"; + reg = <0x000>; + }; + + cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + enable-method = "psci"; + reg = <0x100>; + }; + + cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + enable-method = "psci"; + reg = <0x200>; + + }; + + cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + enable-method = "psci"; + reg = <0x300>; + }; + }; + + gic: interrupt-controller@fd400000 { + #address-cells = <1>; + compatible = "arm,gic-v3","arm,gic"; + #interrupt-cells = <4>; + interrupt-controller; + + reg = <0xfd400000 0x10000>, /* GICD */ + <0xfd460000 0xc0000>; /* GICR */ + status = "okay"; + }; + + psci { + compatible = "arm,psci-0.2", "arm,psci"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + interrupt-parent = <&gic>; + }; + + uart2: serial@fe660000 { + compatible = "rockchip,rk3568-uart", "ns16550"; + reg = <0xfe660000 0x10000>; + interrupts = ; + clock-frequency = <12000000>; + reg-shift = <2>; + status = "disabled"; + }; + +}; diff --git a/dts/bindings/adc/adi,ad5592-adc.yaml b/dts/bindings/adc/adi,ad5592-adc.yaml new file mode 100644 index 000000000000000..2432b55d25a68c3 --- /dev/null +++ b/dts/bindings/adc/adi,ad5592-adc.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Grinn +# SPDX-License-Identifier: Apache-2.0 + +description: AD5592 ADC Controller + +compatible: "adi,ad5592-adc" + +include: adc-controller.yaml + +properties: + "#io-channel-cells": + const: 1 + +io-channel-cells: + - input diff --git a/dts/bindings/adc/espressif,esp32-adc.yaml b/dts/bindings/adc/espressif,esp32-adc.yaml index 2aedb107c7a25f1..d3907dba640839c 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 1cff8da2dd9d170..7ae64d8845af0da 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 4d1296b1c71bb94..0631ea303678cb6 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/lltc,ltc2451.yaml b/dts/bindings/adc/lltc,ltc2451.yaml new file mode 100644 index 000000000000000..b68f127337f7b93 --- /dev/null +++ b/dts/bindings/adc/lltc,ltc2451.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Brill Power Ltd. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +description: Linear Technology LTC2451 ADC + +compatible: "lltc,ltc2451" + +include: i2c-device.yaml + +properties: + conversion-speed: + type: int + enum: + - 30 + - 60 + description: Set conversion speed in Hz diff --git a/dts/bindings/adc/microchip,mcp320x-base.yaml b/dts/bindings/adc/microchip,mcp320x-base.yaml index c5d80c9a63732b1..9bee60f1320d7e4 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 000000000000000..66708431381cdec --- /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 4225c9b0cc347c2..8c0bb066b8028f6 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 00dfda33c034a8d..7fa232b815d1afd 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/nxp,imx-mu-rev2.yaml b/dts/bindings/arm/nxp,imx-mu-rev2.yaml deleted file mode 100644 index 7759e52293c7791..000000000000000 --- a/dts/bindings/arm/nxp,imx-mu-rev2.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2018, NXP -# SPDX-License-Identifier: Apache-2.0 - -description: i.MX Messaging Unit - -compatible: "nxp,imx-mu-rev2" - -include: base.yaml - -properties: - reg: - required: true - - interrupts: - required: true - - rdc: - type: int - required: true - description: Set the RDC permission for this peripheral diff --git a/dts/bindings/audio/nxp,dmic.yaml b/dts/bindings/audio/nxp,dmic.yaml new file mode 100644 index 000000000000000..77f1d0e74a7c865 --- /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 new file mode 100644 index 000000000000000..60c17fc7860ba4e --- /dev/null +++ b/dts/bindings/auxdisplay/sparkfun,serlcd.yaml @@ -0,0 +1,56 @@ +# Copyright (c) 2023 Jan Henke +# SPDX-License-Identifier: Apache-2.0 + +description: | + SparkFun SerLCD Dot Character VFD Controller/Driver IC + + Example: + &i2c1 { + serlcd@72 { + compatible = "sparkfun,serlcd"; + reg = <0x72>; + columns = <16>; + rows = <2>; + command-delay = <10>; + special-command-delay = <50>; + }; + }; + +compatible: "sparkfun,serlcd" + +include: [auxdisplay-device.yaml, i2c-device.yaml] + +properties: + columns: + type: int + default: 16 + enum: + - 16 + - 20 + + rows: + type: int + default: 2 + 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 000000000000000..0e2d1cad3b04eca --- /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/battery/battery.yaml b/dts/bindings/battery/battery.yaml new file mode 100644 index 000000000000000..90bb20532d4c49f --- /dev/null +++ b/dts/bindings/battery/battery.yaml @@ -0,0 +1,25 @@ +# Copyright 2023 Cirrus Logic, Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: | + Static Battery Characteristics + + Properties are inherited from Linux. See + linux/Documentation/devicetree/bindings/power/supply/battery.yaml + +properties: + precharge-current-microamp: + type: int + description: current for pre-charge phase + + charge-term-current-microamp: + type: int + description: current for charge termination phase + + constant-charge-current-max-microamp: + type: int + description: maximum constant input current + + constant-charge-voltage-max-microvolt: + type: int + description: maximum constant input voltage 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 000000000000000..42df66d2180941a --- /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 e45c7c3598359d5..25213af3ecc5ff4 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 000000000000000..3784c88ded047cb --- /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 000000000000000..36b25eae768946d --- /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/bluetooth/zephyr,bt-hci-spi.yaml b/dts/bindings/bluetooth/zephyr,bt-hci-spi.yaml index 1a5afdc647373df..50d0e311461b503 100644 --- a/dts/bindings/bluetooth/zephyr,bt-hci-spi.yaml +++ b/dts/bindings/bluetooth/zephyr,bt-hci-spi.yaml @@ -28,10 +28,10 @@ properties: type: int default: 20 description: - Duration to delay between reading a valid header and reading the data associated - with that header. This delay gives the controller time to configure the SPI data - transaction after finishing the header transaction. Without this delay the host - can attempt to read before the controller is ready, resulting in empty data that - then needs to be read a second time. The default of 20uS was chosen as the lowest - delay that reliably eliminated double transmits between a nRF9160 host and a - nRF52832 controller. + Duration to delay between reading a valid header and transceiving the data + associated with that header. This delay gives the controller time to configure + the SPI data transaction after finishing the header transaction. Without this + delay the host can attempt to read/write before the controller is ready, + resulting in an ignored transaction that then needs to be performed a second time. + The default of 20uS was chosen as the lowest delay that reliably eliminated double + transactions between a nRF9160 host and a nRF52832 controller. diff --git a/dts/bindings/can/atmel,sam-can.yaml b/dts/bindings/can/atmel,sam-can.yaml index 0d0dc268f4c502e..c224604fa0bd9c1 100644 --- a/dts/bindings/can/atmel,sam-can.yaml +++ b/dts/bindings/can/atmel,sam-can.yaml @@ -1,4 +1,4 @@ -description: Specialization of Bosch m_can CAN-FD controller for Atmel SAM +description: Specialization of Bosch m_can CAN FD controller for Atmel SAM compatible: "atmel,sam-can" @@ -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 0a70dfd9d5eafb0..7002386c9228da9 100644 --- a/dts/bindings/can/atmel,sam0-can.yaml +++ b/dts/bindings/can/atmel,sam0-can.yaml @@ -1,4 +1,4 @@ -description: Specialization of Bosch m_can CAN-FD controller for Atmel SAM0 +description: Specialization of Bosch m_can CAN FD controller for Atmel SAM0 compatible: "atmel,sam0-can" @@ -13,6 +13,9 @@ properties: interrupts: required: true + interrupt-names: + required: true + clocks: required: true diff --git a/dts/bindings/can/bosch,m_can-base.yaml b/dts/bindings/can/bosch,m_can-base.yaml index 1663cf82082e45f..0c59c671949f9bb 100644 --- a/dts/bindings/can/bosch,m_can-base.yaml +++ b/dts/bindings/can/bosch,m_can-base.yaml @@ -1,4 +1,4 @@ -description: Bosch M_CAN CAN-FD controller base +description: Bosch M_CAN CAN FD controller base include: [can-fd-controller.yaml] diff --git a/dts/bindings/can/can-fd-controller.yaml b/dts/bindings/can/can-fd-controller.yaml index beb9da9f7362cdf..3882518d6262f7b 100644 --- a/dts/bindings/can/can-fd-controller.yaml +++ b/dts/bindings/can/can-fd-controller.yaml @@ -1,4 +1,4 @@ -# Common fields for CAN-FD controllers +# Common fields for CAN FD controllers include: can-controller.yaml 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 000000000000000..8fa50922aced070 --- /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 000000000000000..66b0fb72a87c971 --- /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 3338f82e02a6627..b35cb0fa48a60ad 100644 --- a/dts/bindings/can/microchip,mcp251xfd.yaml +++ b/dts/bindings/can/microchip,mcp251xfd.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 description: | - Microchip MCP251XFD SPI CAN-FD controller + Microchip MCP251XFD SPI CAN FD controller The MCP251XFD node is defined on an SPI bus. An example configuration is: @@ -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 new file mode 100644 index 000000000000000..f70e86693c16216 --- /dev/null +++ b/dts/bindings/can/nuvoton,numaker-canfd.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton NuMaker CAN FD controller, using Bosch M_CAN IP + +compatible: "nuvoton,numaker-canfd" + +include: ["bosch,m_can-base.yaml", reset-device.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + interrupt-names: + required: true + + resets: + required: true + + clocks: + required: true diff --git a/dts/bindings/can/nxp,flexcan-fd.yaml b/dts/bindings/can/nxp,flexcan-fd.yaml index 890cbd8de94e473..72c36292cc0c664 100644 --- a/dts/bindings/can/nxp,flexcan-fd.yaml +++ b/dts/bindings/can/nxp,flexcan-fd.yaml @@ -4,7 +4,7 @@ description: | NXP FlexCAN CANFD controller. - This is a specialization of the NXP FlexCAN CAN controller with support for CAN-FD. + This is a specialization of the NXP FlexCAN CAN controller with support for CAN FD. Example: flexcan3: can@401d8000 { diff --git a/dts/bindings/can/nxp,lpc-mcan.yaml b/dts/bindings/can/nxp,lpc-mcan.yaml index 65a06baea873eef..48aef0031396c81 100644 --- a/dts/bindings/can/nxp,lpc-mcan.yaml +++ b/dts/bindings/can/nxp,lpc-mcan.yaml @@ -1,4 +1,4 @@ -description: NXP LPC SoC series MCAN CAN-FD controller +description: NXP LPC SoC series MCAN CAN FD controller compatible: "nxp,lpc-mcan" @@ -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 36a38d97ca3280f..f4cfb310dac60f9 100644 --- a/dts/bindings/can/st,stm32-fdcan.yaml +++ b/dts/bindings/can/st,stm32-fdcan.yaml @@ -1,4 +1,4 @@ -description: ST STM32 FDCAN CAN-FD controller +description: ST STM32 FDCAN CAN FD controller compatible: "st,stm32-fdcan" @@ -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 5679141fe8e46f2..14f6fad61c568ec 100644 --- a/dts/bindings/can/st,stm32h7-fdcan.yaml +++ b/dts/bindings/can/st,stm32h7-fdcan.yaml @@ -1,4 +1,4 @@ -description: ST STM32H7 series FDCAN CAN-FD controller +description: ST STM32H7 series FDCAN CAN FD controller compatible: "st,stm32h7-fdcan" @@ -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/ti,tcan4x5x.yaml b/dts/bindings/can/ti,tcan4x5x.yaml index 567a158a2053cf6..8f57f66ae85ed58 100644 --- a/dts/bindings/can/ti,tcan4x5x.yaml +++ b/dts/bindings/can/ti,tcan4x5x.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 description: | - Texas Instruments TCAN4x5x SPI CAN-FD controller. + Texas Instruments TCAN4x5x SPI CAN FD controller. Example: &spi0 { 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 000000000000000..4175617403b34f1 --- /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 275019a2c9e079a..000000000000000 --- 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/maxim,max20335-charger.yaml b/dts/bindings/charger/maxim,max20335-charger.yaml new file mode 100644 index 000000000000000..f830e03cec5d979 --- /dev/null +++ b/dts/bindings/charger/maxim,max20335-charger.yaml @@ -0,0 +1,15 @@ +# Copyright (c), 2023 Grinn +# SPDX -License-Identifier: Apache-2.0 + +description: Maxim MAX20335 battery charger + +include: battery.yaml + +compatible: "maxim,max20335-charger" + +properties: + constant-charge-current-max-microamp: + required: true + + constant-charge-voltage-max-microvolt: + required: true diff --git a/dts/bindings/charger/ti,bq24190.yaml b/dts/bindings/charger/ti,bq24190.yaml new file mode 100644 index 000000000000000..6ff662c9c5850e6 --- /dev/null +++ b/dts/bindings/charger/ti,bq24190.yaml @@ -0,0 +1,15 @@ +# Copyright 2023 Cirrus Logic, Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: Texas Instruments family of BQ24190 of charging ICs + +include: [battery.yaml, i2c-device.yaml] + +compatible: "ti,bq24190" + +properties: + constant-charge-current-max-microamp: + required: true + + constant-charge-voltage-max-microvolt: + required: true diff --git a/dts/bindings/charger/ti,bq25180.yaml b/dts/bindings/charger/ti,bq25180.yaml new file mode 100644 index 000000000000000..be3b336aa50e9b4 --- /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/ambiq,clkctrl.yaml b/dts/bindings/clock/ambiq,clkctrl.yaml new file mode 100644 index 000000000000000..e1b3f9534b3de9f --- /dev/null +++ b/dts/bindings/clock/ambiq,clkctrl.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Ambiq Micro Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: Ambiq Apollo Series SoC Clock Controller + +compatible: "ambiq,clkctrl" + +include: [clock-controller.yaml, pinctrl-device.yaml, base.yaml] + +properties: + clock-frequency: + type: int + description: output clock frequency (Hz) + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + "#clock-cells": + const: 1 diff --git a/dts/bindings/clock/microchip,xec-pcr.yaml b/dts/bindings/clock/microchip,xec-pcr.yaml index 5a07aec6d40a8cc..00acde17ff8a66a 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 000000000000000..dc99c67e5cc2f55 --- /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-lfxo.yaml b/dts/bindings/clock/nordic,nrf-lfxo.yaml new file mode 100644 index 000000000000000..f0090ff4a814979 --- /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/nxp,imx-ccm.yaml b/dts/bindings/clock/nxp,imx-ccm.yaml index 9ddda734e8144be..f328b6f034a725c 100644 --- a/dts/bindings/clock/nxp,imx-ccm.yaml +++ b/dts/bindings/clock/nxp,imx-ccm.yaml @@ -8,9 +8,6 @@ compatible: "nxp,imx-ccm" include: [clock-controller.yaml, base.yaml] properties: - reg: - required: true - "#clock-cells": const: 3 diff --git a/dts/bindings/clock/pwm-clock.yaml b/dts/bindings/clock/pwm-clock.yaml new file mode 100644 index 000000000000000..d377aa0fb2b4f05 --- /dev/null +++ b/dts/bindings/clock/pwm-clock.yaml @@ -0,0 +1,54 @@ +# Copyright (c) 2023 Andriy Gelman +# SPDX-License-Identifier: Apache-2.0 + +description: | + An external clock signal driven by a PWM pin. + + The devicetree must define a clock node: + + pwmclock: pwmclock { + status = "okay"; + compatible = "pwm-clock"; + #clock-cells = <1>; + pwms = <&pwm_ccu40 2 PWM_HZ(1000000) PWM_POLARITY_NORMAL>; + }; + + This will create a device node with a clock-controller + API. Internally the device node will use PWM API to start the + clock signals at 1MHz. Note that the PWM_HZ() macro converts the + frequency to time (nanoseconds units). This may result in rounding + errors if the clock frequency is not an integer number of nanoseconds. + The clock frequency can be explicitly set using the clock-frequency + property. + + The PWM node may need to be properly configured to generate + the target period (i.e. using prescaler options). See the documentation + for the target PWM driver. + +compatible: "pwm-clock" + +include: [clock-controller.yaml, base.yaml] + +properties: + pwms: + type: phandle-array + required: true + + clock-frequency: + type: int + description: | + Exact output frequency, in case the PWM period is not exact + but was rounded to nanoseconds. This property is optional. + + pwm-on-delay: + type: int + default: 0 + description: + Optional blocking delay in micro seconds to make sure that the PWM + clock has started after returning from clock_control_on(). + + "#clock-cells": + const: 1 + +clock-cells: + - id 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 000000000000000..a4f8557e8caba76 --- /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 000000000000000..c787f3c7e819666 --- /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 000000000000000..d3859802c7dda75 --- /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 000000000000000..79058bc75c3f6c6 --- /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 000000000000000..89d3fa6fdfeff49 --- /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 new file mode 100644 index 000000000000000..2769a02ce2dfbbb --- /dev/null +++ b/dts/bindings/clock/renesas,ra-clock-generation-circuit.yaml @@ -0,0 +1,46 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RA series Clock Generation Circuit + +compatible: "renesas,ra-clock-generation-circuit" + +include: [clock-controller.yaml, base.yaml] + +properties: + reg: + required: true + + iclk-div: + type: int + description: Division factor for ICLK + + fclk-div: + type: int + description: Division factor for FCLK + + pclka-div: + type: int + description: Division factor for PCLKA + + pclkb-div: + type: int + description: Division factor for PCLKB + + pclkc-div: + type: int + description: Division factor for PCLKC + + pclkd-div: + type: int + description: Division factor for PCLKD + + clock-source: + type: phandle + description: System clock source + + "#clock-cells": + const: 1 + +clock-cells: + - id diff --git a/dts/bindings/clock/silabs,hfxo.yaml b/dts/bindings/clock/silabs,hfxo.yaml new file mode 100644 index 000000000000000..a5d0fdeff9515b9 --- /dev/null +++ b/dts/bindings/clock/silabs,hfxo.yaml @@ -0,0 +1,13 @@ +compatible: "silabs,hfxo" + +include: fixed-clock.yaml + +properties: + ctune: + 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 833a393595d676b..45cfa050c50bdf7 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-hsi48-clock.yaml b/dts/bindings/clock/st,stm32-hsi48-clock.yaml new file mode 100644 index 000000000000000..f8bcc88691b4986 --- /dev/null +++ b/dts/bindings/clock/st,stm32-hsi48-clock.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2023, Aurelien Jarno +# SPDX-License-Identifier: Apache-2.0 + +description: STM32 HSI48 Clock + +compatible: "st,stm32-hsi48-clock" + +include: [fixed-clock.yaml] + +properties: + crs-usb-sof: + type: boolean + description: | + Clock Recovery System using USB SOF packet reception + Set the property to enable clock recovery of the HSI48 oscillator using + the USB SOF packet reception as a reference. diff --git a/dts/bindings/clock/st,stm32-rcc.yaml b/dts/bindings/clock/st,stm32-rcc.yaml index 94aafc01a8509c9..ebc6b7e84e3f1ac 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 5b30f52d3e5c74d..04c9a8e295436e4 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 a503e247172ddeb..d2f01e8989b52a4 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 5e9825129f722c5..ca0e57dc7193e86 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 137a15822ac3a04..1346ec8a55fd45b 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 d85ba13ad207bf0..797c366da11efa2 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 c1bc2199b79e458..f765efc264e5aa9 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 000000000000000..633ca5557a3c8ba --- /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/counter/nxp,mrt-channel.yaml b/dts/bindings/counter/nxp,mrt-channel.yaml new file mode 100644 index 000000000000000..c3ab744fc5a878f --- /dev/null +++ b/dts/bindings/counter/nxp,mrt-channel.yaml @@ -0,0 +1,15 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + NXP Multirate Timer Channel + + Must be a child node of an nxp,mrt compatible node. + +compatible: "nxp,mrt-channel" + +include: base.yaml + +properties: + reg: + required: true diff --git a/dts/bindings/counter/nxp,mrt.yaml b/dts/bindings/counter/nxp,mrt.yaml new file mode 100644 index 000000000000000..e9e05b6c5b5b066 --- /dev/null +++ b/dts/bindings/counter/nxp,mrt.yaml @@ -0,0 +1,28 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP Multirate Timer + +compatible: "nxp,mrt" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + num-channels: + type: int + required: true + description: Number of channels on the IP version + + num-bits: + type: int + required: true + description: Timer width in bits of IP version + + clocks: + required: true diff --git a/dts/bindings/cpu/andes,andescore-v5.yaml b/dts/bindings/cpu/andes,andescore-v5.yaml new file mode 100644 index 000000000000000..d535b1dfd971a40 --- /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 000000000000000..ff0d6e2a4201fe0 --- /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 000000000000000..86de7c7a9c00829 --- /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 000000000000000..051284f703fed23 --- /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/nuclei,bumblebee.yaml b/dts/bindings/cpu/nuclei,bumblebee.yaml index 8c9dfc7d35d8b47..96eebcd0fb8d2f6 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 000000000000000..9bcb53c9e893826 --- /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 000000000000000..33fe84508990680 --- /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 000000000000000..2a0bbbfd58c5a99 --- /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/crypto/renesas,smartbond-crypto.yaml b/dts/bindings/crypto/renesas,smartbond-crypto.yaml new file mode 100644 index 000000000000000..7bee8dd4f9b8a7d --- /dev/null +++ b/dts/bindings/crypto/renesas,smartbond-crypto.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +include: base.yaml + +description: Renesas SmartBond(tm) CRYPTO + +compatible: "renesas,smartbond-crypto" + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/bindings/dac/adi,ad5592-dac.yaml b/dts/bindings/dac/adi,ad5592-dac.yaml new file mode 100644 index 000000000000000..3ac8087b91da562 --- /dev/null +++ b/dts/bindings/dac/adi,ad5592-dac.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Grinn +# SPDX-License-Identifier: Apache-2.0 + +description: AD5592 DAC Controller + +compatible: "adi,ad5592-dac" + +include: dac-controller.yaml + +properties: + "#io-channel-cells": + const: 1 + +io-channel-cells: + - output diff --git a/dts/bindings/dac/atmel,sam-dac.yaml b/dts/bindings/dac/atmel,sam-dac.yaml index 6b650d2bec12ef5..6775164363faacc 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 000000000000000..ae9cd201880f6e0 --- /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 000000000000000..fbfa6009a8a6bec --- /dev/null +++ b/dts/bindings/display/galaxycore,gc9x01x.yaml @@ -0,0 +1,149 @@ +# 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>; + pixel-format = ; + }; + }; + + +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 37cf5999cd9344a..a2afb6d39839c27 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/nxp,imx-elcdif.yaml b/dts/bindings/display/nxp,imx-elcdif.yaml index 5f9807bfdcfb133..a5ef4f13ded86c6 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/ultrachip,uc8175.yaml b/dts/bindings/display/ultrachip,uc8175.yaml new file mode 100644 index 000000000000000..8c89c86aded7968 --- /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 new file mode 100644 index 000000000000000..4c0020dd69d7713 --- /dev/null +++ b/dts/bindings/dma/andestech,atcdmac300.yaml @@ -0,0 +1,84 @@ +# +# Copyright (c) 2023 Andes Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +compatible: "andestech,atcdmac300" + +include: dma-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + chain-transfer: + type: int + + "#dma-cells": + const: 3 + +dma-cells: + - channel + - slot + - channel-config + +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 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) + 0x0: MEM to MEM + 0x1: MEM to PERIPH + 0x2: PERIPH to MEM + 0x3: reserved for PERIPH to PERIPH + -bit 2 : Peripheral Increment Address + 0x0: no address increment between transfers + 0x1: increment address between transfers + -bit 3 : Memory Increment Address + 0x0: no address increment between transfers + 0x1: increment address between transfers + -bit 4-6 : Peripheral data size + 0x0: Byte (8 bits) + 0x1: Half-word (16 bits) + 0x2: Word (32 bits) + 0x3: Double word (64 bits) + 0x4: Quad word (128 bits) + 0x5: Eight word (256 bits) + 0x6-0x7: reserved + -bit 7-9 : Memory data size + 0x0: Byte (8 bits) + 0x1: Half-word (16 bits) + 0x2: Word (32 bits) + 0x3: Double word (64 bits) + 0x4: Quad word (128 bits) + 0x5: Eight word (256 bits) + 0x6-0x7: reserved + -bit 10 : Priority level + 0x0: lower priority + 0x1: higher priority + + examples for andes_v5_ae350 DMA instance + dma0: dma0@f0c00000 { + compatible = "andestech,atcdmac300"; + ... + dma-channels = <8>; + dma-requests = <16>; + status = "disabled"; + label = "DMA_0"; + }; + + For the client part, example for andes_ae350 DMA instance + Tx using channel 2, slot 0 + Rx using channel 3, slot 1 + spi1: spi@f0f00000 { + compatible = "andestech,atcspi200" + dmas = <&dma0 2 0 0x0129>, + <&dma0 3 1 0x012A>; + dma-names = "tx", "rx"; + }; diff --git a/dts/bindings/dma/intel,lpss.yaml b/dts/bindings/dma/intel,lpss.yaml index 5f1954216f0234f..d9fc4a60f1140cd 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/intel,sedi_dma.yaml b/dts/bindings/dma/intel,sedi_dma.yaml new file mode 100644 index 000000000000000..3fe1036c00c9f37 --- /dev/null +++ b/dts/bindings/dma/intel,sedi_dma.yaml @@ -0,0 +1,21 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: Intel SEDI DMA controller. + +compatible: "intel,sedi_dma" + +include: dma-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + peripheral-id: + type: int + description: Peripheral Instance ID + required: true diff --git a/dts/bindings/dma/nxp,edma.yaml b/dts/bindings/dma/nxp,edma.yaml new file mode 100644 index 000000000000000..5c3305cb7dd4a25 --- /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/nxp,sof-host-dma.yaml b/dts/bindings/dma/nxp,sof-host-dma.yaml new file mode 100644 index 000000000000000..ebb03c46d8bf0fc --- /dev/null +++ b/dts/bindings/dma/nxp,sof-host-dma.yaml @@ -0,0 +1,12 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP SOF host DMA node + +compatible: "nxp,sof-host-dma" + +include: [base.yaml, dma-controller.yaml] + +properties: + dma-channels: + required: true diff --git a/dts/bindings/dma/renesas,smartbond-dma.yaml b/dts/bindings/dma/renesas,smartbond-dma.yaml new file mode 100644 index 000000000000000..0845df77463249e --- /dev/null +++ b/dts/bindings/dma/renesas,smartbond-dma.yaml @@ -0,0 +1,21 @@ +# Copyright (c) 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +include: dma-controller.yaml + +description: Renesas Smartbond(tm) DMA + +compatible: "renesas,smartbond-dma" + +properties: + reg: + required: true + + interrupts: + required: true + + block-count: + required: true + type: int + const: 1 + description: Number of block counts supported diff --git a/dts/bindings/dma/st,stm32-dma-v1.yaml b/dts/bindings/dma/st,stm32-dma-v1.yaml index 8e33887dacef649..c4658e6b30e9158 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 38e968c1a3b4466..632ff53a90b3b89 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 5ce00b952901992..84d5e8668e46f2a 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 000000000000000..b055062cb7243fe --- /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/dsa/microchip_dsa.yaml b/dts/bindings/dsa/microchip_dsa.yaml index 8762fec748ced66..4a607b11ae42c8f 100644 --- a/dts/bindings/dsa/microchip_dsa.yaml +++ b/dts/bindings/dsa/microchip_dsa.yaml @@ -12,16 +12,6 @@ properties: dsa-slave-ports: type: int description: Number of slave ports on the switch - spi-cpha: - type: boolean - description: | - Set to indicate phase starts with asserted half-phase (CPHA=1). - For this driver using this property requires also using cpol. - spi-cpol: - type: boolean - description: | - Set to indicate clock leading edge is falling (CPOL=1). - For this driver using this property requires also using cpha. reset-gpios: type: phandle-array description: | 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 000000000000000..115f8e5e4a470e2 --- /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 ebce305a3affc72..e53c3acb94b4ed1 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 f17d78df696f18b..0975647e1875c6d 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 3ffd12cdc5009d5..df063fd57a8a88e 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 a5a9cec2700c6d9..8823459d3a9ebc7 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 000000000000000..c526fe89055e3f5 --- /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 000000000000000..83a6be9f72d99b0 --- /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/microchip,lan865x.yaml b/dts/bindings/ethernet/microchip,lan865x.yaml new file mode 100644 index 000000000000000..699bfca7dc600bb --- /dev/null +++ b/dts/bindings/ethernet/microchip,lan865x.yaml @@ -0,0 +1,46 @@ +# Copyright (c) 2023 DENX Software Engineering GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: | + LAN865x standalone 10BASE-T1L Ethernet controller with SPI interface. + +compatible: "microchip,lan865x" + +include: [spi-device.yaml, ethernet-controller.yaml] + +properties: + tx-cut-through-mode: + type: boolean + description: Enable TX cut through mode + rx-cut-through-mode: + type: boolean + description: Enable RX cut through mode + plca-enable: + type: boolean + description: Enable or disable PLCA support + plca-node-id: + type: int + description: Specify the PLCA node ID number + plca-node-count: + type: int + description: Specify the PLCA node count + plca-burst-count: + type: int + description: Specify the PLCA burst count + plca-burst-timer: + type: int + description: Specify the PLCA burst timer value + plca-to-timer: + type: int + description: Specify the PLCA to timer value + int-gpios: + type: phandle-array + required: true + description: | + The interrupt pin of LAN865X is active low. + If connected directly the MCU pin should be configured + as active low. + rst-gpios: + type: phandle-array + required: true + description: The reset pin of LAN865X. diff --git a/dts/bindings/ethernet/nuvoton,numaker-ethernet.yaml b/dts/bindings/ethernet/nuvoton,numaker-ethernet.yaml new file mode 100644 index 000000000000000..4cdf35c4f60ae07 --- /dev/null +++ b/dts/bindings/ethernet/nuvoton,numaker-ethernet.yaml @@ -0,0 +1,30 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, NuMaker Ethernet controller + +compatible: "nuvoton,numaker-ethernet" + +include: + - ethernet-controller.yaml + - ethernet,fixed-link.yaml + - reset-device.yaml + - pinctrl-device.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + resets: + required: true + + clocks: + required: true + + phy-addr: + type: int + description: Address of the phy controller + required: true diff --git a/dts/bindings/ethernet/nxp,enet-mac.yaml b/dts/bindings/ethernet/nxp,enet-mac.yaml new file mode 100644 index 000000000000000..8ca42e769f3cacf --- /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 000000000000000..f77e30b30357d01 --- /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 000000000000000..f98af9f002b50c8 --- /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 357a5eb15212d55..7767a755f39d846 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 000000000000000..a15c9be3aba6698 --- /dev/null +++ b/dts/bindings/ethernet/nxp,tja1103.yaml @@ -0,0 +1,24 @@ +# 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 + + 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 a4c16094b08d0d3..90cff14f2601851 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/ambiq,flash-controller.yaml b/dts/bindings/flash_controller/ambiq,flash-controller.yaml new file mode 100644 index 000000000000000..60cb1dee81b1533 --- /dev/null +++ b/dts/bindings/flash_controller/ambiq,flash-controller.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023, Ambiq Micro Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: Ambiq flash controller + +compatible: "ambiq,flash-controller" + +include: flash-controller.yaml diff --git a/dts/bindings/flash_controller/atmel,sam-flash-controller.yaml b/dts/bindings/flash_controller/atmel,sam-flash-controller.yaml index 64a84a03758b502..80257970fad532b 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 000000000000000..c588c1837fe2576 --- /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/gnss/gnss-nmea-generic.yaml b/dts/bindings/gnss/gnss-nmea-generic.yaml new file mode 100644 index 000000000000000..a3887995e106993 --- /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/gnss-pps.yaml b/dts/bindings/gnss/gnss-pps.yaml new file mode 100644 index 000000000000000..5ec554b69e2bf52 --- /dev/null +++ b/dts/bindings/gnss/gnss-pps.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +properties: + pps-mode: + type: string + required: true + description: | + PPS output mode: + - GNSS_PPS_MODE_DISABLED: Output disabled + - GNSS_PPS_MODE_ENABLED: Output always enabled + - GNSS_PPS_MODE_ENABLED_AFTER_LOCK: Output enabled from first lock + - GNSS_PPS_MODE_ENABLED_WHILE_LOCKED: Output enabled only while locked + enum: + - GNSS_PPS_MODE_DISABLED + - GNSS_PPS_MODE_ENABLED + - GNSS_PPS_MODE_ENABLED_AFTER_LOCK + - GNSS_PPS_MODE_ENABLED_WHILE_LOCKED + + pps-pulse-width: + type: int + description: 1PPS pulse width + default: 100 diff --git a/dts/bindings/gnss/quectel,lc26g.yaml b/dts/bindings/gnss/quectel,lc26g.yaml new file mode 100644 index 000000000000000..bfb278147c6e3a8 --- /dev/null +++ b/dts/bindings/gnss/quectel,lc26g.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Trackunit Corporation +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +description: Quectel LC26G GNSS modem + +compatible: "quectel,lc26g" + +include: + - uart-device.yaml + - gnss-pps.yaml diff --git a/dts/bindings/gnss/quectel,lc76g.yaml b/dts/bindings/gnss/quectel,lc76g.yaml new file mode 100644 index 000000000000000..45c1da2fbaefe35 --- /dev/null +++ b/dts/bindings/gnss/quectel,lc76g.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Trackunit Corporation +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +description: Quectel LC76G GNSS modem + +compatible: "quectel,lc76g" + +include: + - uart-device.yaml + - gnss-pps.yaml diff --git a/dts/bindings/gnss/quectel,lc86g.yaml b/dts/bindings/gnss/quectel,lc86g.yaml new file mode 100644 index 000000000000000..a3b762149d98f58 --- /dev/null +++ b/dts/bindings/gnss/quectel,lc86g.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Trackunit Corporation +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +description: Quectel LC86G GNSS modem + +compatible: "quectel,lc86g" + +include: + - uart-device.yaml + - gnss-pps.yaml diff --git a/dts/bindings/gpio/adi,ad5592-gpio.yaml b/dts/bindings/gpio/adi,ad5592-gpio.yaml new file mode 100644 index 000000000000000..b815f557c51877e --- /dev/null +++ b/dts/bindings/gpio/adi,ad5592-gpio.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Grinn +# SPDX-License-Identifier: Apache-2.0 + +description: AD5592 GPIO Controller + +compatible: "adi,ad5592-gpio" + +include: gpio-controller.yaml + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/gpio/ambiq,gpio-bank.yaml b/dts/bindings/gpio/ambiq,gpio-bank.yaml new file mode 100644 index 000000000000000..8d9114acc5b8e5a --- /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 000000000000000..9ce7c7c87794dc4 --- /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 000000000000000..b082bc0ae58e586 --- /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/brcm,bcm2711-gpio.yaml b/dts/bindings/gpio/brcm,bcm2711-gpio.yaml new file mode 100644 index 000000000000000..9237ee6dfc5cf8e --- /dev/null +++ b/dts/bindings/gpio/brcm,bcm2711-gpio.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2023 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +description: BCM2711 GPIO + +compatible: "brcm,bcm2711-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/gpio/infineon,tle9104.yaml b/dts/bindings/gpio/infineon,tle9104.yaml new file mode 100644 index 000000000000000..cb82ecbde92c4b2 --- /dev/null +++ b/dts/bindings/gpio/infineon,tle9104.yaml @@ -0,0 +1,49 @@ +# +# Copyright (c) 2023 SILA Embedded Solutions GmbH +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Infineon TLE9104 4-channel powertrain switch + +compatible: "infineon,tle9104" + +include: [gpio-controller.yaml, spi-device.yaml] + +properties: + "#gpio-cells": + const: 2 + + ngpios: + type: int + required: true + const: 4 + description: Number of GPIOs supported + + en-gpios: + type: phandle-array + description: "GPIO for enable" + + resn-gpios: + type: phandle-array + description: "GPIO for reset" + + in1-gpios: + type: phandle-array + description: "GPIO for controlling OUT1" + + in2-gpios: + type: phandle-array + description: "GPIO for controlling OUT2" + + in3-gpios: + type: phandle-array + description: "GPIO for controlling OUT3" + + in4-gpios: + type: phandle-array + description: "GPIO for controlling OUT4" + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/gpio/ite,it8xxx2-gpio-v2.yaml b/dts/bindings/gpio/ite,it8xxx2-gpio-v2.yaml index 7c77e610a2375b2..744365cc5a396e5 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 000000000000000..ddb0c38f82c08d3 --- /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,mbus-header.yaml b/dts/bindings/gpio/m5stack,mbus-header.yaml new file mode 100644 index 000000000000000..2ad85dd7a647be5 --- /dev/null +++ b/dts/bindings/gpio/m5stack,mbus-header.yaml @@ -0,0 +1,28 @@ +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +description: | + GPIO pins exposed on M5Stack M-Bus headers. + + This binding provides a nexus mapping for 30 pins as depicted below. + + 0 GND 1 ADC0 + 2 GND 3 ADC1 + 4 GND 5 RESET + 6 MOSI 7 DAC0 + 8 MISO 9 DAC1 + 10 SCK 11 3.3V + 12 RXD0 13 TXD0 + 14 RXD1 15 TXD1 + 16 intSDA 17 intSCL + 18 SDA 19 SCL + 20 GPIO 21 GPIO + 22 GPIO 23 GPIO + 24 NC 25 GPIO + 26 NC 27 5V + 28 NC 29 BAT + + +compatible: "m5stack,mbus-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 000000000000000..a04fb9997ba2942 --- /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 550acd1a865cfe8..097a99d8fa94b0f 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 49ddba3595ba42f..cefc3385afef8b2 100644 --- a/dts/bindings/gpio/nordic,nrf-gpiote.yaml +++ b/dts/bindings/gpio/nordic,nrf-gpiote.yaml @@ -13,3 +13,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 000000000000000..eaa4e08374e48cc --- /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 96cb2409c16b4f1..000000000000000 --- 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 000000000000000..868ba5205713f10 --- /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/renesas,ra-gpio.yaml b/dts/bindings/gpio/renesas,ra-gpio.yaml new file mode 100644 index 000000000000000..ad18a0d45dae774 --- /dev/null +++ b/dts/bindings/gpio/renesas,ra-gpio.yaml @@ -0,0 +1,83 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RA series GPIO + +compatible: "renesas,ra-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + port-irq0-pins: + type: array + description: Pins allow to assign port-irq0 + + port-irq1-pins: + type: array + description: Pins allow to assign port-irq1 + + port-irq2-pins: + type: array + description: Pins allow to assign port-irq2 + + port-irq3-pins: + type: array + description: Pins allow to assign port-irq3 + + port-irq4-pins: + type: array + description: Pins allow to assign port-irq4 + + port-irq5-pins: + type: array + description: Pins allow to assign port-irq5 + + port-irq6-pins: + type: array + description: Pins allow to assign port-irq6 + + port-irq7-pins: + type: array + description: Pins allow to assign port-irq7 + + port-irq8-pins: + type: array + description: Pins allow to assign port-irq8 + + port-irq9-pins: + type: array + description: Pins allow to assign port-irq9 + + port-irq10-pins: + type: array + description: Pins allow to assign port-irq10 + + port-irq11-pins: + type: array + description: Pins allow to assign port-irq11 + + port-irq12-pins: + type: array + description: Pins allow to assign port-irq12 + + port-irq13-pins: + type: array + description: Pins allow to assign port-irq13 + + port-irq14-pins: + type: array + description: Pins allow to assign port-irq14 + + port-irq15-pins: + type: array + description: Pins allow to assign port-irq15 + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/gpio/renesas,rzt2m-gpio.yaml b/dts/bindings/gpio/renesas,rzt2m-gpio.yaml new file mode 100644 index 000000000000000..e099c81753e1704 --- /dev/null +++ b/dts/bindings/gpio/renesas,rzt2m-gpio.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 +description: Renesas RZT2M GPIO + +compatible: "renesas,rzt2m-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#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 446cde37a5511ba..7e1b6b8920609c3 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 486953428b4e71d..205b44ce83b9990 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 000000000000000..1ced649632bebb8 --- /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,davinci-gpio-nexus.yaml b/dts/bindings/gpio/ti,davinci-gpio-nexus.yaml index 3cfccfa5ee32343..1b38fe927ca223a 100644 --- a/dts/bindings/gpio/ti,davinci-gpio-nexus.yaml +++ b/dts/bindings/gpio/ti,davinci-gpio-nexus.yaml @@ -7,7 +7,7 @@ description: GPIO controller for Davinci and Keystone devices compatible: "ti,davinci-gpio-nexus" -include: [base.yaml, gpio-nexus.yaml] +include: [base.yaml, gpio-nexus.yaml, pinctrl-device.yaml] properties: "#gpio-cells": diff --git a/dts/bindings/gpio/ti,davinci-gpio.yaml b/dts/bindings/gpio/ti,davinci-gpio.yaml index 0472dfa1aa13775..64c0bbd5db56e82 100644 --- a/dts/bindings/gpio/ti,davinci-gpio.yaml +++ b/dts/bindings/gpio/ti,davinci-gpio.yaml @@ -7,7 +7,7 @@ description: GPIO controller for Davinci and Keystone devices. compatible: "ti,davinci-gpio" -include: [gpio-controller.yaml, base.yaml] +include: [base.yaml, gpio-controller.yaml, pinctrl-device.yaml] properties: reg: diff --git a/dts/bindings/gpio/ti,tca9538.yaml b/dts/bindings/gpio/ti,tca9538.yaml index 6cb235995abd6c7..9200a9a16061a3a 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/i2c/atmel,sam-i2c-twim.yaml b/dts/bindings/i2c/atmel,sam-i2c-twim.yaml index 1b865d256ca33ea..90c5c6e83881250 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/gpio-i2c-switch.yaml b/dts/bindings/i2c/gpio-i2c-switch.yaml new file mode 100644 index 000000000000000..ebd932afc710f2a --- /dev/null +++ b/dts/bindings/i2c/gpio-i2c-switch.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2023, Ayush Singh +# Copyright (c) 2021, Jason Kridner, BeagleBoard.org Foundation +# SPDX-License-Identifier: Apache-2.0 + +description: | + GPIO enabled analog switch to isolate devices from an I2C bus + +compatible: "gpio-i2c-switch" + +include: i2c-controller.yaml + +properties: + "#address-cells": + required: true + const: 1 + "#size-cells": + required: true + const: 0 + controller: + type: phandle + required: true + gpios: + type: phandle-array + required: true diff --git a/dts/bindings/i2c/infineon,cat1-i2c.yaml b/dts/bindings/i2c/infineon,cat1-i2c.yaml index fa7ca1b8f4a274d..ef287709b767bf5 100644 --- a/dts/bindings/i2c/infineon,cat1-i2c.yaml +++ b/dts/bindings/i2c/infineon,cat1-i2c.yaml @@ -3,7 +3,42 @@ # # SPDX-License-Identifier: Apache-2.0 -description: Infineon CAT1 I2C +description: | + Infineon CAT1 I2C driver + + This driver configures the SCB as an I2C device. + + Example devicetree configuration with vl53l0x Time-of-Flight (ToF) + ranging sensor connected on the bus: + + i2c3: &scb3 { + compatible = "infineon,cat1-i2c"; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-0 = <&p6_0_scb3_i2c_scl &p6_1_scb3_i2c_sda>; + pinctrl-names = "default"; + + vl53l0x@29 { + compatible = "st,vl53l0x"; + reg = <0x29>; + }; + }; + + The pinctrl nodes need to be configured as open-drain and + input-enable: + + &p6_0_scb3_i2c_scl { + drive-open-drain; + input-enable; + }; + + &p6_1_scb3_i2c_sda { + drive-open-drain; + input-enable; + }; compatible: "infineon,cat1-i2c" diff --git a/dts/bindings/i2c/ite,common-i2c.yaml b/dts/bindings/i2c/ite,common-i2c.yaml index 251903efafcc4bf..1e4e90793da162e 100644 --- a/dts/bindings/i2c/ite,common-i2c.yaml +++ b/dts/bindings/i2c/ite,common-i2c.yaml @@ -30,6 +30,54 @@ properties: 4 = I2C_CHANNEL_E, 5 = I2C_CHANNEL_F, + channel-switch-sel: + type: int + required: true + enum: + - 0 + - 1 + - 2 + - 3 + - 4 + - 5 + description: | + The default setting is as described below + 0 = I2C_CHA_LOCATE: Channel A is located at SMCLK0/SMDAT0 + 1 = I2C_CHB_LOCATE: Channel B is located at SMCLK1/SMDAT1 + 2 = I2C_CHC_LOCATE: Channel C is located at SMCLK2/SMDAT2 + 3 = I2C_CHD_LOCATE: Channel D is located at SMCLK3/SMDAT3 + 4 = I2C_CHE_LOCATE: Channel E is located at SMCLK4/SMDAT4 + 5 = I2C_CHF_LOCATE: Channel F is located at SMCLK5/SMDAT5 + + The following is an example of the 'channel-switch-sel' property + being swapped between node &i2c0 and &i2c2 in the application: + Note: The property of 'port-num' cannot be changed in the + application. + + Channel C is located at SMCLK0/SMDAT0: + &i2c0 { + channel-switch-sel = ; + pinctrl-0 = <&i2c2_clk_gpf6_default + &i2c2_data_gpf7_default>; + pinctrl-names = "default"; + scl-gpios = <&gpiof 6 0>; + sda-gpios = <&gpiof 7 0>; + }; + + Channel A is located at SMCLK2/SMDAT2: + &i2c2 { + channel-switch-sel = ; + pinctrl-0 = <&i2c0_clk_gpb3_default + &i2c0_data_gpb4_default>; + pinctrl-names = "default"; + scl-gpios = <&gpiob 3 0>; + sda-gpios = <&gpiob 4 0>; + }; + + If the property of 'channel-switch-sel' is changed, the pinctrl + setting and recovery pin in &i2c0 and &i2c2 nodes must also be + modified accordingly. + scl-gpios: type: phandle-array required: true diff --git a/dts/bindings/i2c/ite,enhance-i2c.yaml b/dts/bindings/i2c/ite,enhance-i2c.yaml index 446f3f09aea31b2..95720c85158977e 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 000000000000000..5ba876448c19183 --- /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/nxp,mcux-i2s.yaml b/dts/bindings/i2s/nxp,mcux-i2s.yaml index a4eae452396a2d8..25295432874a7fd 100644 --- a/dts/bindings/i2s/nxp,mcux-i2s.yaml +++ b/dts/bindings/i2s/nxp,mcux-i2s.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2021, NXP +# Copyright 2021,2023 NXP # SPDX-License-Identifier: Apache-2.0 description: NXP mcux SAI-I2S controller @@ -60,3 +60,8 @@ properties: nxp,tx-channel: type: int description: tx channel the maximum number is SOC dependent + + clock-mux: + required: true + type: int + description: Clock mux source for SAI root clock 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 000000000000000..09e13c449e9a84e --- /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 1de415d0ddf9d67..263e787d4659f94 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 000000000000000..8fa3bf89c5b1c39 --- /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/i3c/nxp,mcux-i3c.yaml b/dts/bindings/i3c/nxp,mcux-i3c.yaml index a31d61d6a85c5e0..2fd62be969499c0 100644 --- a/dts/bindings/i3c/nxp,mcux-i3c.yaml +++ b/dts/bindings/i3c/nxp,mcux-i3c.yaml @@ -36,3 +36,12 @@ properties: type: int description: Slow clock divider for I3C required: true + + disable-open-drain-high-pp: + type: boolean + description: | + If false, open drain high time is 1 PPBAUD count, + which is short high and long low. + If true, open drain high time is same as ODBAUD + so that open drain clock is 50% duty cycle. + Default is false. diff --git a/dts/bindings/input/analog-axis.yaml b/dts/bindings/input/analog-axis.yaml new file mode 100644 index 000000000000000..ded94e86c0f2426 --- /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 000000000000000..7fe6a01d0c76dfd --- /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 new file mode 100644 index 000000000000000..c8bad93d767e18b --- /dev/null +++ b/dts/bindings/input/gpio-kbd-matrix.yaml @@ -0,0 +1,64 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + GPIO based keyboard matrix input device + + Implement an input device for a GPIO based keyboard matrix. + + Example configuration: + + kbd-matrix { + compatible = "gpio-kbd-matrix"; + row-gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, + <&gpio0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + col-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>, + <&gpio0 3 GPIO_ACTIVE_LOW>, + <&gpio0 4 GPIO_ACTIVE_LOW>; + no-ghostkey-check; + }; + +compatible: "gpio-kbd-matrix" + +include: + - name: kbd-matrix-common.yaml + property-blocklist: + - row-size + - col-size + +properties: + row-gpios: + 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 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. + 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 9b3581a1c13cb92..f2776bbda9d8079 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 963a60e14917e0e..96afde35b40ca9f 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 000000000000000..195cb1efb119f72 --- /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/ite,it8xxx2-kbd.yaml b/dts/bindings/input/ite,it8xxx2-kbd.yaml new file mode 100644 index 000000000000000..d809f41fbbc971f --- /dev/null +++ b/dts/bindings/input/ite,it8xxx2-kbd.yaml @@ -0,0 +1,48 @@ +# Copyright (c) 2021 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +description: ITE it8xxx2 keyboard matrix controller + +compatible: "ite,it8xxx2-kbd" + +include: [kbd-matrix-common.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + wucctrl: + type: phandles + description: | + Configure wakeup controller, this controller is used to set that + when the interrupt is triggered in EC low power mode, it can wakeup + EC or not. Via this controller, we set the wakeup trigger edge, + enable, disable, and clear wakeup status for the specific pin which + may be gpio pins or alternate pins. + + kso16-gpios: + type: phandle-array + required: true + description: | + The KSO16 pin for the selected port. + + kso17-gpios: + type: phandle-array + required: true + description: | + The KSO17 pin for the selected port. + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + row-size: + required: true + + col-size: + required: true diff --git a/dts/bindings/input/kbd-matrix-common.yaml b/dts/bindings/input/kbd-matrix-common.yaml new file mode 100644 index 000000000000000..075c217fe4d851f --- /dev/null +++ b/dts/bindings/input/kbd-matrix-common.yaml @@ -0,0 +1,64 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: Keyboard matrix device + +include: base.yaml + +properties: + row-size: + type: int + description: | + The number of rows in the keyboard matrix. + + col-size: + type: int + description: | + The number of column in the keyboard matrix. + + poll-period-ms: + type: int + default: 5 + description: | + 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 + default: 100 + description: | + How long to wait before going from polling back to idle state. Defaults + to 100ms if unspecified. + + debounce-down-ms: + type: int + default: 10 + description: | + Debouncing time for a key press event. Defaults to 10ms if unspecified. + + debounce-up-ms: + type: int + default: 20 + description: | + Debouncing time for a key release event. Defaults to 20ms if unspecified. + + settle-time-us: + type: int + default: 50 + description: | + 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: | + Ignore the ghost key checking in the driver if the diodes are used + in the matrix hardware. diff --git a/dts/bindings/input/nuvoton,npcx-kbd.yaml b/dts/bindings/input/nuvoton,npcx-kbd.yaml index 9ba33d31aa1036c..b7c30c5388f08f4 100644 --- a/dts/bindings/input/nuvoton,npcx-kbd.yaml +++ b/dts/bindings/input/nuvoton,npcx-kbd.yaml @@ -5,7 +5,7 @@ description: Nuvoton NPCX keyboard scan controller compatible: "nuvoton,npcx-kbd" -include: [base.yaml, pinctrl-device.yaml] +include: [kbd-matrix-common.yaml, pinctrl-device.yaml] properties: reg: @@ -31,33 +31,7 @@ properties: &wui_io25 &wui_io24 &wui_io23 &wui_io22>; row-size: - type: int - default: 8 required: true - description: | - The row size is used in the keyboard matrix. - valid range: 1 - 8 col-size: - type: int - default: 18 required: true - description: | - The column size is used in the keyboard matrix. - valid range: 1 - 18 - - debounce-down-ms: - type: int - default: 10 - description: Determines the time in msecs for debouncing a key press. - - debounce-up-ms: - type: int - default: 20 - description: Determines the time in msecs for debouncing a key release. - - no-ghostkey-check: - type: boolean - description: | - Ignore the ghost key checking in the driver if the diodes are used - in the matrix hardware. diff --git a/dts/bindings/input/zephyr,input-longpress.yaml b/dts/bindings/input/zephyr,input-longpress.yaml index abf87a158030627..a6ef96f5d40b881 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 000000000000000..5fdd3be735af644 --- /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 000000000000000..cd3fa2198104786 --- /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 982d7b4aa089e64..4e9770e65ce85e5 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/nuvoton,npcx-miwu.yaml b/dts/bindings/interrupt-controller/nuvoton,npcx-miwu.yaml index 10d9ebc311b1847..d1319c9b1c2b20d 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 03b5d3b39e036ea..f3300ae6821058b 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 000000000000000..18c3fac42db0b64 --- /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/interrupt-controller/renesas,ra-interrupt-controller-unit.yaml b/dts/bindings/interrupt-controller/renesas,ra-interrupt-controller-unit.yaml new file mode 100644 index 000000000000000..dd13f876cdce55e --- /dev/null +++ b/dts/bindings/interrupt-controller/renesas,ra-interrupt-controller-unit.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2023, TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RA series interrupt controller unit + +compatible: "renesas,ra-interrupt-controller-unit" + +include: [interrupt-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#interrupt-cells": + const: 3 + +interrupt-cells: + - irq + - priority + - flags diff --git a/dts/bindings/ipc/zephyr,ipc-icbmsg.yaml b/dts/bindings/ipc/zephyr,ipc-icbmsg.yaml new file mode 100644 index 000000000000000..0fc6be01a494b6d --- /dev/null +++ b/dts/bindings/ipc/zephyr,ipc-icbmsg.yaml @@ -0,0 +1,22 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Inter-core messaging backend with dynamically allocated buffers + +compatible: "zephyr,ipc-icbmsg" + +include: zephyr,ipc-icmsg.yaml + +properties: + tx-blocks: + description: number of allocable TX blocks + required: true + type: int + + rx-blocks: + description: number of allocable RX blocks + required: true + type: int diff --git a/dts/bindings/ipc/zephyr,ipc-icmsg.yaml b/dts/bindings/ipc/zephyr,ipc-icmsg.yaml index b67c9072980fc0e..417930053734df7 100644 --- a/dts/bindings/ipc/zephyr,ipc-icmsg.yaml +++ b/dts/bindings/ipc/zephyr,ipc-icmsg.yaml @@ -21,6 +21,19 @@ properties: required: true type: phandle + dcache-alignment: + type: int + description: | + Data cache alignment. If any side of the communication uses cache on + rx-region/tx-region this property must be the biggest value of the + invalidation or the write-back size for both sides of the communication. + If no side of the communication uses data cache this property could be + safely omitted. + For example: + Side A: no data cache + Side B: 32 Bytes write-back size, 16 Bytes invalidation size + dcache-alignment = 32; for both + mboxes: description: phandle to the MBOX controller (TX and RX are required) required: true diff --git a/dts/bindings/arm/nxp,imx-mu.yaml b/dts/bindings/ipm/nxp,imx-mu.yaml similarity index 100% rename from dts/bindings/arm/nxp,imx-mu.yaml rename to dts/bindings/ipm/nxp,imx-mu.yaml diff --git a/dts/bindings/kscan/ite,it8xxx2-kscan.yaml b/dts/bindings/kscan/ite,it8xxx2-kscan.yaml deleted file mode 100644 index 47a06b44ee37bdf..000000000000000 --- a/dts/bindings/kscan/ite,it8xxx2-kscan.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2021 ITE Corporation. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - -description: ITE it8xxx2 keyboard matrix controller - -compatible: "ite,it8xxx2-kscan" - -include: [kscan.yaml, pinctrl-device.yaml] - -properties: - reg: - required: true - - interrupts: - required: true - - wucctrl: - type: phandles - description: | - Configure wakeup controller, this controller is used to set that - when the interrupt is triggered in EC low power mode, it can wakeup - EC or not. Via this controller, we set the wakeup trigger edge, - enable, disable, and clear wakeup status for the specific pin which - may be gpio pins or alternate pins. - - kso16-gpios: - type: phandle-array - required: true - description: | - The KSO16 pin for the selected port. - - kso17-gpios: - type: phandle-array - required: true - description: | - The KSO17 pin for the selected port. - - pinctrl-0: - required: true - - pinctrl-names: - required: true 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 000000000000000..d5d41ed38ee3962 --- /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/led_strip/worldsemi,ws2812-spi.yaml b/dts/bindings/led_strip/worldsemi,ws2812-spi.yaml index 0eafd37fde727f6..3c8626c1ec32895 100644 --- a/dts/bindings/led_strip/worldsemi,ws2812-spi.yaml +++ b/dts/bindings/led_strip/worldsemi,ws2812-spi.yaml @@ -24,14 +24,6 @@ include: [spi-device.yaml, ws2812.yaml] properties: - spi-cpol: - type: boolean - description: Set SPI clock polarity. - - spi-cpha: - type: boolean - description: Set SPI clock phase. - spi-one-frame: type: int required: true diff --git a/dts/bindings/mdio/atmel,sam-mdio.yaml b/dts/bindings/mdio/atmel,sam-mdio.yaml index 4eb649b5b24fa21..bc15ad2b76fc8ef 100644 --- a/dts/bindings/mdio/atmel,sam-mdio.yaml +++ b/dts/bindings/mdio/atmel,sam-mdio.yaml @@ -8,3 +8,7 @@ compatible: "atmel,sam-mdio" include: - name: mdio-controller.yaml - name: pinctrl-device.yaml + +properties: + clocks: + type: phandle-array diff --git a/dts/bindings/mdio/infineon,xmc4xxx-mdio.yaml b/dts/bindings/mdio/infineon,xmc4xxx-mdio.yaml new file mode 100644 index 000000000000000..b9da5926d6bbd8a --- /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 9a2a6782d538348..ad83e03278791fa 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 000000000000000..68bc917444a81b2 --- /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 000000000000000..7e7f7273c0b519b --- /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/memory-controllers/nxp,flexram.yaml b/dts/bindings/memory-controllers/nxp,flexram.yaml new file mode 100644 index 000000000000000..76248c063948df0 --- /dev/null +++ b/dts/bindings/memory-controllers/nxp,flexram.yaml @@ -0,0 +1,52 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP FlexRAM on-chip ram controller + +include: base.yaml + +compatible: "nxp,flexram" + +properties: + reg: + required: true + + interrupts: + required: true + + flexram,has-magic-addr: + type: boolean + description: | + Whether or not the flexram on the SOC has the + magic address feature, which allows for an interrupt + on arbitrary address access in any on chip RAM region. + + flexram,num-ram-banks: + type: int + required: true + description: | + Number of RAM banks in the SOC ram array + + flexram,bank-size: + type: int + required: true + description: | + Size of each RAM bank in KB + + flexram,bank-spec: + type: array + description: | + Custom mapping of runtime RAM bank partitions. If this + property is present, then it will be used. If this + property is not present, then the fusemap configuration + will be used. + + flexram,tcm-read-wait-mode: + type: boolean + description: | + TCM RAM read will finish in 2 cycles instead of 1. + + flexram,tcm-write-wait-mode: + type: boolean + description: | + TCM RAM write will finish in 2 cycles instead of 1. diff --git a/dts/bindings/mfd/adi,ad5592.yaml b/dts/bindings/mfd/adi,ad5592.yaml new file mode 100644 index 000000000000000..d3e404ec1433f06 --- /dev/null +++ b/dts/bindings/mfd/adi,ad5592.yaml @@ -0,0 +1,13 @@ +# Copyright (C) 2023 Grinn +# SPDX-License-Identifier: Apache-2.0 + +description: Analog AD5592 ADC/DAC/GPIO chip + +compatible: "adi,ad5592" + +include: spi-device.yaml + +properties: + reset-gpios: + type: phandle-array + description: RESET pin diff --git a/dts/bindings/mfd/maxim,max20335.yaml b/dts/bindings/mfd/maxim,max20335.yaml new file mode 100644 index 000000000000000..deec53c872dcdf5 --- /dev/null +++ b/dts/bindings/mfd/maxim,max20335.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Grinn +# SPDX-License-Identifier: Apache-2.0 + +description: Maxim MAX20335 + +compatible: "maxim,max20335" + +include: i2c-device.yaml + +properties: + reg: + required: true diff --git a/dts/bindings/mipi-dsi/nxp,mipi-dsi-2l.yaml b/dts/bindings/mipi-dsi/nxp,mipi-dsi-2l.yaml index fc0a69870c5816d..02871f29641bcb8 100644 --- a/dts/bindings/mipi-dsi/nxp,mipi-dsi-2l.yaml +++ b/dts/bindings/mipi-dsi/nxp,mipi-dsi-2l.yaml @@ -70,3 +70,9 @@ properties: description: Maximum clock speed supported by the device, in Hz. Leave at default if no DPHY PLL is present + + noncontinuous-hs-clk: + type: boolean + description: + Enable non-contiuous high speed clock. Saves power but introduces latency + when transitioning to high speed mode. diff --git a/dts/bindings/misc/nordic,split-channels.yaml b/dts/bindings/misc/nordic,split-channels.yaml new file mode 100644 index 000000000000000..a875dc12d7f3c53 --- /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/nxp,s32-lcu.yaml b/dts/bindings/misc/nxp,s32-lcu.yaml new file mode 100644 index 000000000000000..51707de20e89499 --- /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 000000000000000..55a589d6836c47c --- /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/renesas,ra-sci.yaml b/dts/bindings/misc/renesas,ra-sci.yaml new file mode 100644 index 000000000000000..d5feedde20150d0 --- /dev/null +++ b/dts/bindings/misc/renesas,ra-sci.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RA SCI controller + +compatible: "renesas,ra-sci" + +include: [base.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + clocks: + required: true diff --git a/dts/bindings/misc/zephyr,devmux.yaml b/dts/bindings/misc/zephyr,devmux.yaml new file mode 100644 index 000000000000000..744daaca120a819 --- /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/misc/zephyr,log-uart.yaml b/dts/bindings/misc/zephyr,log-uart.yaml new file mode 100644 index 000000000000000..2e0a065e3b238d3 --- /dev/null +++ b/dts/bindings/misc/zephyr,log-uart.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +description: Log Backend UART + +compatible: "zephyr,log-uart" + +include: [base.yaml] + +properties: + + uarts: + type: phandles + required: true + description: | + UART devices to be used by the UART log backend. diff --git a/dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml b/dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml index 6534ec078744a80..16bdac395e4606a 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 36de0b9f711a71d..e0c6c3b4cecd8bd 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 fd924284de87756..7800e36d7a1003d 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 103216228919db4..0e7c12bf1b03c6a 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/quectel,eg25-g.yaml b/dts/bindings/modem/quectel,eg25-g.yaml new file mode 100644 index 000000000000000..45284ddf174b4b1 --- /dev/null +++ b/dts/bindings/modem/quectel,eg25-g.yaml @@ -0,0 +1,16 @@ +description: Quectel EG25-G modem + +compatible: "quectel,eg25-g" + +include: uart-device.yaml + +properties: + mdm-reset-gpios: + type: phandle-array + required: true + + mdm-dtr-gpios: + type: phandle-array + + mdm-wdisable-gpios: + type: phandle-array diff --git a/dts/bindings/modem/telit,me910g1.yaml b/dts/bindings/modem/telit,me910g1.yaml new file mode 100644 index 000000000000000..2599b6cd237d595 --- /dev/null +++ b/dts/bindings/modem/telit,me910g1.yaml @@ -0,0 +1,23 @@ +# Copyright(c) 2023 Jeff Welder (Ellenby Technologies, Inc.) +# SPDX-License-Identifier: Apache-2.0 + +description: Telit ME910G1 Modem + +compatible: "telit,me910g1" + +include: uart-device.yaml + +properties: + mdm-power-gpios: + type: phandle-array + required: true + + mdm-reset-gpios: + type: phandle-array + required: true + + mdm-dtr-gpios: + type: phandle-array + + mdm-ri-gpios: + type: phandle-array 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 000000000000000..af6c3318fd078bc --- /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 000000000000000..c2a16328105d729 --- /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/jedec,jesd216.yaml b/dts/bindings/mtd/jedec,jesd216.yaml index fcbc20ec84d2177..c55440456c2ac1d 100644 --- a/dts/bindings/mtd/jedec,jesd216.yaml +++ b/dts/bindings/mtd/jedec,jesd216.yaml @@ -68,3 +68,16 @@ properties: addressing is require to access the full address range, and automatically puts the device into 4-byte address mode when the device is initialized. + + page-size: + type: int + description: | + Number of bytes in a page from JESD216 BFP DW11 + + This property is only used in the CONFIG_SPI_NOR_SFDP_MINIMAL configuration. + It is ignored if the device is configured to use SFDP data + from the sfdp-bfp property (CONFIG_SPI_NOR_SFDP_DEVICETREE) or + if the SFDP parameters are read from the device at + runtime (CONFIG_SPI_NOR_SFDP_RUNTIME). + + The default value is 256 bytes if the value is not specified. diff --git a/dts/bindings/net/wireless/gpio-radio-coex.yaml b/dts/bindings/net/wireless/gpio-radio-coex.yaml index e21cc53d4339992..1acb8e7f9a9f07c 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/options/openthread,config.yaml b/dts/bindings/options/openthread,config.yaml index 054107fab44f525..6366c289c805c1c 100644 --- a/dts/bindings/options/openthread,config.yaml +++ b/dts/bindings/options/openthread,config.yaml @@ -10,6 +10,7 @@ description: | compatible = "openthread,config"; diag-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>, <&gpio1 0 GPIO_ACTIVE_LOW>; + bootloader-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; }; }; @@ -21,3 +22,9 @@ properties: description: | This enables access to diagnostic GPIO pins. Each field consists of GPIO pin's configuration: controller's phandle, pin number and configuration flags. + + bootloader-gpios: + type: phandle-array + description: | + This enables resetting to bootloader by triggering given GPIO pin. Property represents + chosen GPIO pin's configuration: controller's phandle, pin number and configuration flags. diff --git a/dts/bindings/pinctrl/espressif,esp32-pinctrl.yaml b/dts/bindings/pinctrl/espressif,esp32-pinctrl.yaml index 79cd24910cf77fb..c55372094aee59d 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 36a3a7595a27389..01a1c758a9c553d 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/nxp,imx-iomuxc-scu.yaml b/dts/bindings/pinctrl/nxp,imx-iomuxc-scu.yaml new file mode 100644 index 000000000000000..60dde5ae4c90599 --- /dev/null +++ b/dts/bindings/pinctrl/nxp,imx-iomuxc-scu.yaml @@ -0,0 +1,25 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + Use this compatible for i.MX boards on which the + IOMUXC is managed by the SCU. + +compatible: "nxp,imx-iomuxc-scu" + +include: base.yaml + +child-binding: + description: SCFW-based IOMUXC pin mux. + properties: + pinmux: + required: true + type: array + description: | + This is an array of values defining the pin mux selection + with the following format: + + + + pad: Which pad to configure. + mux: Select which signal to route. diff --git a/dts/bindings/pinctrl/nxp,imx8-pinctrl.yaml b/dts/bindings/pinctrl/nxp,imx8-pinctrl.yaml new file mode 100644 index 000000000000000..4f0427d5d95cce3 --- /dev/null +++ b/dts/bindings/pinctrl/nxp,imx8-pinctrl.yaml @@ -0,0 +1,17 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: Use this compatible for i.MX8QM/QXP boards. + +compatible: "nxp,imx8-pinctrl" + +include: base.yaml + +child-binding: + description: i.MX8QM/QXP pin controller pin group + child-binding: + description: i.MX8QM/QXP pin controller pin configuration node. + properties: + pinmux: + required: true + type: phandles diff --git a/dts/bindings/pinctrl/nxp,kinetis-pinctrl.yaml b/dts/bindings/pinctrl/nxp,kinetis-pinctrl.yaml index ccc36d4f167ed5d..c5b2f5d60207e7e 100644 --- a/dts/bindings/pinctrl/nxp,kinetis-pinctrl.yaml +++ b/dts/bindings/pinctrl/nxp,kinetis-pinctrl.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2022, NXP +# Copyright (c) 2022-2023, NXP # SPDX-License-Identifier: Apache-2.0 description: | @@ -63,7 +63,6 @@ child-binding: 0 DSE_0- low drive strength when pin is configured as output 1 DSE_1- high drive strength when pin is configured as output slew-rate: - required: true type: string enum: - "fast" diff --git a/dts/bindings/pinctrl/renesas,ra-pinctrl.yaml b/dts/bindings/pinctrl/renesas,ra-pinctrl.yaml new file mode 100644 index 000000000000000..6a48dedf37e77d8 --- /dev/null +++ b/dts/bindings/pinctrl/renesas,ra-pinctrl.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: | + Renesas RA series pin controller + +compatible: "renesas,ra-pinctrl" + +include: base.yaml + +child-binding: + description: | + Definitions for a pinctrl state. + child-binding: + + properties: + pinmux: + required: true + type: array + description: | + An array of pins sharing the same group properties. Each + element of the array is an integer constructed from the + pin number and the alternative function of the pin. diff --git a/dts/bindings/pinctrl/renesas,rcar-pfc.yaml b/dts/bindings/pinctrl/renesas,rcar-pfc.yaml index fa94cd11c05eb14..1743f213193e19d 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/renesas,rzt2m-pinctrl.yaml b/dts/bindings/pinctrl/renesas,rzt2m-pinctrl.yaml new file mode 100644 index 000000000000000..82016017201bcc0 --- /dev/null +++ b/dts/bindings/pinctrl/renesas,rzt2m-pinctrl.yaml @@ -0,0 +1,93 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +description: | + The Renesas RZ/T2M pin controller is a node responsible for controlling + pin function selection and pin properties, such as routing the TX and RX of UART0 + to pin 5 and pin 6 of port 16. + + The node has the 'pinctrl' node label set in your SoC's devicetree, + so you can modify it like this: + + &pinctrl { + /* your modifications go here */ + }; + + All device pin configurations should be placed in child nodes of the + 'pinctrl' node, as shown in this example: + + /* You can put this in places like a board-pinctrl.dtsi file in + * your board directory, or a devicetree overlay in your application. + */ + + /* include pre-defined combinations for the SoC variant used by the board */ + #include + + &pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + }; + + The 'uart0_default' child node encodes the pin configurations for a + particular state of a device; in this case, the default (that is, active) + state. + + As shown, pin configurations are organized in groups within each child node. + Each group can specify a list of pin function selections in the 'pinmux' + property. + + A group can also specify shared pin properties common to all the specified + pins, such as the 'input-enable' property in group 2. + +compatible: "renesas,rzt2m-pinctrl" + +include: base.yaml + +child-binding: + description: | + Definitions for a pinctrl state. + child-binding: + + include: + - name: pincfg-node.yaml + property-allowlist: + - input-enable + - bias-pull-up + - bias-pull-down + - bias-high-impedance + - input-schmitt-enable + + properties: + pinmux: + required: true + type: array + description: | + An array of pins sharing the same group properties. Each + element of the array is an integer constructed from the + pin number and the alternative function of the pin. + drive-strength: + type: string + enum: + - "low" + - "middle" + - "high" + - "ultrahigh" + default: "low" + description: | + The drive strength of a pin, relative to full-driver strength. + The default value is "low", which is the reset value. + slew-rate: + type: string + enum: + - "slow" + - "fast" + default: "slow" + description: | + Select slew rate for a pin. The default is slow, which is the reset value. diff --git a/dts/bindings/pinctrl/st,stm32-pinctrl.yaml b/dts/bindings/pinctrl/st,stm32-pinctrl.yaml index cfc1c2a6fa75c1a..b412d5dfddb4de1 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 f96b3c123ea0b79..77efa78c06418a1 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 2c19c46a0804e70..df490ffa18a750f 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 000000000000000..7a5af3a2b7dcafc --- /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 new file mode 100644 index 000000000000000..734aab8e6f7894b --- /dev/null +++ b/dts/bindings/power-domain/power-domain-gpio-monitor.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + Simple monitorig power domain + + 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 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" + +include: power-domain.yaml + +properties: + gpios: + type: phandle-array + required: true + description: | + GPIO to use to sense if rail is powered on. diff --git a/dts/bindings/power/atmel,sam-supc.yaml b/dts/bindings/power/atmel,sam-supc.yaml new file mode 100644 index 000000000000000..fdba03f87cfdff0 --- /dev/null +++ b/dts/bindings/power/atmel,sam-supc.yaml @@ -0,0 +1,47 @@ +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +description: | + Atmel SAM SUPC (Supply-Controller) controller + + The supply controller manages the voltage reference, power supply and supply + monitoring of the device. It have a special feature that it can wake-up the + device from a low-power state using special peripherals as wake-up sources. + + The dedicated peripherals that can wake-up the core supply domain are: RTC, + RTT, Supply Monitor and GPIOs. In the first three peripherals it is necessary + inform the wakeup-source-id property on their respective nodes. + + rtc: rtc@xxx { + ... + wakeup-source-id = <&supc SUPC_WAKEUP_SOURCE_RTC>; + ... + }; + + The special peripheral will wake-up the device only when the standard property + wakeup-source is defined, e.g.: + + &rtc { + ... + wakeup-source; + ... + }; + + The SUPC wakeup source ids that can be enabled are defined in the + zephyr/include/zephyr/dt-bindings/power/atmel_sam_supc.h header file. + +compatible: "atmel,sam-supc" + +include: + - name: base.yaml + +properties: + reg: + required: true + + "#wakeup-source-id-cells": + type: int + const: 1 + +wakeup-source-id-cells: + - wakeup-source-id diff --git a/dts/bindings/ppc/nxp,nx20p3483.yaml b/dts/bindings/ppc/nxp,nx20p3483.yaml new file mode 100644 index 000000000000000..c705ac32c333158 --- /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 37de69e39e16880..0b8a2ffc674ac43 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 7d61e5d81047e22..0f59af09f251772 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 new file mode 100644 index 000000000000000..d23a1fdf1c1ef5c --- /dev/null +++ b/dts/bindings/regulator/maxim,max20335-regulator.yaml @@ -0,0 +1,51 @@ +# Copyright (c), 2023 Grinn +# SPDX -License-Identifier: Apache-2.0 + +description: | + Maxim MAX20335 PMIC + + The PMIC has two buck converters and three LDOs. All need to be defined as + children nodes, strictly following the BUCK1..2, LDO1..3 node names. For + example: + + pmic@28 { + reg = <0x28>; + ... + regulators { + compatible = maxim,max20335-regulator"; + + BUCK1 { + /* all properties for BUCK1 */ + }; + BUCK2 { + /* all properties for BUCK2 */ + }; + LDO1 { + /* all properties for LDO1 */ + }; + LDO2 { + /* all properties for LDO2 */ + }; + LDO3 { + /* all properties for LDO3 */ + }; + }; + }; + +compatible: "maxim,max20335-regulator" + +include: base.yaml + +child-binding: + include: + - name: regulator.yaml + property-allowlist: + - regulator-init-microvolt + - regulator-min-microvolt + - regulator-max-microvolt + - regulator-init-microamp + - regulator-max-microamp + - regulator-always-on + - regulator-boot-on + - regulator-initial-mode + - regulator-allowed-modes diff --git a/dts/bindings/regulator/nordic,npm1300-regulator.yaml b/dts/bindings/regulator/nordic,npm1300-regulator.yaml index 987a3b522e1228c..c5364a49fe0dd70 100644 --- a/dts/bindings/regulator/nordic,npm1300-regulator.yaml +++ b/dts/bindings/regulator/nordic,npm1300-regulator.yaml @@ -60,6 +60,8 @@ child-binding: - regulator-initial-mode - regulator-min-microamp - regulator-max-microamp + - startup-delay-us + - off-on-delay-us properties: retention-microvolt: @@ -83,3 +85,13 @@ child-binding: type: phandle-array description: | Retention mode controlled by specified regulator GPIO pin. + + soft-start-microamp: + type: int + enum: + - 10000 + - 20000 + - 35000 + - 50000 + description: | + Soft start current limit in microamps. diff --git a/dts/bindings/regulator/nxp,pca9420.yaml b/dts/bindings/regulator/nxp,pca9420.yaml index 1f88113760118ea..2e4584d0a67dcee 100644 --- a/dts/bindings/regulator/nxp,pca9420.yaml +++ b/dts/bindings/regulator/nxp,pca9420.yaml @@ -63,6 +63,18 @@ properties: To disable current limit, set property to zero. Defaults to 425mA, the IC default value. + nxp,asys-uvlo-sel-millivolt: + type: int + default: 2700 + enum: + - 2400 + - 2500 + - 2600 + - 2700 + description: | + ASYS UVLO (under voltage lock out) threshold, in millivolts. Defaults to + 2700mV to match the IC default value. + child-binding: include: - name: regulator.yaml diff --git a/dts/bindings/regulator/regulator-fixed.yaml b/dts/bindings/regulator/regulator-fixed.yaml index 1033d333f08d17f..4f3236d8c6cb26f 100644 --- a/dts/bindings/regulator/regulator-fixed.yaml +++ b/dts/bindings/regulator/regulator-fixed.yaml @@ -13,6 +13,8 @@ include: - regulator-always-on - regulator-min-microvolt - regulator-max-microvolt + - startup-delay-us + - off-on-delay-us compatible: "regulator-fixed" @@ -29,13 +31,3 @@ properties: provide the GPIO polarity and open-drain status in the phandle selector. The Linux enable-active-high and gpio-open-drain properties are not valid for Zephyr devicetree files. - - startup-delay-us: - type: int - default: 0 - description: Startup time, in microseconds - - off-on-delay-us: - type: int - default: 0 - description: Off delay time, in microseconds diff --git a/dts/bindings/regulator/regulator-gpio.yaml b/dts/bindings/regulator/regulator-gpio.yaml index aa7aeb44eeeee6e..15c419a0043a8b1 100644 --- a/dts/bindings/regulator/regulator-gpio.yaml +++ b/dts/bindings/regulator/regulator-gpio.yaml @@ -34,6 +34,7 @@ include: - regulator-max-microvolt - regulator-always-on - regulator-boot-on + - startup-delay-us compatible: "regulator-gpio" @@ -70,7 +71,3 @@ properties: Example: enable-gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>; - - startup-delay-us: - type: int - description: startup time in microseconds diff --git a/dts/bindings/regulator/regulator.yaml b/dts/bindings/regulator/regulator.yaml index 067133aa97e2672..635bfa49596d415 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 @@ -256,3 +260,11 @@ properties: description: | Maximum difference between current and target voltages that can be changed safely in a single step. + + startup-delay-us: + type: int + description: Startup time, in microseconds + + off-on-delay-us: + type: int + description: Off to on delay time, in microseconds diff --git a/dts/bindings/regulator/renesas,da1469x-regulator.yaml b/dts/bindings/regulator/renesas,da1469x-regulator.yaml new file mode 100644 index 000000000000000..2537b7e09d7da8e --- /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/retained_mem/zephyr,retained-ram.yaml b/dts/bindings/retained_mem/zephyr,retained-ram.yaml index 5f2c1df12449ab4..0b11fdd1bff93c0 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 000000000000000..12c9a5303906bde --- /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/rng/st,stm32-rng.yaml b/dts/bindings/rng/st,stm32-rng.yaml index a58a8a81aeb0410..c0e6d5e2ec3fb67 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/atmel,sam-rtc.yaml b/dts/bindings/rtc/atmel,sam-rtc.yaml new file mode 100644 index 000000000000000..7e787ebaf10b1fd --- /dev/null +++ b/dts/bindings/rtc/atmel,sam-rtc.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +description: Atmel SAM family RTC device + +compatible: "atmel,sam-rtc" + +include: rtc-device.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + clocks: + required: true diff --git a/dts/bindings/rtc/maxim,ds1307.yaml b/dts/bindings/rtc/maxim,ds1307.yaml new file mode 100644 index 000000000000000..fc81e803cb4d7b0 --- /dev/null +++ b/dts/bindings/rtc/maxim,ds1307.yaml @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 Arunmani Alagarsamy +# Author: Arunmani Alagarsamy + +description: Maxim DS1307 RTC + +compatible: "maxim,ds1307" + +include: + - name: rtc-device.yaml + - name: i2c-device.yaml diff --git a/dts/bindings/rtc/nxp,pcf8563.yaml b/dts/bindings/rtc/nxp,pcf8563.yaml index 95ca4a793a4bd46..d354c71af004551 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/rtc/renesas,smartbond-rtc.yaml b/dts/bindings/rtc/renesas,smartbond-rtc.yaml new file mode 100644 index 000000000000000..afe21aef79b9a9d --- /dev/null +++ b/dts/bindings/rtc/renesas,smartbond-rtc.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas SmartBond(tm) RTC node + +compatible: "renesas,smartbond-rtc" + +include: rtc-device.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/bindings/sdhc/cdns,sdhc.yaml b/dts/bindings/sdhc/cdns,sdhc.yaml new file mode 100644 index 000000000000000..536b9c4bd58a4e1 --- /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/sdhc/infineon,cat1-sdhc-sdio.yaml b/dts/bindings/sdhc/infineon,cat1-sdhc-sdio.yaml new file mode 100644 index 000000000000000..8bb1071b02b3cd5 --- /dev/null +++ b/dts/bindings/sdhc/infineon,cat1-sdhc-sdio.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: Infineon CAT1 SDHC/SDIO controller + +compatible: "infineon,cat1-sdhc-sdio" + +include: [sdhc.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true diff --git a/dts/bindings/sensor/adi,adxl367-common.yaml b/dts/bindings/sensor/adi,adxl367-common.yaml new file mode 100644 index 000000000000000..722d13d92e07f55 --- /dev/null +++ b/dts/bindings/sensor/adi,adxl367-common.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2023 Analog Devices Inc. +# SPDX-License-Identifier: Apache-2.0 + +include: sensor-device.yaml + +properties: + odr: + type: int + default: 0 + description: | + Accelerometer sampling frequency (ODR). Default is power on reset value. + 0 # 12.5Hz + 1 # 25Hz + 2 # 50Hz + 3 # 100Hz + 4 # 200Hz + 5 # 400Hz + enum: + - 0 + - 1 + - 2 + - 3 + - 4 + - 5 + + int1-gpios: + type: phandle-array + description: | + The INT1 signal defaults to active high as produced by the + sensor. The property value should ensure the flags properly + describe the signal that is presented to the driver. diff --git a/dts/bindings/sensor/adi,adxl367-i2c.yaml b/dts/bindings/sensor/adi,adxl367-i2c.yaml new file mode 100644 index 000000000000000..faab9e577b9643e --- /dev/null +++ b/dts/bindings/sensor/adi,adxl367-i2c.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Analog Devices Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: ADXL367 3-axis nanopower accelerometer, accessed through I2C bus + +compatible: "adi,adxl367" + +include: ["i2c-device.yaml", "adi,adxl367-common.yaml"] diff --git a/dts/bindings/sensor/adi,adxl367-spi.yaml b/dts/bindings/sensor/adi,adxl367-spi.yaml new file mode 100644 index 000000000000000..86d825f781c34c8 --- /dev/null +++ b/dts/bindings/sensor/adi,adxl367-spi.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Analog Devices Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: ADXL367 3-axis nanopower accelerometer, accessed through SPI bus + +compatible: "adi,adxl367" + +include: ["spi-device.yaml", "adi,adxl367-common.yaml"] diff --git a/dts/bindings/sensor/adi,adxl372-common.yaml b/dts/bindings/sensor/adi,adxl372-common.yaml index 6c666dce8a9355a..547337fc70a0f92 100644 --- a/dts/bindings/sensor/adi,adxl372-common.yaml +++ b/dts/bindings/sensor/adi,adxl372-common.yaml @@ -56,3 +56,10 @@ properties: - 2 - 3 - 4 + + int1-gpios: + type: phandle-array + description: | + The INT1 signal defaults to active high as produced by the + sensor. The property value should ensure the flags properly + describe the signal that is presented to the driver. diff --git a/dts/bindings/sensor/adi,adxl372-i2c.yaml b/dts/bindings/sensor/adi,adxl372-i2c.yaml index f6f0ac197eddcf6..1e732b1f9d48988 100644 --- a/dts/bindings/sensor/adi,adxl372-i2c.yaml +++ b/dts/bindings/sensor/adi,adxl372-i2c.yaml @@ -6,11 +6,3 @@ description: ADXL372 3-axis high-g accelerometer, accessed through I2C bus compatible: "adi,adxl372" include: ["i2c-device.yaml", "adi,adxl372-common.yaml"] - -properties: - int1-gpios: - type: phandle-array - description: | - The INT1 signal defaults to active high as produced by the - sensor. The property value should ensure the flags properly - describe the signal that is presented to the driver. diff --git a/dts/bindings/sensor/adi,adxl372-spi.yaml b/dts/bindings/sensor/adi,adxl372-spi.yaml index 7d6863c3118117f..2cb4e6745223466 100644 --- a/dts/bindings/sensor/adi,adxl372-spi.yaml +++ b/dts/bindings/sensor/adi,adxl372-spi.yaml @@ -7,11 +7,3 @@ description: ADXL372 3-axis high-g accelerometer, accessed through SPI bus compatible: "adi,adxl372" include: ["spi-device.yaml", "adi,adxl372-common.yaml"] - -properties: - int1-gpios: - type: phandle-array - description: | - The INT1 signal defaults to active high as produced by the - sensor. The property value should ensure the flags properly - describe the signal that is presented to the driver. diff --git a/dts/bindings/sensor/amd,sb-tsi.yaml b/dts/bindings/sensor/amd,sb-tsi.yaml new file mode 100644 index 000000000000000..f9204b79db23dbf --- /dev/null +++ b/dts/bindings/sensor/amd,sb-tsi.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: AMD SB Temperature Sensor Interface. + +compatible: "amd,sb-tsi" + +include: [sensor-device.yaml, i2c-device.yaml] diff --git a/dts/bindings/sensor/ams,tsl2540.yaml b/dts/bindings/sensor/ams,tsl2540.yaml index e47f8a8e8f0031e..d19bd4ea0026b54 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/ams,tsl2561.yaml b/dts/bindings/sensor/ams,tsl2561.yaml new file mode 100644 index 000000000000000..fbc97a673e8d049 --- /dev/null +++ b/dts/bindings/sensor/ams,tsl2561.yaml @@ -0,0 +1,28 @@ +# Copyright (c) 2023, Gustavo Silva +# SPDX-License-Identifier: Apache-2.0 + +description: | + OSRAM ams TSL2561 light sensor. + +compatible: "ams,tsl2561" + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + integration-time: + type: int + default: 402 + description: | + ADC integration time in ms. The default value matches Timing Register's value at power on. + enum: + - 13 + - 101 + - 402 + gain: + type: int + default: 16 + description: | + ADC gain factor. The default value matches Timing Register's value at power on. + enum: + - 1 + - 16 diff --git a/dts/bindings/sensor/aosong,ags10.yaml b/dts/bindings/sensor/aosong,ags10.yaml new file mode 100644 index 000000000000000..fffd0f258fe12aa --- /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 000000000000000..f7053021850c38f --- /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 000000000000000..8c5ddce21387ad1 --- /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 000000000000000..dfadc8c686e7b5d --- /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 000000000000000..0d8421429291f70 --- /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 32bf13a30137018..31509f40251d180 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/gss,explorir-m.yaml b/dts/bindings/sensor/gss,explorir-m.yaml new file mode 100644 index 000000000000000..62de081c1be159b --- /dev/null +++ b/dts/bindings/sensor/gss,explorir-m.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023, Vitrolife A/S +# SPDX-License-Identifier: Apache-2.0 + +description: Gas Sensing Solutions CO2 sensor + +compatible: "gss,explorir-m" + +include: [sensor-device.yaml, uart-device.yaml] diff --git a/dts/bindings/sensor/ltrf216a.yaml b/dts/bindings/sensor/ltrf216a.yaml new file mode 100644 index 000000000000000..fdbd7304be012a4 --- /dev/null +++ b/dts/bindings/sensor/ltrf216a.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023, Trridonic +# SPDX-License-Identifier: Apache-2.0 + +description: LiteOn F216A ambient light sensor + +compatible: "ltr,f216a" + +include: [sensor-device.yaml, i2c-device.yaml] diff --git a/dts/bindings/sensor/maxim,max31875.yaml b/dts/bindings/sensor/maxim,max31875.yaml index 4ded503bdbd40a2..546a931e6f64f53 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/sensor/memsic,mc3419.yaml b/dts/bindings/sensor/memsic,mc3419.yaml new file mode 100644 index 000000000000000..accb86b667be264 --- /dev/null +++ b/dts/bindings/sensor/memsic,mc3419.yaml @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 Linumiz + +description: MC3419 3-axis accel sensor + +compatible: "memsic,mc3419" + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + int-gpios: + type: phandle-array + description: | + This property specifies the connection for INT, this pin + defaults to active low when sample produce interrupt. + + int-pin2: + type: boolean + description: | + This property is used for interrupt routing.The sensor + has two interrupt pins.By default the interrupt are routed + to interrupt pin 1, by enabled this property interrupt are + routed to interrupt pin 2. diff --git a/dts/bindings/sensor/nordic,npm1300-charger.yaml b/dts/bindings/sensor/nordic,npm1300-charger.yaml index cfb0420ecc9b6df..2885cd0de76ea09 100644 --- a/dts/bindings/sensor/nordic,npm1300-charger.yaml +++ b/dts/bindings/sensor/nordic,npm1300-charger.yaml @@ -114,3 +114,15 @@ properties: type: boolean description: | Disable automatic recharge. + + dietemp-stop-millidegrees: + type: int + description: | + Die temperature halt threshold in milli-degrees. + When die temperature exceeds this threshold, charging will be inhibited. + + dietemp-resume-millidegrees: + type: int + description: | + Die temperature resume threshold in milli-degrees. + When die temperature falls below this threshold, charging will be permitted. 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 40d0e1b6e0ca4a3..2cc687b8423c358 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 0b2b4d9df9df4f0..0ad50bf2e978fbb 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 000000000000000..935d2122f23289c --- /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/renesas,hs300x.yaml b/dts/bindings/sensor/renesas,hs300x.yaml new file mode 100644 index 000000000000000..cd24b67da74db1c --- /dev/null +++ b/dts/bindings/sensor/renesas,hs300x.yaml @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023 Ian Morris +# +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas HS300x humidity and temperature sensor + +compatible: "renesas,hs300x" + +include: [sensor-device.yaml, i2c-device.yaml] diff --git a/dts/bindings/sensor/st,iis2dlpc-common.yaml b/dts/bindings/sensor/st,iis2dlpc-common.yaml index 36c258df4b12a5e..d21f4a6d195ae22 100644 --- a/dts/bindings/sensor/st,iis2dlpc-common.yaml +++ b/dts/bindings/sensor/st,iis2dlpc-common.yaml @@ -1,6 +1,20 @@ # Copyright (c) 2018 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the odr property in a .dts or .dtsi file you may include + iis2dlpc.h and use the macros defined there. + + Example: + #include + + iis2dlpc: iis2dlpc@0 { + ... + + tap-mode = ; + power-mode = ; + }; + include: sensor-device.yaml properties: @@ -16,36 +30,44 @@ properties: drdy-int: type: int default: 1 - enum: - - 1 # drdy is generated from INT1 - - 2 # drdy is generated from INT2 - description: Select DRDY pin number (1 or 2). + enum: [1, 2] + description: | + Select DRDY pin number (1 or 2). 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. + - 1 # drdy is generated from INT1 + - 2 # drdy is generated from INT2 + range: type: int default: 2 - description: Range in g. Default is power-up configuration. - enum: + description: | + Range in g. Default is power-up configuration. + - 16 # 16g (1.952 mg/LSB) - 8 # 8g (0.976 mg/LSB) - 4 # 4g (0.488 mg/LSB) - 2 # 2g (0.244 mg/LSB) + enum: [16, 8, 4, 2] + power-mode: type: int default: 0 - description: Specify the sensor power mode. Default is power-up configuration. - enum: - - 0 # Low Power M1 - - 1 # Low Power M2 - - 2 # Low Power M3 - - 3 # Low Power M4 - - 4 # High Performance + description: | + Specify the sensor power mode. Default is power-up configuration. + + - 0 # IIS2DLPC_DT_LP_M1 + - 1 # IIS2DLPC_DT_LP_M2 + - 2 # IIS2DLPC_DT_LP_M3 + - 3 # IIS2DLPC_DT_LP_M4 + - 4 # IIS2DLPC_DT_HP_MODE + + enum: [0, 1, 2, 3, 4] # tap and tap-tap configuration section # All default values are selected to match the power-up values. @@ -54,10 +76,13 @@ properties: tap-mode: type: int default: 0 - description: Tap mode. Default is power-up configuration. - enum: - - 0 # Only Single Tap - - 1 # Single and Double Tap + description: | + Tap mode. Default is power-up configuration. + + - 0 # IIS2DLPC_DT_SINGLE_TAP + - 1 # IIS2DLPC_DT_SINGLE_DOUBLE_TAP + + enum: [0, 1] tap-threshold: type: array diff --git a/dts/bindings/sensor/st,iis2iclx-common.yaml b/dts/bindings/sensor/st,iis2iclx-common.yaml index 9551c274ae10e5e..73bf28940810fd4 100644 --- a/dts/bindings/sensor/st,iis2iclx-common.yaml +++ b/dts/bindings/sensor/st,iis2iclx-common.yaml @@ -1,12 +1,27 @@ # Copyright (c) 2020 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the range, odr properties in a .dts or .dtsi file you may + include iis2iclx.h and use the macros defined there. + + Example: + #include + + iis2iclx: iis2iclx@0 { + ... + + range = ; + odr = ; + }; + include: sensor-device.yaml properties: drdy-gpios: type: phandle-array - description: DRDY pin + description: | + DRDY pin This pin defaults to active high when produced by the sensor. The property value should ensure the flags properly describe @@ -15,41 +30,45 @@ properties: int-pin: type: int default: 1 - enum: - - 1 # drdy is generated from INT1 - - 2 # drdy is generated from INT2 - description: Select DRDY pin number (1 or 2). + enum: [1, 2] + description: | + Select DRDY pin number (1 or 2). 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. + - 1 # drdy is generated from INT1 + - 2 # drdy is generated from INT2 + range: type: int default: 3 - description: Range in g. Default is power-up configuration. - enum: - - 0 # 500mg (0.015 mg/LSB) - - 1 # 3g (0.122 mg/LSB) - - 2 # 1g (0.031 mg/LSB) - - 3 # 2g (0.061 mg/LSB) + description: | + Range in g. Default is power-up configuration. + + - 0 # IIS2ICLX_DT_FS_500mG (0.015 mg/LSB) + - 1 # IIS2ICLX_DT_FS_3G (0.122 mg/LSB) + - 2 # IIS2ICLX_DT_FS_1G (0.031 mg/LSB) + - 3 # IIS2ICLX_DT_FS_2G (0.061 mg/LSB) + + enum: [0, 1, 2, 3] odr: type: int default: 0 - description: + description: | Specify the default accelerometer output data rate expressed in samples per second (Hz). Default is power-up configuration. - enum: - - 0 # Power-Down - - 1 # 12.5Hz - - 2 # 26Hz - - 3 # 52Hz - - 4 # 104Hz - - 5 # 208Hz - - 6 # 416Hz - - 7 # 833Hz - - 8 # 1660Hz - - 9 # 3330Hz - - 10 # 6660Hz + + - 0 # IIS2ICLX_DT_ODR_OFF + - 1 # IIS2ICLX_DT_ODR_12Hz5 + - 2 # IIS2ICLX_DT_ODR_26H + - 3 # IIS2ICLX_DT_ODR_52Hz + - 4 # IIS2ICLX_DT_ODR_104Hz + - 5 # IIS2ICLX_DT_ODR_208Hz + - 6 # IIS2ICLX_DT_ODR_416Hz + - 7 # IIS2ICLX_DT_ODR_833Hz + + enum: [0, 1, 2, 3, 4, 5, 6, 7] diff --git a/dts/bindings/sensor/st,ism330dhcx-common.yaml b/dts/bindings/sensor/st,ism330dhcx-common.yaml index 93d9be0890ef87f..a12ab3446c1a5c3 100644 --- a/dts/bindings/sensor/st,ism330dhcx-common.yaml +++ b/dts/bindings/sensor/st,ism330dhcx-common.yaml @@ -1,6 +1,20 @@ # Copyright (c) 2021 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the accel-odr and gyro-odr properties in a .dts or .dtsi file you may include + ism330dhcx.h and use the macros defined there. + + Example: + #include + + ism330dhcx: ism330dhcx@0 { + ... + + accel-odr = ; + gyro-odr = ; + }; + include: sensor-device.yaml properties: @@ -27,9 +41,7 @@ properties: (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 + enum: [1, 2] accel-odr: type: int @@ -38,30 +50,20 @@ properties: Specify the default accelerometer output data rate expressed in samples per second (Hz). Default is power-up configuration. - Selection - 0 Power-Down - 1 12.5Hz - 2 26Hz - 3 52Hz - 4 104Hz - 5 208Hz - 6 416Hz - 7 833Hz - 8 1660Hz - 9 3330Hz - 10 6660Hz - enum: - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 - - 8 - - 9 - - 10 + - 0 # ISM330DHCX_DT_ODR_OFF + - 1 # ISM330DHCX_DT_ODR_12Hz5 + - 2 # ISM330DHCX_DT_ODR_26H + - 3 # ISM330DHCX_DT_ODR_52Hz + - 4 # ISM330DHCX_DT_ODR_104Hz + - 5 # ISM330DHCX_DT_ODR_208Hz + - 6 # ISM330DHCX_DT_ODR_416Hz + - 7 # ISM330DHCX_DT_ODR_833Hz + - 8 # ISM330DHCX_DT_ODR_1666Hz + - 9 # ISM330DHCX_DT_ODR_3332Hz + - 10 # ISM330DHCX_DT_ODR_6667Hz + - 11 # ISM330DHCX_DT_ODR_1Hz6 + + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] accel-range: type: int @@ -69,16 +71,12 @@ properties: description: | Range in g. Default is power-up configuration. - Selection - 16 16g (0.488 mg/LSB) - 8 8g (0.244 mg/LSB) - 4 4g (0.122 mg/LSB) - 2 2g (0.061 mg/LSB) - enum: - - 16 - - 8 - - 4 - - 2 + - 16 # 16g (0.488 mg/LSB) + - 8 # 8g (0.244 mg/LSB) + - 4 # 4g (0.122 mg/LSB) + - 2 # 2g (0.061 mg/LSB) + + enum: [16, 8, 4, 2] gyro-odr: type: int @@ -87,30 +85,19 @@ properties: Specify the default gyro output data rate expressed in samples per second (Hz). Default is power-up configuration. - Selection - 0 Power-Down - 1 12.5Hz - 2 26Hz - 3 52Hz - 4 104Hz - 5 208Hz - 6 416Hz - 7 833Hz - 8 1660Hz - 9 3330Hz - 10 6660Hz - enum: - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 - - 8 - - 9 - - 10 + - 0 # ISM330DHCX_DT_ODR_OFF + - 1 # ISM330DHCX_DT_ODR_12Hz5 + - 2 # ISM330DHCX_DT_ODR_26H + - 3 # ISM330DHCX_DT_ODR_52Hz + - 4 # ISM330DHCX_DT_ODR_104Hz + - 5 # ISM330DHCX_DT_ODR_208Hz + - 6 # ISM330DHCX_DT_ODR_416Hz + - 7 # ISM330DHCX_DT_ODR_833Hz + - 8 # ISM330DHCX_DT_ODR_1666Hz + - 9 # ISM330DHCX_DT_ODR_3332Hz + - 10 # ISM330DHCX_DT_ODR_6667Hz + + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] gyro-range: type: int @@ -118,15 +105,10 @@ properties: description: | Range in dps. Default is power-up configuration. - Selection - 125 +/- 125dps - 250 +/- 250dps - 500 +/- 500dps - 1000 +/- 1000dps - 2000 +/- 2000dps - enum: - - 125 - - 250 - - 500 - - 1000 - - 2000 + - 125 # +/- 125dps + - 250 # +/- 250dps + - 500 # +/- 500dps + - 1000 # +/- 1000dps + - 2000 # +/- 2000dps + + enum: [125, 250, 500, 1000, 2000] diff --git a/dts/bindings/sensor/st,lis2dh-common.yaml b/dts/bindings/sensor/st,lis2dh-common.yaml index d86960e26d3e208..1988a7c1deb5e9b 100644 --- a/dts/bindings/sensor/st,lis2dh-common.yaml +++ b/dts/bindings/sensor/st,lis2dh-common.yaml @@ -1,6 +1,21 @@ # Copyright (c) 2018 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the int1-gpio-config/int2-gpio-config and anym-mode properties + in a .dts or .dtsi file you may include lis2dh.h and use the macros defined there. + + Example: + #include + + lis2dh: lis2dh@0 { + ... + + int1-gpio-config = ; + int2-gpio-config = ; + anym-mode = ; + }; + include: sensor-device.yaml properties: @@ -10,6 +25,40 @@ properties: The INT1 and (optional) INT2 signal connections. These signals are active-high as produced by the sensor. + int1-gpio-config: + type: int + default: 0 + description: | + Select the interrupt configuration for INT1 gpio. + + The default of 0 is the most common situation to avoid multiple interrupts + to be triggered by same event. + + - 0 # LIS2DH_DT_GPIO_INT_EDGE + - 1 # LIS2DH_DT_GPIO_INT_EDGE_RISING + - 2 # LIS2DH_DT_GPIO_INT_EDGE_FALLING + - 3 # LIS2DH_DT_GPIO_INT_LEVEL_HIGH + - 4 # LIS2DH_DT_GPIO_INT_LEVEL_LOW + + enum: [0, 1, 2, 3, 4] + + int2-gpio-config: + type: int + default: 0 + description: | + Select the interrupt configuration for INT2 gpio. + + The default of 0 is the most common situation to avoid multiple interrupts + to be triggered by same event. + + - 0 # LIS2DH_DT_GPIO_INT_EDGE + - 1 # LIS2DH_DT_GPIO_INT_EDGE_RISING + - 2 # LIS2DH_DT_GPIO_INT_EDGE_FALLING + - 3 # LIS2DH_DT_GPIO_INT_LEVEL_HIGH + - 4 # LIS2DH_DT_GPIO_INT_LEVEL_LOW + + enum: [0, 1, 2, 3, 4] + disconnect-sdo-sa0-pull-up: type: boolean description: | @@ -36,14 +85,11 @@ properties: description: | Select the interrupt mode for any movement. - 0 = OR combination of interrupt events - 1 = 6D movement recognition - 2 = AND combination of interrupt events - 3 = 6D position recognition - The default of 0 is the power-on-reset value. - enum: - - 0 - - 1 - - 2 - - 3 + + - 0 # LIS2DH_DT_ANYM_OR_COMBINATION + - 1 # LIS2DH_DT_ANYM_6D_MOVEMENT + - 2 # LIS2DH_DT_ANYM_AND_COMBINATION + - 3 # LIS2DH_DT_ANYM_6D_POSITION + + enum: [0, 1, 2, 3] diff --git a/dts/bindings/sensor/st,lis2ds12-common.yaml b/dts/bindings/sensor/st,lis2ds12-common.yaml index 4a5926c42ad21a7..230e57c0bb5d9a4 100644 --- a/dts/bindings/sensor/st,lis2ds12-common.yaml +++ b/dts/bindings/sensor/st,lis2ds12-common.yaml @@ -1,6 +1,20 @@ # Copyright (c) 2021 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the odr and power-mode properties in a .dts or .dtsi file you may include + lis2ds12.h and use the macros defined there. + + Example: + #include + + lis2ds12: lis2ds12@0 { + ... + + power-mode = ; + odr = ; + }; + include: sensor-device.yaml properties: @@ -19,23 +33,25 @@ properties: description: | Range in g. Default is power-up configuration. - enum: - 16 # 16g (0.488 mg/LSB) - 8 # 8g (0.244 mg/LSB) - 4 # 4g (0.122 mg/LSB) - 2 # 2g (0.061 mg/LSB) + enum: [16, 8, 4, 2] + power-mode: type: int default: 0 description: | Specify the sensor power mode. Default is power-down mode - enum: - - 0 # Power Down (PD) - - 1 # Low Power (LP) - - 2 # High Resolution (HR) - - 3 # High Frequency (HF) + - 0 # LIS2DS12_DT_POWER_DOWN + - 1 # LIS2DS12_DT_LOW_POWER + - 2 # LIS2DS12_DT_HIGH_RESOLUTION + - 3 # LIS2DS12_DT_HIGH_FREQUENCY + + enum: [0, 1, 2, 3] odr: type: int @@ -43,16 +59,18 @@ properties: description: | Specify the default output data rate expressed in samples per second (Hz). Default is power-down mode - enum: - - 0 # Power-Down - - 1 # 1Hz (available in LP mode only) - - 2 # 12.5Hz (available in LP and HR mode) - - 3 # 25Hz (available in LP and HR mode) - - 4 # 50Hz (available in LP and HR mode) - - 5 # 100Hz (available in LP and HR mode) - - 6 # 200Hz (available in LP and HR mode) - - 7 # 400Hz (available in LP and HR mode) - - 8 # 800Hz (available in LP and HR mode) - - 9 # 1600Hz (available in HF mode only) - - 10 # 3200Hz (available in HF mode only) - - 11 # 6400Hz (available in HF mode only) + + - 0 # LIS2DS12_DT_ODR_OFF + - 1 # LIS2DS12_DT_ODR_1Hz_LP + - 2 # LIS2DS12_DT_ODR_12Hz5 + - 3 # LIS2DS12_DT_ODR_25Hz + - 4 # LIS2DS12_DT_ODR_50Hz + - 5 # LIS2DS12_DT_ODR_100Hz + - 6 # LIS2DS12_DT_ODR_200Hz + - 7 # LIS2DS12_DT_ODR_400Hz + - 8 # LIS2DS12_DT_ODR_800Hz + - 9 # LIS2DS12_DT_ODR_1600Hz + - 10 # LIS2DS12_DT_ODR_3200Hz_HF + - 11 # LIS2DS12_DT_ODR_6400Hz_HF + + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] diff --git a/dts/bindings/sensor/st,lis2du12-common.yaml b/dts/bindings/sensor/st,lis2du12-common.yaml new file mode 100644 index 000000000000000..d9ca38d9e32fdec --- /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 # 1Hz6 (ultra low power) + 0x02 # 3Hz (ultra low power) + 0x03 # 25Hz (ultra low power) + 0x04 # 6Hz (low power) + 0x05 # 12Hz5 (low power) + 0x06 # 25Hz (low power) + 0x07 # 50Hz (low power) + 0x08 # 100Hz (low power) + 0x09 # 200Hz (low power) + 0x0a # 400Hz (low power) + 0x0b # 800Hz (low power) + 0x0e # Single-shot high latency by INT2 + 0x0f # Single-shot high latency by IF + + 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 000000000000000..ad09f2601c39f4e --- /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 000000000000000..0fad5696827b23a --- /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 635e9d9e9d5afd2..c95a97da3987ccd 100644 --- a/dts/bindings/sensor/st,lis2dw12-common.yaml +++ b/dts/bindings/sensor/st,lis2dw12-common.yaml @@ -1,6 +1,23 @@ # Copyright (c) 2021 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the odr property in a .dts or .dtsi file you may include + lis2dw12.h and use the macros defined there. + + Example: + #include + + lis2dw12: lis2dw12@0 { + ... + + wakeup-duration = ; + ff-threshold = ; + tap-mode = ; + power-mode = ; + bw-filt = ; + }; + include: sensor-device.yaml properties: @@ -16,9 +33,8 @@ properties: int-pin: type: int default: 1 - enum: - - 1 - - 2 + enum: [1, 2] + description: | Select DRDY pin number (1 or 2). @@ -41,11 +57,7 @@ properties: 4 # 4g (0.488 mg/LSB) 2 # 2g (0.244 mg/LSB) - enum: - - 16 - - 8 - - 4 - - 2 + enum: [16, 8, 4, 2] odr: type: int @@ -56,17 +68,7 @@ properties: If 0 selected as the odr, the accelerometer initializes into power off state. - enum: - - 0 - - 1 - - 12 - - 25 - - 50 - - 100 - - 200 - - 400 - - 800 - - 1600 + enum: [0, 1, 12, 25, 50, 100, 200, 400, 800, 1600] bw-filt: type: int @@ -74,16 +76,12 @@ properties: description: | Digital filtering cutoff bandwidth. Default is power-up configuration. - 3 # ODR/20 (HP/LP) - 2 # ODR/10 (HP/LP) - 1 # ODR/ 4 (HP/LP) - 0 # ODR/ 2 (up to ODR = 800 Hz, 400 Hz when ODR = 1600 Hz) + - 0 # LIS2DW12_DT_FILTER_BW_ODR_DIV_2 + - 1 # LIS2DW12_DT_FILTER_BW_ODR_DIV_4 + - 2 # LIS2DW12_DT_FILTER_BW_ODR_DIV_10 + - 3 # LIS2DW12_DT_FILTER_BW_ODR_DIV_20 - enum: - - 3 - - 2 - - 1 - - 0 + enum: [0, 1, 2, 3] power-mode: type: int @@ -91,18 +89,13 @@ properties: description: | Specify the sensor power mode. Default is power-up configuration. - 0 # Low Power M1 - 1 # Low Power M2 - 2 # Low Power M3 - 3 # Low Power M4 - 4 # High Performance + - 0 # LIS2DW12_DT_LP_M1 + - 1 # LIS2DW12_DT_LP_M2 + - 2 # LIS2DW12_DT_LP_M3 + - 3 # LIS2DW12_DT_LP_M4 + - 4 # LIS2DW12_DT_HP_MODE - enum: - - 0 - - 1 - - 2 - - 3 - - 4 + enum: [0, 1, 2, 3, 4] # tap and tap-tap configuration section # All default values are selected to match the power-up values. @@ -114,12 +107,10 @@ properties: description: | Tap mode. Default is power-up configuration. - 0 # Only Single Tap - 1 # Single and Double Tap + - 0 # LIS2DW12_DT_SINGLE_TAP + - 1 # LIS2DW12_DT_SINGLE_DOUBLE_TAP - enum: - - 0 - - 1 + enum: [0, 1] tap-threshold: type: array @@ -228,21 +219,31 @@ properties: than the freefall threshold value for the freefall duration long, then a freefall trigger occurs. This value is 3 bits long. Default value chosen 3 (312 mg) refer to ST DT0100 design tip document. - 0 # ~156mg - 1 # ~219mg - 2 # ~250mg - 3 # ~312mg - 4 # ~344mg - 5 # ~406mg - 6 # ~469mg - 7 # ~500mg - - enum: - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 + + - 0 # LIS2DW12_DT_FF_THRESHOLD_156_mg + - 1 # LIS2DW12_DT_FF_THRESHOLD_219_mg + - 2 # LIS2DW12_DT_FF_THRESHOLD_250_mg + - 3 # LIS2DW12_DT_FF_THRESHOLD_312_mg + - 4 # LIS2DW12_DT_FF_THRESHOLD_344_mg + - 5 # LIS2DW12_DT_FF_THRESHOLD_406_mg + - 6 # LIS2DW12_DT_FF_THRESHOLD_469_mg + - 7 # LIS2DW12_DT_FF_THRESHOLD_500_mg + + enum: [0, 1, 2, 3, 4, 5, 6, 7] + + wakeup-duration: + type: int + default: 0 + description: | + The wakeup duration. Default value is the register reset value. + If the accelerometer readings of the all axes are higher + than the wakeup threshold value for the wakeup duration long, + then a wakeup trigger occurs. This value is 2 bits long in the + register and 1 LSB = 1 * 1/ODR. + + - 0 # LIS2DW12_DT_WAKEUP_1_ODR + - 1 # LIS2DW12_DT_WAKEUP_2_ODR + - 2 # LIS2DW12_DT_WAKEUP_3_ODR + - 3 # LIS2DW12_DT_WAKEUP_4_ODR + + enum: [0, 1, 2, 3] diff --git a/dts/bindings/sensor/st,lis2mdl-common.yaml b/dts/bindings/sensor/st,lis2mdl-common.yaml index 4fe9e877bbca6bb..53e0d723d93c95e 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 new file mode 100644 index 000000000000000..779d877f9013348 --- /dev/null +++ b/dts/bindings/sensor/st,lps22df-common.yaml @@ -0,0 +1,87 @@ +# 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 lps22df.h and use the macros defined there. + + Example: + #include + + lps22df@5d { + ... + + odr = ; + lpf = ; + avg = ; + }; + +include: sensor-device.yaml + +properties: + drdy-gpios: + type: phandle-array + description: | + DRDY 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-pulsed: + type: boolean + description: | + Selects the pulsed mode for data-ready interrupt when enabled, + and the latched mode when disabled. + + odr: + type: int + default: 0 + description: | + Specify the output data rate expressed in samples per second (Hz). + The default is the power-on reset value. + + - 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] + + lpf: + type: int + default: 0 + description: | + Specify the low pass filter value to be applied to pressure data. + The default is the power-on reset value. + + - 0 # LPS2xDF_DT_LP_FILTER_OFF + - 1 # LPS2xDF_DT_LP_FILTER_ODR_4 + - 3 # LPS2xDF_DT_LP_FILTER_ODR_9 + + enum: [0, 1, 3] + + avg: + type: int + default: 0 + description: | + Specify the average filter value (i.e. number of samples) to be applied + to pressure and temperature data. + The default is the power-on reset value. + + - 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,lps22df-i2c.yaml b/dts/bindings/sensor/st,lps22df-i2c.yaml new file mode 100644 index 000000000000000..11074528cf34fa8 --- /dev/null +++ b/dts/bindings/sensor/st,lps22df-i2c.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LPS22DF pressure and temperature sensor connected to I2C + bus + +compatible: "st,lps22df" + +include: ["i2c-device.yaml", "st,lps22df-common.yaml"] diff --git a/dts/bindings/sensor/st,lps22df-i3c.yaml b/dts/bindings/sensor/st,lps22df-i3c.yaml new file mode 100644 index 000000000000000..6bba397e0bea363 --- /dev/null +++ b/dts/bindings/sensor/st,lps22df-i3c.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LPS22DF pressure and temperature sensor connected to I3C + bus + +compatible: "st,lps22df" + +include: ["i3c-device.yaml", "st,lps22df-common.yaml"] diff --git a/dts/bindings/sensor/st,lps22df-spi.yaml b/dts/bindings/sensor/st,lps22df-spi.yaml new file mode 100644 index 000000000000000..219738d0e950f13 --- /dev/null +++ b/dts/bindings/sensor/st,lps22df-spi.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LPS22DF pressure and temperature sensor connected to SPI + bus + +compatible: "st,lps22df" + +include: ["spi-device.yaml", "st,lps22df-common.yaml"] diff --git a/dts/bindings/sensor/st,lps22hh-common.yaml b/dts/bindings/sensor/st,lps22hh-common.yaml index a704eac46aea2df..a5e27c30b30d03d 100644 --- a/dts/bindings/sensor/st,lps22hh-common.yaml +++ b/dts/bindings/sensor/st,lps22hh-common.yaml @@ -1,6 +1,19 @@ # Copyright (c) 2021 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the odr property in a .dts or .dtsi file you may include + lps22hh.h and use the macros defined there. + + Example: + #include + + lps22hh: lps22hh@0 { + ... + + odr = ; + }; + include: sensor-device.yaml properties: @@ -19,12 +32,14 @@ properties: description: | Specify the default output data rate expressed in samples per second (Hz). The default is the power-on reset value. - enum: - - 0 # Power-Down - - 1 # 1Hz - - 2 # 10Hz - - 3 # 25Hz - - 4 # 50Hz - - 5 # 75Hz - - 6 # 100Hz - - 7 # 200Hz + + - 0 # LPS22HH_DT_ODR_POWER_DOWN + - 1 # LPS22HH_DT_ODR_1HZ + - 2 # LPS22HH_DT_ODR_10HZ + - 3 # LPS22HH_DT_ODR_25HZ + - 4 # LPS22HH_DT_ODR_50HZ + - 5 # LPS22HH_DT_ODR_75HZ + - 6 # LPS22HH_DT_ODR_100HZ + - 7 # LPS22HH_DT_ODR_200HZ + + enum: [0, 1, 2, 3, 4, 5, 6, 7] diff --git a/dts/bindings/sensor/st,lps28dfw-common.yaml b/dts/bindings/sensor/st,lps28dfw-common.yaml new file mode 100644 index 000000000000000..1ca646fab66e502 --- /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 000000000000000..0c47d7b27f62049 --- /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 000000000000000..8c3fdb1946dcb08 --- /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 e8de1e9a75df113..fe1c4d90ab1b98f 100644 --- a/dts/bindings/sensor/st,lsm6dso-common.yaml +++ b/dts/bindings/sensor/st,lsm6dso-common.yaml @@ -1,6 +1,25 @@ # Copyright (c) 2021 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +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 lsm6dso.h + and use the macros defined there. + + Example: + #include + + lsm6dso: lsm6dso@0 { + ... + + accel-pm = ; + accel-range = ; + accel-odr = ; + gyro-pm = ; + gyro-range = ; + gyro-odr = ; + }; + include: sensor-device.yaml properties: @@ -33,21 +52,25 @@ properties: description: | Specify the accelerometer power mode. Default is power-up configuration. - enum: - - 0 # High Performance mode (default) - - 1 # Low/Normal Power mode - - 2 # Ultra Low Power mode + + - 0 # LSM6DSO_DT_XL_HP_MODE + - 1 # LSM6DSO_DT_XL_LP_NORMAL_MODE + - 2 # LSM6DSO_DT_XL_ULP_MODE + + enum: [0, 1, 2] accel-range: type: int default: 0 description: | Range in g. Default is power-up configuration. - enum: - - 0 # 2g (0.061 mg/LSB) (LSM6DSO32 will be double these values) - - 1 # 16g (0.488 mg/LSB) - - 2 # 4g (0.122 mg/LSB) - - 3 # 8g (0.244 mg/LSB) + + - 0 # LSM6DSO_DT_FS_2G (0.061 mg/LSB) (LSM6DSO32 will be double these values) + - 1 # LSM6DSO_DT_FS_16G (0.488 mg/LSB) + - 2 # LSM6DSO_DT_FS_4G (0.122 mg/LSB) + - 3 # LSM6DSO_DT_FS_8G (0.244 mg/LSB) + + enum: [0, 1, 2, 3] accel-odr: type: int @@ -55,18 +78,21 @@ properties: description: | Specify the default accelerometer output data rate expressed in samples per second (Hz). Default is power-up configuration. - enum: - - 0 # Power-Down - - 1 # 12.5Hz - - 2 # 26Hz - - 3 # 52Hz - - 4 # 104Hz - - 5 # 208Hz - - 6 # 417Hz - - 7 # 833Hz - - 8 # 1667Hz - - 9 # 3333Hz - - 10 # 6667Hz + + - 0 # LSM6DSO_DT_ODR_OFF + - 1 # LSM6DSO_DT_ODR_12Hz5 + - 2 # LSM6DSO_DT_ODR_26H + - 3 # LSM6DSO_DT_ODR_52Hz + - 4 # LSM6DSO_DT_ODR_104Hz + - 5 # LSM6DSO_DT_ODR_208Hz + - 6 # LSM6DSO_DT_ODR_417Hz + - 7 # LSM6DSO_DT_ODR_833Hz + - 8 # LSM6DSO_DT_ODR_1667Hz + - 9 # LSM6DSO_DT_ODR_3333Hz + - 10 # LSM6DSO_DT_ODR_6667Hz + - 11 # LSM6DSO_DT_ODR_1Hz6 + + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] gyro-pm: type: int @@ -74,21 +100,25 @@ properties: description: | Specify the gyrometer power mode. Default is power-up configuration. - enum: - - 0 # High Performance mode (default) - - 1 # Low/Normal Power mode + + - 0 # LSM6DSO_DT_GY_HP_MODE + - 1 # LSM6DSO_DT_GY_NORMAL_MODE + + enum: [0, 1] gyro-range: type: int default: 0 description: | Range in dps. Default is power-up configuration. - enum: - - 0 # 250 dps (8.75 mdps/LSB) - - 1 # 125 dps (4.375 mdps/LSB) - - 2 # 500 dps (17.50 mdps/LSB) - - 4 # 1000 dps (35 mdps/LSB) - - 6 # 2000 dps (70 mdps/LSB) + + - 0 # LSM6DSO_DT_FS_250DPS (8.75 mdps/LSB) + - 1 # LSM6DSO_DT_FS_125DPS (4.375 mdps/LSB) + - 2 # LSM6DSO_DT_FS_500DPS (17.50 mdps/LSB) + - 4 # LSM6DSO_DT_FS_1000DPS (35 mdps/LSB) + - 6 # LSM6DSO_DT_FS_2000DPS (70 mdps/LSB) + + enum: [0, 1, 2, 4, 6] gyro-odr: type: int @@ -96,18 +126,20 @@ properties: description: | Specify the default gyro output data rate expressed in samples per second (Hz). Default is power-up configuration. - enum: - - 0 # Power-Down - - 1 # 12.5Hz - - 2 # 26Hz - - 3 # 52Hz - - 4 # 104Hz - - 5 # 208Hz - - 6 # 417Hz - - 7 # 833Hz - - 8 # 1667Hz - - 9 # 3333Hz - - 10 # 6667Hz + + - 0 # LSM6DSO_DT_ODR_OFF + - 1 # LSM6DSO_DT_ODR_12Hz5 + - 2 # LSM6DSO_DT_ODR_26H + - 3 # LSM6DSO_DT_ODR_52Hz + - 4 # LSM6DSO_DT_ODR_104Hz + - 5 # LSM6DSO_DT_ODR_208Hz + - 6 # LSM6DSO_DT_ODR_417Hz + - 7 # LSM6DSO_DT_ODR_833Hz + - 8 # LSM6DSO_DT_ODR_1667Hz + - 9 # LSM6DSO_DT_ODR_3333Hz + - 10 # LSM6DSO_DT_ODR_6667Hz + + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] drdy-pulsed: type: boolean diff --git a/dts/bindings/sensor/st,lsm6dso16is-common.yaml b/dts/bindings/sensor/st,lsm6dso16is-common.yaml index 16304b5692c0b4f..07c1f21adeff148 100644 --- a/dts/bindings/sensor/st,lsm6dso16is-common.yaml +++ b/dts/bindings/sensor/st,lsm6dso16is-common.yaml @@ -1,6 +1,23 @@ # Copyright (c) 2023 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the accel-range, accel-odr, gyro-range, gyro-odr properties in + a .dts or .dtsi file you may include lsm6dso16is.h and use the macros + defined there. + + Example: + #include + + lsm6dso16is: lsm6dso16is@0 { + ... + + accel-range = ; + accel-odr = ; + gyro-range = ; + gyro-odr = ; + }; + include: sensor-device.yaml properties: @@ -32,11 +49,13 @@ properties: default: 0 description: | Range in g. Default is power-up configuration. - enum: - - 0 # 2g (0.061 mg/LSB) - - 1 # 16g (0.488 mg/LSB) - - 2 # 4g (0.122 mg/LSB) - - 3 # 8g (0.244 mg/LSB) + + - 0 # LSM6DSO16IS_DT_FS_2G (0.061 mg/LSB) + - 1 # LSM6DSO16IS_DT_FS_16G (0.488 mg/LSB) + - 2 # LSM6DSO16IS_DT_FS_4G (0.122 mg/LSB) + - 3 # LSM6DSO16IS_DT_FS_8G (0.244 mg/LSB) + + enum: [0, 1, 2, 3] accel-odr: type: int @@ -46,41 +65,46 @@ properties: The values are taken in accordance to lsm6dso16is_xl_data_rate_t enumerative in hal/st module. Default is power-up configuration. - enum: - - 0x00 # Power-Down - - 0x01 # 12.5Hz High Performance - - 0x02 # 26Hz High Performance - - 0x03 # 52Hz High Performance - - 0x04 # 104Hz High Performance - - 0x05 # 208Hz High Performance - - 0x06 # 417Hz High Performance - - 0x07 # 833Hz High Performance - - 0x08 # 1667Hz High Performance - - 0x09 # 3333Hz High Performance - - 0x0a # 6667Hz High Performance - - 0x11 # 12.5Hz Low Power - - 0x12 # 26Hz Low Power - - 0x13 # 52Hz Low Power - - 0x14 # 104Hz Low Power - - 0x15 # 208Hz Low Power - - 0x16 # 417Hz Low Power - - 0x17 # 833Hz Low Power - - 0x18 # 1667Hz Low Power - - 0x19 # 3333Hz Low Power - - 0x1a # 6667Hz Low Power - - 0x1b # 1Hz6 Low Power + + - 0x00 # LSM6DSO16IS_DT_ODR_OFF + - 0x01 # LSM6DSO16IS_DT_ODR_12Hz5_HP + - 0x02 # LSM6DSO16IS_DT_ODR_26H_HP + - 0x03 # LSM6DSO16IS_DT_ODR_52Hz_HP + - 0x04 # LSM6DSO16IS_DT_ODR_104Hz_HP + - 0x05 # LSM6DSO16IS_DT_ODR_208Hz_HP + - 0x06 # LSM6DSO16IS_DT_ODR_416Hz_HP + - 0x07 # LSM6DSO16IS_DT_ODR_833Hz_HP + - 0x08 # LSM6DSO16IS_DT_ODR_1667Hz_HP + - 0x09 # LSM6DSO16IS_DT_ODR_3333Hz_HP + - 0x0a # LSM6DSO16IS_DT_ODR_6667Hz_HP + - 0x11 # LSM6DSO16IS_DT_ODR_12Hz5_LP + - 0x12 # LSM6DSO16IS_DT_ODR_26H_LP + - 0x13 # LSM6DSO16IS_DT_ODR_52Hz_LP + - 0x14 # LSM6DSO16IS_DT_ODR_104Hz_LP + - 0x15 # LSM6DSO16IS_DT_ODR_208Hz_LP + - 0x16 # LSM6DSO16IS_DT_ODR_416Hz_LP + - 0x17 # LSM6DSO16IS_DT_ODR_833Hz_LP + - 0x18 # LSM6DSO16IS_DT_ODR_1667Hz_LP + - 0x19 # LSM6DSO16IS_DT_ODR_3333Hz_LP + - 0x1a # LSM6DSO16IS_DT_ODR_6667Hz_LP + - 0x1b # LSM6DSO16IS_DT_ODR_1Hz6_LP + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b] gyro-range: type: int default: 0 description: | Range in dps. Default is power-up configuration. - enum: - - 0 # 250 dps (8.75 mdps/LSB) - - 1 # 125 dps (4.375 mdps/LSB) - - 2 # 500 dps (17.50 mdps/LSB) - - 4 # 1000 dps (35 mdps/LSB) - - 6 # 2000 dps (70 mdps/LSB) + + - 0x0 # LSM6DSO16IS_DT_FS_250DPS (8.75 mdps/LSB) + - 0x1 # LSM6DSO16IS_DT_FS_500DPS (17.50 mdps/LSB) + - 0x2 # LSM6DSO16IS_DT_FS_1000DPS (35 mdps/LSB) + - 0x3 # LSM6DSO16IS_DT_FS_2000DPS (70 mdps/LSB) + - 0x10 # LSM6DSO16IS_DT_FS_125DPS (4.375 mdps/LSB) + + enum: [0x0, 0x1, 0x2, 0x3, 0x10] gyro-odr: type: int @@ -90,28 +114,31 @@ properties: The values are taken in accordance to lsm6dso16is_gy_data_rate_t enumerative in hal/st module. Default is power-up configuration. - enum: - - 0x00 # Power-Down - - 0x01 # 12.5Hz High Performance - - 0x02 # 26Hz High Performance - - 0x03 # 52Hz High Performance - - 0x04 # 104Hz High Performance - - 0x05 # 208Hz High Performance - - 0x06 # 417Hz High Performance - - 0x07 # 833Hz High Performance - - 0x08 # 1667Hz High Performance - - 0x09 # 3333Hz High Performance - - 0x0a # 6667Hz High Performance - - 0x11 # 12.5Hz Low Power - - 0x12 # 26Hz Low Power - - 0x13 # 52Hz Low Power - - 0x14 # 104Hz Low Power - - 0x15 # 208Hz Low Power - - 0x16 # 417Hz Low Power - - 0x17 # 833Hz Low Power - - 0x18 # 1667Hz Low Power - - 0x19 # 3333Hz Low Power - - 0x1a # 6667Hz Low Power + + - 0x00 # LSM6DSO16IS_DT_ODR_OFF + - 0x01 # LSM6DSO16IS_DT_ODR_12Hz5_HP + - 0x02 # LSM6DSO16IS_DT_ODR_26H_HP + - 0x03 # LSM6DSO16IS_DT_ODR_52Hz_HP + - 0x04 # LSM6DSO16IS_DT_ODR_104Hz_HP + - 0x05 # LSM6DSO16IS_DT_ODR_208Hz_HP + - 0x06 # LSM6DSO16IS_DT_ODR_416Hz_HP + - 0x07 # LSM6DSO16IS_DT_ODR_833Hz_HP + - 0x08 # LSM6DSO16IS_DT_ODR_1667Hz_HP + - 0x09 # LSM6DSO16IS_DT_ODR_3333Hz_HP + - 0x0a # LSM6DSO16IS_DT_ODR_6667Hz_HP + - 0x11 # LSM6DSO16IS_DT_ODR_12Hz5_LP + - 0x12 # LSM6DSO16IS_DT_ODR_26H_LP + - 0x13 # LSM6DSO16IS_DT_ODR_52Hz_LP + - 0x14 # LSM6DSO16IS_DT_ODR_104Hz_LP + - 0x15 # LSM6DSO16IS_DT_ODR_208Hz_LP + - 0x16 # LSM6DSO16IS_DT_ODR_416Hz_LP + - 0x17 # LSM6DSO16IS_DT_ODR_833Hz_LP + - 0x18 # LSM6DSO16IS_DT_ODR_1667Hz_LP + - 0x19 # LSM6DSO16IS_DT_ODR_3333Hz_LP + - 0x1a # LSM6DSO16IS_DT_ODR_6667Hz_LP + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a] drdy-pulsed: type: boolean diff --git a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml index d12e8c324269ae8..84c0dce96a713be 100644 --- a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml +++ b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml @@ -1,13 +1,39 @@ # Copyright (c) 2023 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +description: | + When setting the accel-range, accel-odr, gyro-range, gyro-odr properties in + a .dts or .dtsi file you may include lsm6dsv16x.h and use the macros + defined there. + + Example: + #include + + lsm6dsv16x: lsm6dsv16x@0 { + ... + + accel-range = ; + accel-odr = ; + gyro-range = ; + gyro-odr = ; + }; + include: sensor-device.yaml properties: - irq-gpios: + 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: | - DRDY pin + INT2 pin This pin defaults to active high when produced by the sensor. The property value should ensure the flags properly describe @@ -32,11 +58,13 @@ properties: default: 0 description: | Range in g. Default is power-up configuration. - enum: - - 0 # 2g (0.061 mg/LSB) - - 1 # 4g (0.122 mg/LSB) - - 2 # 8g (0.244 mg/LSB) - - 3 # 16g (0.488 mg/LSB) + + - 0 # LSM6DSV16X_DT_FS_2G (0.061 mg/LSB) + - 1 # LSM6DSV16X_DT_FS_4G (0.122 mg/LSB) + - 2 # LSM6DSV16X_DT_FS_8G (0.244 mg/LSB) + - 3 # LSM6DSV16X_DT_FS_16G (0.488 mg/LSB) + + enum: [0, 1, 2, 3] accel-odr: type: int @@ -47,53 +75,59 @@ properties: module. Please note that this values will not change the operating mode, which will remain High Performance (device default) Default is power-up configuration. - enum: - - 0x00 # Power-Down - - 0x01 # 1Hz875 - - 0x02 # 7Hz5 - - 0x03 # 15Hz - - 0x04 # 30Hz - - 0x05 # 60Hz - - 0x06 # 120Hz - - 0x07 # 240Hz - - 0x08 # 480Hz - - 0x09 # 960Hz - - 0x0a # 1920Hz - - 0x0b # 3840Hz - - 0x0c # 7680Hz - - 0x13 # 15Hz625 (High Accuracy 1) - - 0x14 # 31Hz25 (High Accuracy 1) - - 0x15 # 62Hz5 (High Accuracy 1) - - 0x16 # 125Hz (High Accuracy 1) - - 0x17 # 250Hz (High Accuracy 1) - - 0x18 # 500Hz (High Accuracy 1) - - 0x19 # 1000Hz (High Accuracy 1) - - 0x1a # 2000Hz (High Accuracy 1) - - 0x1b # 4000Hz (High Accuracy 1) - - 0x1c # 8000Hz (High Accuracy 1) - - 0x23 # 12Hz5 (High Accuracy 2) - - 0x24 # 25Hz (High Accuracy 2) - - 0x25 # 50Hz (High Accuracy 2) - - 0x26 # 100Hz (High Accuracy 2) - - 0x27 # 200Hz (High Accuracy 2) - - 0x28 # 400Hz (High Accuracy 2) - - 0x29 # 800Hz (High Accuracy 2) - - 0x2a # 1600Hz (High Accuracy 2) - - 0x2b # 3200Hz (High Accuracy 2) - - 0x2c # 6400Hz (High Accuracy 2) + + - 0x00 # LSM6DSV16X_DT_ODR_OFF + - 0x01 # LSM6DSV16X_DT_ODR_AT_1Hz875 + - 0x02 # LSM6DSV16X_DT_ODR_AT_7Hz5 + - 0x03 # LSM6DSV16X_DT_ODR_AT_15Hz + - 0x04 # LSM6DSV16X_DT_ODR_AT_30Hz + - 0x05 # LSM6DSV16X_DT_ODR_AT_60Hz + - 0x06 # LSM6DSV16X_DT_ODR_AT_120Hz + - 0x07 # LSM6DSV16X_DT_ODR_AT_240Hz + - 0x08 # LSM6DSV16X_DT_ODR_AT_480Hz + - 0x09 # LSM6DSV16X_DT_ODR_AT_960Hz + - 0x0a # LSM6DSV16X_DT_ODR_AT_1920Hz + - 0x0b # LSM6DSV16X_DT_ODR_AT_3840Hz + - 0x0c # LSM6DSV16X_DT_ODR_AT_7680Hz + - 0x13 # LSM6DSV16X_DT_ODR_HA01_AT_15Hz625 + - 0x14 # LSM6DSV16X_DT_ODR_HA01_AT_31Hz25 + - 0x15 # LSM6DSV16X_DT_ODR_HA01_AT_62Hz5 + - 0x16 # LSM6DSV16X_DT_ODR_HA01_AT_125Hz + - 0x17 # LSM6DSV16X_DT_ODR_HA01_AT_250Hz + - 0x18 # LSM6DSV16X_DT_ODR_HA01_AT_500Hz + - 0x19 # LSM6DSV16X_DT_ODR_HA01_AT_1000Hz + - 0x1a # LSM6DSV16X_DT_ODR_HA01_AT_2000Hz + - 0x1b # LSM6DSV16X_DT_ODR_HA01_AT_4000Hz + - 0x1c # LSM6DSV16X_DT_ODR_HA01_AT_8000Hz + - 0x23 # LSM6DSV16X_DT_ODR_HA02_AT_12Hz5 + - 0x24 # LSM6DSV16X_DT_ODR_HA02_AT_25Hz + - 0x25 # LSM6DSV16X_DT_ODR_HA02_AT_50Hz + - 0x26 # LSM6DSV16X_DT_ODR_HA02_AT_100Hz + - 0x27 # LSM6DSV16X_DT_ODR_HA02_AT_200Hz + - 0x28 # LSM6DSV16X_DT_ODR_HA02_AT_400Hz + - 0x29 # LSM6DSV16X_DT_ODR_HA02_AT_800Hz + - 0x2a # LSM6DSV16X_DT_ODR_HA02_AT_1600Hz + - 0x2b # LSM6DSV16X_DT_ODR_HA02_AT_3200Hz + - 0x2c # LSM6DSV16X_DT_ODR_HA02_AT_6400Hz + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, + 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c] gyro-range: type: int default: 0 description: | Range in dps. Default is power-up configuration. - enum: - - 0 # 125 dps (4.375 mdps/LSB) - - 1 # 250 dps (8.75 mdps/LSB) - - 2 # 500 dps (17.50 mdps/LSB) - - 3 # 1000 dps (35 mdps/LSB) - - 4 # 2000 dps (70 mdps/LSB) - - 5 # 4000 dps (140 mdps/LSB) + + - 0x0 # LSM6DSV16X_DT_FS_125DPS (4.375 mdps/LSB) + - 0x1 # LSM6DSV16X_DT_FS_250DPS (8.75 mdps/LSB) + - 0x2 # LSM6DSV16X_DT_FS_500DPS (17.50 mdps/LSB) + - 0x3 # LSM6DSV16X_DT_FS_1000DPS (35 mdps/LSB) + - 0x4 # LSM6DSV16X_DT_FS_2000DPS (70 mdps/LSB) + - 0xc # LSM6DSV16X_DT_FS_4000DPS (140 mdps/LSB) + + enum: [0x0, 0x1, 0x2, 0x3, 0x4, 0xc] gyro-odr: type: int @@ -101,44 +135,49 @@ 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. - enum: - - 0x00 # Power-Down - - 0x02 # 7Hz5 - - 0x03 # 15Hz - - 0x04 # 30Hz - - 0x05 # 60Hz - - 0x06 # 120Hz - - 0x07 # 240Hz - - 0x08 # 480Hz - - 0x09 # 960Hz - - 0x0a # 1920Hz - - 0x0b # 3840Hz - - 0x0c # 7680Hz - - 0x13 # 15Hz625 (High Accuracy 1) - - 0x14 # 31Hz25 (High Accuracy 1) - - 0x15 # 62Hz5 (High Accuracy 1) - - 0x16 # 125Hz (High Accuracy 1) - - 0x17 # 250Hz (High Accuracy 1) - - 0x18 # 500Hz (High Accuracy 1) - - 0x19 # 1000Hz (High Accuracy 1) - - 0x1a # 2000Hz (High Accuracy 1) - - 0x1b # 4000Hz (High Accuracy 1) - - 0x1c # 8000Hz (High Accuracy 1) - - 0x23 # 12Hz5 (High Accuracy 2) - - 0x24 # 25Hz (High Accuracy 2) - - 0x25 # 50Hz (High Accuracy 2) - - 0x26 # 100Hz (High Accuracy 2) - - 0x27 # 200Hz (High Accuracy 2) - - 0x28 # 400Hz (High Accuracy 2) - - 0x29 # 800Hz (High Accuracy 2) - - 0x2a # 1600Hz (High Accuracy 2) - - 0x2b # 3200Hz (High Accuracy 2) - - 0x2c # 6400Hz (High Accuracy 2) + + - 0x00 # LSM6DSV16X_DT_ODR_OFF + - 0x01 # LSM6DSV16X_DT_ODR_AT_1Hz875 + - 0x02 # LSM6DSV16X_DT_ODR_AT_7Hz5 + - 0x03 # LSM6DSV16X_DT_ODR_AT_15Hz + - 0x04 # LSM6DSV16X_DT_ODR_AT_30Hz + - 0x05 # LSM6DSV16X_DT_ODR_AT_60Hz + - 0x06 # LSM6DSV16X_DT_ODR_AT_120Hz + - 0x07 # LSM6DSV16X_DT_ODR_AT_240Hz + - 0x08 # LSM6DSV16X_DT_ODR_AT_480Hz + - 0x09 # LSM6DSV16X_DT_ODR_AT_960Hz + - 0x0a # LSM6DSV16X_DT_ODR_AT_1920Hz + - 0x0b # LSM6DSV16X_DT_ODR_AT_3840Hz + - 0x0c # LSM6DSV16X_DT_ODR_AT_7680Hz + - 0x13 # LSM6DSV16X_DT_ODR_HA01_AT_15Hz625 + - 0x14 # LSM6DSV16X_DT_ODR_HA01_AT_31Hz25 + - 0x15 # LSM6DSV16X_DT_ODR_HA01_AT_62Hz5 + - 0x16 # LSM6DSV16X_DT_ODR_HA01_AT_125Hz + - 0x17 # LSM6DSV16X_DT_ODR_HA01_AT_250Hz + - 0x18 # LSM6DSV16X_DT_ODR_HA01_AT_500Hz + - 0x19 # LSM6DSV16X_DT_ODR_HA01_AT_1000Hz + - 0x1a # LSM6DSV16X_DT_ODR_HA01_AT_2000Hz + - 0x1b # LSM6DSV16X_DT_ODR_HA01_AT_4000Hz + - 0x1c # LSM6DSV16X_DT_ODR_HA01_AT_8000Hz + - 0x23 # LSM6DSV16X_DT_ODR_HA02_AT_12Hz5 + - 0x24 # LSM6DSV16X_DT_ODR_HA02_AT_25Hz + - 0x25 # LSM6DSV16X_DT_ODR_HA02_AT_50Hz + - 0x26 # LSM6DSV16X_DT_ODR_HA02_AT_100Hz + - 0x27 # LSM6DSV16X_DT_ODR_HA02_AT_200Hz + - 0x28 # LSM6DSV16X_DT_ODR_HA02_AT_400Hz + - 0x29 # LSM6DSV16X_DT_ODR_HA02_AT_800Hz + - 0x2a # LSM6DSV16X_DT_ODR_HA02_AT_1600Hz + - 0x2b # LSM6DSV16X_DT_ODR_HA02_AT_3200Hz + - 0x2c # LSM6DSV16X_DT_ODR_HA02_AT_6400Hz + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, + 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c] drdy-pulsed: type: boolean diff --git a/dts/bindings/sensor/tdk,ntcg163jf103ft1.yaml b/dts/bindings/sensor/tdk,ntcg163jf103ft1.yaml new file mode 100644 index 000000000000000..88883e14706db66 --- /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 16032b625cf3593..e92f0d092084ea2 100644 --- a/dts/bindings/sensor/ti,bq274xx.yaml +++ b/dts/bindings/sensor/ti,bq274xx.yaml @@ -24,12 +24,22 @@ 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 + description: | + The value of the Chem ID register. When zero, the driver will not check the register. + See the reference manual for the specific BQ274xx variant for values. int-gpios: type: phandle-array diff --git a/dts/bindings/sensor/ti,fdc2x1x.yaml b/dts/bindings/sensor/ti,fdc2x1x.yaml index 4d8d9c6f245d417..b79b27248894b15 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 c68e704c90054a8..d4f5d3abffce83f 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/zephyr,sensing-hinge-angle.yaml b/dts/bindings/sensor/zephyr,sensing-hinge-angle.yaml new file mode 100644 index 000000000000000..4d4e4415677b962 --- /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 5bcaa39f2570e00..e0b8aae492dd0c6 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 30588f35dfd7953..f817137d7b69e4d 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 c93ee94082581a0..788ea54c9568da6 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/intel,lw_uart.yaml b/dts/bindings/serial/intel,lw_uart.yaml new file mode 100644 index 000000000000000..798dfa5322533a1 --- /dev/null +++ b/dts/bindings/serial/intel,lw_uart.yaml @@ -0,0 +1,19 @@ +description: Intel Lightweight UART + +compatible: "intel,lw-uart" + +include: uart-controller.yaml + +properties: + reg: + required: true + description: Base address of the uart controller. + + current-speed: + required: true + description: Default baudrate of the uart controller. + + fixed-baudrate: + type: boolean + description: | + Baud rate cannot be changed by software (Divisor register is not writable) diff --git a/dts/bindings/serial/renesas,ra-uart-sci.yaml b/dts/bindings/serial/renesas,ra-uart-sci.yaml new file mode 100644 index 000000000000000..94229b069247a1d --- /dev/null +++ b/dts/bindings/serial/renesas,ra-uart-sci.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RA Series SCI based UART controller + +compatible: "renesas,ra-uart-sci" + +include: [uart-controller.yaml] diff --git a/dts/bindings/serial/renesas,rzt2m-uart.yaml b/dts/bindings/serial/renesas,rzt2m-uart.yaml new file mode 100644 index 000000000000000..967972ac7c83645 --- /dev/null +++ b/dts/bindings/serial/renesas,rzt2m-uart.yaml @@ -0,0 +1,26 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RZ/T2M UART + +compatible: "renesas,rzt2m-uart" + +include: + - name: uart-controller.yaml + - name: pinctrl-device.yaml + +properties: + reg: + required: true + + current-speed: + required: true + description: | + Initial baud rate setting for UART. Only a fixed set of baud + rates is currently supported. + enum: + - 9600 + - 115200 + + interrupts: + required: true diff --git a/dts/bindings/serial/st,stm32-uart-base.yaml b/dts/bindings/serial/st,stm32-uart-base.yaml index ed8a6e1e3a9f350..3c20564bdda441d 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 000000000000000..720dc4e7377a9eb --- /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/serial/zephyr,uart-emul.yaml b/dts/bindings/serial/zephyr,uart-emul.yaml index d3d50dc9e937b05..119aa49df6ae922 100644 --- a/dts/bindings/serial/zephyr,uart-emul.yaml +++ b/dts/bindings/serial/zephyr,uart-emul.yaml @@ -25,3 +25,9 @@ properties: description: | Connects TX to RX internally creating a loop back connection. Useful for testing. + + latch-buffer-size: + type: int + default: 1 + description: | + Size of the virtual UART latch buffer. 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 000000000000000..dc197fb6fd8237b --- /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 000000000000000..2c93189c178d436 --- /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/infineon,xmc4xxx-spi.yaml b/dts/bindings/spi/infineon,xmc4xxx-spi.yaml index b3475924e14f986..a4f30d994006573 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/intel,sedi-spi.yaml b/dts/bindings/spi/intel,sedi-spi.yaml new file mode 100644 index 000000000000000..ef3af78460a7774 --- /dev/null +++ b/dts/bindings/spi/intel,sedi-spi.yaml @@ -0,0 +1,23 @@ +# +# Copyright (c) 2023 Intel Corporation. +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Intel SEDI SPI controller + +compatible: "intel,sedi-spi" + +include: spi-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + peripheral-id: + type: int + description: Peripheral Instance ID + required: true diff --git a/dts/bindings/spi/microchip,xec-qmspi-ldma.yaml b/dts/bindings/spi/microchip,xec-qmspi-ldma.yaml index 7654612229afa83..418d874bb377157 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 000000000000000..da771b4ba8216d7 --- /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 7e6673cd3c03457..01073f8d0039a35 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/spi-device.yaml b/dts/bindings/spi/spi-device.yaml index f820863b30d4a57..6915b664890e8a5 100644 --- a/dts/bindings/spi/spi-device.yaml +++ b/dts/bindings/spi/spi-device.yaml @@ -40,3 +40,21 @@ properties: enum: - 0 - 32768 + spi-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. + spi-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. + spi-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/spi/st,stm32h7-spi.yaml b/dts/bindings/spi/st,stm32h7-spi.yaml index 3843e420f714058..a1082fff7c45260 100644 --- a/dts/bindings/spi/st,stm32h7-spi.yaml +++ b/dts/bindings/spi/st,stm32h7-spi.yaml @@ -12,3 +12,18 @@ 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. diff --git a/dts/bindings/test/vnd,cpu-intc.yaml b/dts/bindings/test/vnd,cpu-intc.yaml new file mode 100644 index 000000000000000..75f3c02306cedd6 --- /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 000000000000000..b506062792c4b09 --- /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 000000000000000..795b15d93130415 --- /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 000000000000000..760b683b470fbb7 --- /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 000000000000000..e78e57df97e29aa --- /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 cee9e2bc9e7812b..5c8f319a7c51d2a 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 313960930974899..4d1aac49c14a5ae 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 a13deb1f7940902..5792e38ef8de5c4 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 c5e69653a33e816..334f2f06e18de64 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/nxp,ehci.yaml b/dts/bindings/usb/nxp,ehci.yaml new file mode 100644 index 000000000000000..cf72a69545c9f27 --- /dev/null +++ b/dts/bindings/usb/nxp,ehci.yaml @@ -0,0 +1,8 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP EHCI USB device mode + +compatible: nxp,ehci + +include: "nxp,mcux-usbd.yaml" diff --git a/dts/bindings/usb/nxp,lpcip3511.yaml b/dts/bindings/usb/nxp,lpcip3511.yaml new file mode 100644 index 000000000000000..70ea11888372239 --- /dev/null +++ b/dts/bindings/usb/nxp,lpcip3511.yaml @@ -0,0 +1,8 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP LPCIP3511 USB device mode + +compatible: nxp,lpcip3511 + +include: "nxp,mcux-usbd.yaml" diff --git a/dts/bindings/usb/nxp,mcux-usbd.yaml b/dts/bindings/usb/nxp,mcux-usbd.yaml index 389f43e1da0e1a9..af0dd7621371c92 100644 --- a/dts/bindings/usb/nxp,mcux-usbd.yaml +++ b/dts/bindings/usb/nxp,mcux-usbd.yaml @@ -4,8 +4,6 @@ description: | NPX MXRT and LPC USBOTG Controller in device mode -compatible: "nxp,mcux-usbd" - include: [usb-ep.yaml, pinctrl-device.yaml] properties: @@ -14,24 +12,3 @@ properties: interrupts: required: true - - usb-controller-index: - required: true - type: string - description: | - This is taken from the usb_controller_index_t enum that is included inside the NXP SDK - enum: - - "Khci0" - - "Khci1" - - "Ehci0" - - "Ehci1" - - "LpcIp3511Fs0" - - "LpcIp3511Fs1" - - "LpcIp3511Hs0" - - "LpcIp3511Hs1" - - "Ohci0" - - "Ohci1" - - "Ip3516Hs0" - - "Ip3516Hs1" - - "Dwc30" - - "Dwc31" 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 000000000000000..6e661d1c73d86aa --- /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 000000000000000..e71b2990a29e4cb --- /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 000000000000000..3a2412b1427901e --- /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 000000000000000..0c638566c6102f6 --- /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 000000000000000..c1ce1d842f3b295 --- /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 000000000000000..a4283f219a01116 --- /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 91968126c1e6865..a7b1f857d5ff50c 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 ce0245cc1361ea0..f440186f5fe7284 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 032021fd363a0a1..9a12b78b89423d7 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 4b2ab91c73e1a01..268e72ea8c7390c 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -10,6 +10,7 @@ # # +aaeon AAEON Technology Inc. abb ABB abilis Abilis Systems abracon Abracon Corporation @@ -207,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 @@ -222,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 @@ -243,6 +246,7 @@ google Google, Inc. greeled GreeLed Electronic Ltd. grinn Grinn grmn Garmin Limited +gss Gas Sensing Solutions Ltd. gumstix Gumstix, Inc. hamamatsu Hamamatsu Photonics K.K. hannstar HannStar Display Corporation @@ -352,6 +356,7 @@ lontium Lontium Semiconductor Corporation loongson Loongson Technology Corporation Limited lowrisc lowRISC Community Interest Company lsi LSI Corp. (LSI Logic) +ltr LiteOn OptoElectronics lwn Liebherr-Werk Nenzing GmbH lxa Linux Automation GmbH m5stack M5Stack @@ -509,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) @@ -581,6 +587,7 @@ sony Sony Corporation spansion Spansion Inc. sparkfun SparkFun Electronics sprd Spreadtrum Communications Inc. +sqn Sequans Communications sst Silicon Storage Technology, Inc. sstar Xiamen Xingchen(SigmaStar) Technology Co., Ltd. (formerly part of MStar Semiconductor, Inc.) st STMicroelectronics @@ -602,10 +609,12 @@ 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 telink Telink Semiconductor +telit Telit Cinterion tempo Tempo Semiconductor techstar Shenzhen Techstar Electronics Co., Ltd. terasic Terasic Inc. diff --git a/dts/bindings/w1/zephyr,w1-gpio.yaml b/dts/bindings/w1/zephyr,w1-gpio.yaml new file mode 100644 index 000000000000000..46f4e684e01b7a5 --- /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/infineon,xmc4xxx-watchdog.yaml b/dts/bindings/watchdog/infineon,xmc4xxx-watchdog.yaml new file mode 100644 index 000000000000000..66afaa53e68bc0a --- /dev/null +++ b/dts/bindings/watchdog/infineon,xmc4xxx-watchdog.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023, SLB +# SPDX-License-Identifier: Apache-2.0 + +description: Infineon XMC4xxx watchdog + +compatible: "infineon,xmc4xxx-watchdog" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/bindings/watchdog/intel,adsp-watchdog.yaml b/dts/bindings/watchdog/intel,adsp-watchdog.yaml index 379e9e5edaabb95..495ee67af84606a 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 558f598c5424e43..5660ebf00513d95 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 654fb3b2aa1c783..5b0b899c6219cd0 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/bindings/wifi/infineon,airoc-wifi.yaml b/dts/bindings/wifi/infineon,airoc-wifi.yaml new file mode 100644 index 000000000000000..9c93b238a4edbe7 --- /dev/null +++ b/dts/bindings/wifi/infineon,airoc-wifi.yaml @@ -0,0 +1,50 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: | + AIROC Wi-Fi Connectivity. + + Example of enabling AIROC Wi-Fi device (for SDIO): + &sdhc0 { + status = "okay"; + + /* SDIO pins */ + pinctrl-0 = <&p2_4_sdio_cmd &p2_5_sdio_clk &p2_0_sdio_data0 + &p2_1_sdio_data1 &p2_2_sdio_data2 &p2_3_sdio_data3>; + pinctrl-names = "default"; + + /* Wifi configuration */ + airoc-wifi { + status = "okay"; + compatible = "infineon,airoc-wifi-sdio"; + + /* Wi-Fi control gpios */ + wifi-reg-on-gpios = <&gpio_prt2 6 GPIO_ACTIVE_HIGH>; + wifi-host-wake-gpios = <&gpio_prt0 4 GPIO_ACTIVE_HIGH>; + }; + }; + +compatible: "infineon,airoc-wifi" + +include: [base.yaml, pinctrl-device.yaml] + +properties: + wifi-reg-on-gpios: + description: | + Power-up/down gpio to control the internal regulators used + by the WiFi section of AIROC Wi-Fi device. + type: phandle-array + + wifi-host-wake-gpios: + description: | + Host wake-up gpio. Signal from the AIROC Wi-Fi device + to the host indicating that the device requires attention. + type: phandle-array + + wifi-dev-wake-gpios: + description: | + WiFi device wake-up gpio. Signal from the host to the + AIROC Wi-Fi device indicating that the host requires attention. + type: phandle-array diff --git a/dts/riscv/andes/andes_v5_ae350.dtsi b/dts/riscv/andes/andes_v5_ae350.dtsi index 1b5abf0ee8c5f87..419aa712b730049 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 { @@ -275,6 +274,9 @@ reg-names = "control", "mem"; interrupts = <4 1>; interrupt-parent = <&plic0>; + dmas = <&dma0 0 0 0x009>, + <&dma0 1 1 0x00A>; + dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; clock-frequency = <66000000>; @@ -287,6 +289,9 @@ reg-names = "control"; interrupts = <5 1>; interrupt-parent = <&plic0>; + dmas = <&dma0 2 2 0x009>, + <&dma0 3 3 0x00A>; + dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; clock-frequency = <66000000>; @@ -299,6 +304,10 @@ interrupts = <10 1>; interrupt-parent = <&plic0>; dma-channels = <8>; + dma-requests = <16>; + chain-transfer = <1>; + #dma-cells = <3>; + status = "disabled"; }; eth0: eth@e0100000 { diff --git a/dts/riscv/efinix/sapphire_soc.dtsi b/dts/riscv/efinix/sapphire_soc.dtsi index 75043c9dfbbe591..b83c9bc1b0f35a8 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 3b2bb6d07819806..caee77fc6eff345 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 c9f37db5180939c..a631cd4ab18ff95 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 e92e4b73f7b0791..4c6c4fd695bfb18 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 aa3cbda7a853592..a88aa2f0fe91112 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/it81xx2.dtsi b/dts/riscv/ite/it81xx2.dtsi index e8975c4c4968d45..32d47861ee7cc24 100644 --- a/dts/riscv/ite/it81xx2.dtsi +++ b/dts/riscv/ite/it81xx2.dtsi @@ -57,284 +57,284 @@ #address-cells = <1>; #size-cells = <1>; status = "okay"; + }; + + pinctrla: pinctrl@f01610 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01610 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0 0 + 0x02 0x02 0x10 0x0C >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = ; + volt-sel-mask = <0 0 0 0 + 0x1 0x02 0x20 0x40 >; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlb: pinctrl@f01618 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01618 8>; /* GPCR */ + func3-gcr = <0xf016f5 0xf016f5 NO_FUNC NO_FUNC + NO_FUNC NO_FUNC NO_FUNC 0xf01600>; + func3-en-mask = <0x01 0x02 0 0 + 0 0 0 0x02 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0x40 >; + volt-sel = ; + volt-sel-mask = <0 0 0 0x02 + 0x01 0x80 0x40 0x10 >; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlc: pinctrl@f01620 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01620 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0 0x10 + 0 0x10 0 0x02 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0x80 >; + volt-sel = <0xf016e7 0xf016e4 0xf016e4 NO_FUNC + 0xf016e9 NO_FUNC 0xf016e9 0xf016e4>; + volt-sel-mask = <0x80 0x20 0x10 0 + 0x04 0 0x08 0x08 >; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrld: pinctrl@f01628 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01628 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0 0 + 0 0x02 0 0 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf016e4 0xf016e4 0xf016e4 0xf016e5 + 0xf016e5 0xf016e7 0xf016e7 0xf016e7>; + volt-sel-mask = <0x04 0x02 0x01 0x80 + 0x40 0x10 0x20 0x40 >; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrle: pinctrl@f01630 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01630 8>; /* GPCR */ + func3-gcr = <0xf02032 NO_FUNC NO_FUNC NO_FUNC + NO_FUNC 0xf016f0 NO_FUNC 0xf02032>; + func3-en-mask = <0x01 0 0 0 + 0 0x08 0 0x01 >; + func4-gcr = <0xf016f3 NO_FUNC NO_FUNC NO_FUNC + NO_FUNC NO_FUNC NO_FUNC NO_FUNC >; + func4-en-mask = <0x01 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf016e5 0xf016d4 0xf016d4 NO_FUNC + 0xf016e7 0xf016e7 0xf016e5 0xf016e5>; + volt-sel-mask = <0x20 0x40 0x80 0 + 0x04 0x08 0x10 0x08 >; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlf: pinctrl@f01638 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01638 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0x02 0x02 + 0 0 0x10 0x10 >; + func4-gcr = ; + func4-en-mask = <0 0 0x40 0x40 + 0 0 0 0 >; + volt-sel = <0xf016d4 0xf016d4 0xf016e5 0xf016e5 + 0xf016e5 0xf016e6 0xf016e6 0xf016e6>; + volt-sel-mask = <0x10 0x20 0x04 0x02 + 0x01 0x80 0x40 0x20 >; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlg: pinctrl@f01640 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01640 8>; /* GPCR */ + func3-gcr = <0xf016f0 0xf016f0 0xf016f0 NO_FUNC + NO_FUNC NO_FUNC 0xf016f0 NO_FUNC>; + func3-en-mask = <0x20 0x08 0x10 0 + 0 0 0x02 0 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf016d4 0xf016e6 0xf016d4 NO_FUNC + NO_FUNC NO_FUNC 0xf016e6 NO_FUNC>; + volt-sel-mask = <0x04 0x10 0x08 0 + 0 0 0x08 0 >; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlh: pinctrl@f01648 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01648 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0x20 0x20 0 + 0 0x04 0x08 0 >; + func3-ext = ; + func3-ext-mask = <0 0 0 0 + 0 0x01 0x01 0 >; + func4-gcr = ; + func4-en-mask = <0 0x04 0x08 0 + 0 0 0 0 >; + volt-sel = <0xf016e6 0xf016e6 0xf016e6 NO_FUNC + NO_FUNC 0xf016d3 0xf016d4 NO_FUNC>; + volt-sel-mask = <0x04 0x02 0x01 0 + 0 0x80 0x01 0 >; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrli: pinctrl@f01650 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01650 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0 0 + 0 0x08 0x08 0x08 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf016d3 0xf016e8 0xf016e8 0xf016e8 + 0xf016e8 0xf016d3 0xf016d3 0xf016d3>; + volt-sel-mask = <0x08 0x10 0x20 0x40 + 0x80 0x10 0x20 0x40 >; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlj: pinctrl@f01658 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01658 8>; /* GPCR */ + func3-gcr = <0xf016f4 NO_FUNC 0xf016f4 0xf016f4 + 0xf016f0 0xf016f0 NO_FUNC NO_FUNC>; + func3-en-mask = <0x01 0 0x01 0x02 + 0x02 0x03 0 0 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf016e8 0xf016e8 0xf016e8 0xf016e8 + 0xf016d3 0xf016d3 0xf016d3 0xf016d7>; + volt-sel-mask = <0x01 0x02 0x04 0x08 + 0x01 0x02 0x04 0x04 >; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlk: pinctrl@f01690 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01690 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0 0 + 0 0 0 0 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf016d2 0xf016d2 0xf016d2 0xf016d2 + 0xf016d2 0xf016d2 0xf016d2 0xf016d2>; + volt-sel-mask = <0x01 0x02 0x04 0x08 + 0x10 0x20 0x40 0x80 >; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrll: pinctrl@f01698 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01698 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0 0 + 0 0 0 0 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf016d1 0xf016d1 0xf016d1 0xf016d1 + 0xf016d1 0xf016d1 0xf016d1 0xf016d1>; + volt-sel-mask = <0x01 0x02 0x04 0x08 + 0x10 0x20 0x40 0x80 >; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlm: pinctrl@f016a0 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f016a0 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0 0 + 0 0 0 0 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf016ed 0xf016ed 0xf016ed 0xf016ed + 0xf016ed 0xf016ed 0xf016ed NO_FUNC >; + volt-sel-mask = <0x10 0x10 0x10 0x10 + 0x10 0x10 0x10 0 >; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlksi: pinctrl@f01d06 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01d06 1 /* KSIGCTRL */ + 0x00f01d05 1>; /* KSICTRL */ + pp-od-mask = ; + pullup-mask = ; + #pinmux-cells = <2>; + }; + + pinctrlksoh: pinctrl@f01d0a { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01d0a 1 /* KSOHGCTRL */ + 0x00f01d02 1>; /* KSOCTRL */ + pp-od-mask = ; + pullup-mask = ; + #pinmux-cells = <2>; + }; - pinctrla: pinctrl@f01610 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01610 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0 0 - 0x02 0x02 0x10 0x0C >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = ; - volt-sel-mask = <0 0 0 0 - 0x1 0x02 0x20 0x40 >; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlb: pinctrl@f01618 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01618 8>; /* GPCR */ - func3-gcr = <0xf016f5 0xf016f5 NO_FUNC NO_FUNC - NO_FUNC NO_FUNC NO_FUNC 0xf01600>; - func3-en-mask = <0x01 0x02 0 0 - 0 0 0 0x02 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0x40 >; - volt-sel = ; - volt-sel-mask = <0 0 0 0x02 - 0x01 0x80 0x40 0x10 >; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlc: pinctrl@f01620 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01620 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0 0x10 - 0 0x10 0 0x02 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0x80 >; - volt-sel = <0xf016e7 0xf016e4 0xf016e4 NO_FUNC - 0xf016e9 NO_FUNC 0xf016e9 0xf016e4>; - volt-sel-mask = <0x80 0x20 0x10 0 - 0x04 0 0x08 0x08 >; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrld: pinctrl@f01628 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01628 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0 0 - 0 0x02 0 0 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf016e4 0xf016e4 0xf016e4 0xf016e5 - 0xf016e5 0xf016e7 0xf016e7 0xf016e7>; - volt-sel-mask = <0x04 0x02 0x01 0x80 - 0x40 0x10 0x20 0x40 >; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrle: pinctrl@f01630 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01630 8>; /* GPCR */ - func3-gcr = <0xf02032 NO_FUNC NO_FUNC NO_FUNC - NO_FUNC 0xf016f0 NO_FUNC 0xf02032>; - func3-en-mask = <0x01 0 0 0 - 0 0x08 0 0x01 >; - func4-gcr = <0xf016f3 NO_FUNC NO_FUNC NO_FUNC - NO_FUNC NO_FUNC NO_FUNC NO_FUNC >; - func4-en-mask = <0x01 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf016e5 0xf016d4 0xf016d4 NO_FUNC - 0xf016e7 0xf016e7 0xf016e5 0xf016e5>; - volt-sel-mask = <0x20 0x40 0x80 0 - 0x04 0x08 0x10 0x08 >; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlf: pinctrl@f01638 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01638 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0x02 0x02 - 0 0 0x10 0x10 >; - func4-gcr = ; - func4-en-mask = <0 0 0x40 0x40 - 0 0 0 0 >; - volt-sel = <0xf016d4 0xf016d4 0xf016e5 0xf016e5 - 0xf016e5 0xf016e6 0xf016e6 0xf016e6>; - volt-sel-mask = <0x10 0x20 0x04 0x02 - 0x01 0x80 0x40 0x20 >; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlg: pinctrl@f01640 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01640 8>; /* GPCR */ - func3-gcr = <0xf016f0 0xf016f0 0xf016f0 NO_FUNC - NO_FUNC NO_FUNC 0xf016f0 NO_FUNC>; - func3-en-mask = <0x20 0x08 0x10 0 - 0 0 0x02 0 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf016d4 0xf016e6 0xf016d4 NO_FUNC - NO_FUNC NO_FUNC 0xf016e6 NO_FUNC>; - volt-sel-mask = <0x04 0x10 0x08 0 - 0 0 0x08 0 >; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlh: pinctrl@f01648 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01648 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0x20 0x20 0 - 0 0x04 0x08 0 >; - func3-ext = ; - func3-ext-mask = <0 0 0 0 - 0 0x01 0x01 0 >; - func4-gcr = ; - func4-en-mask = <0 0x04 0x08 0 - 0 0 0 0 >; - volt-sel = <0xf016e6 0xf016e6 0xf016e6 NO_FUNC - NO_FUNC 0xf016d3 0xf016d4 NO_FUNC>; - volt-sel-mask = <0x04 0x02 0x01 0 - 0 0x80 0x01 0 >; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrli: pinctrl@f01650 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01650 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0 0 - 0 0x08 0x08 0x08 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf016d3 0xf016e8 0xf016e8 0xf016e8 - 0xf016e8 0xf016d3 0xf016d3 0xf016d3>; - volt-sel-mask = <0x08 0x10 0x20 0x40 - 0x80 0x10 0x20 0x40 >; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlj: pinctrl@f01658 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01658 8>; /* GPCR */ - func3-gcr = <0xf016f4 NO_FUNC 0xf016f4 0xf016f4 - 0xf016f0 0xf016f0 NO_FUNC NO_FUNC>; - func3-en-mask = <0x01 0 0x01 0x02 - 0x02 0x03 0 0 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf016e8 0xf016e8 0xf016e8 0xf016e8 - 0xf016d3 0xf016d3 0xf016d3 0xf016d7>; - volt-sel-mask = <0x01 0x02 0x04 0x08 - 0x01 0x02 0x04 0x04 >; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlk: pinctrl@f01690 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01690 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0 0 - 0 0 0 0 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf016d2 0xf016d2 0xf016d2 0xf016d2 - 0xf016d2 0xf016d2 0xf016d2 0xf016d2>; - volt-sel-mask = <0x01 0x02 0x04 0x08 - 0x10 0x20 0x40 0x80 >; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrll: pinctrl@f01698 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01698 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0 0 - 0 0 0 0 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf016d1 0xf016d1 0xf016d1 0xf016d1 - 0xf016d1 0xf016d1 0xf016d1 0xf016d1>; - volt-sel-mask = <0x01 0x02 0x04 0x08 - 0x10 0x20 0x40 0x80 >; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlm: pinctrl@f016a0 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f016a0 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0 0 - 0 0 0 0 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf016ed 0xf016ed 0xf016ed 0xf016ed - 0xf016ed 0xf016ed 0xf016ed NO_FUNC >; - volt-sel-mask = <0x10 0x10 0x10 0x10 - 0x10 0x10 0x10 0 >; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlksi: pinctrl@f01d06 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01d06 1 /* KSIGCTRL */ - 0x00f01d05 1>; /* KSICTRL */ - pp-od-mask = ; - pullup-mask = ; - #pinmux-cells = <2>; - }; - - pinctrlksoh: pinctrl@f01d0a { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01d0a 1 /* KSOHGCTRL */ - 0x00f01d02 1>; /* KSOCTRL */ - pp-od-mask = ; - pullup-mask = ; - #pinmux-cells = <2>; - }; - - pinctrlksol: pinctrl@f01d0d { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01d0d 1 /* KSOLGCTRL */ - 0x00f01d02 1>; /* KSOCTRL */ - pp-od-mask = ; - pullup-mask = ; - #pinmux-cells = <2>; - }; + pinctrlksol: pinctrl@f01d0d { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01d0d 1 /* KSOLGCTRL */ + 0x00f01d02 1>; /* KSOCTRL */ + pp-od-mask = ; + pullup-mask = ; + #pinmux-cells = <2>; }; i2c0: i2c@f01c40 { @@ -347,6 +347,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpiob 3 0>; sda-gpios = <&gpiob 4 0>; clock-gate-offset = ; @@ -363,6 +364,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioc 1 0>; sda-gpios = <&gpioc 2 0>; clock-gate-offset = ; @@ -379,6 +381,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpiof 6 0>; sda-gpios = <&gpiof 7 0>; clock-gate-offset = ; @@ -394,6 +397,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioh 1 0>; sda-gpios = <&gpioh 2 0>; clock-gate-offset = ; @@ -408,6 +412,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioe 0 0>; sda-gpios = <&gpioe 7 0>; clock-gate-offset = ; @@ -422,6 +427,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioa 4 0>; sda-gpios = <&gpioa 5 0>; clock-gate-offset = ; diff --git a/dts/riscv/ite/it82xx2.dtsi b/dts/riscv/ite/it82xx2.dtsi index 7d9089005aad812..a400d65914b54d7 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>; }; @@ -440,280 +443,284 @@ #address-cells = <1>; #size-cells = <1>; status = "okay"; + }; - pinctrla: pinctrl@f01660 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01660 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0 0 - 0x02 0x02 0x10 0x0C >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf01648 0xf01648 0xf01648 0xf01648 - 0xf01648 0xf01648 0xf01648 0xf01648>; - volt-sel-mask = ; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlb: pinctrl@f01668 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01668 8>; /* GPCR */ - func3-gcr = <0xf03e15 0xf03e15 0xf03e16 NO_FUNC - NO_FUNC 0xf03e16 NO_FUNC NO_FUNC>; - func3-en-mask = <0x01 0x02 0x40 0 - 0 0x40 0 0 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf01649 0xf01649 0xf01649 0xf01649 - 0xf01649 0xf01649 0xf01649 NO_FUNC>; - volt-sel-mask = ; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlc: pinctrl@f01670 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01670 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0 0x10 - 0 0x10 0 0x02 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0x80 >; - volt-sel = <0xf0164a 0xf0164a 0xf0164a 0xf0164a - 0xf0164a 0xf0164a 0xf0164a 0xf0164a>; - volt-sel-mask = ; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrld: pinctrl@f01678 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01678 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0 0 - 0 0x02 0 0 >; - func4-gcr = <0xf03e16 NO_FUNC NO_FUNC NO_FUNC - NO_FUNC NO_FUNC NO_FUNC NO_FUNC>; - func4-en-mask = <0x80 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf0164b 0xf0164b 0xf0164b 0xf0164b - 0xf0164b 0xf0164b 0xf0164b 0xf0164b>; - volt-sel-mask = ; - #pinmux-cells = <2>; - gpio-group; - }; - - 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 >; - func4-gcr = <0xf03e13 NO_FUNC NO_FUNC NO_FUNC - NO_FUNC NO_FUNC NO_FUNC NO_FUNC >; - func4-en-mask = <0x01 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf0164c 0xf0164c 0xf0164c 0xf0164c - 0xf0164c 0xf0164c 0xf0164c 0xf0164c>; - volt-sel-mask = ; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlf: pinctrl@f01688 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01688 8>; /* GPCR */ - func3-gcr = <0xf03e15 0xf03e15 0xf03e10 0xf03e10 - NO_FUNC NO_FUNC 0xf03e11 NO_FUNC>; - func3-en-mask = <0x04 0x08 0x02 0x02 - 0 0 0x10 0 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf0164d 0xf0164d 0xf0164d 0xf0164d - 0xf0164d 0xf0164d 0xf0164d 0xf0164d>; - volt-sel-mask = ; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlg: pinctrl@f01690 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01690 8>; /* GPCR */ - func3-gcr = <0xf03e10 0xf03e10 0xf03e10 NO_FUNC - NO_FUNC NO_FUNC 0xf03e10 NO_FUNC>; - func3-en-mask = <0x20 0x08 0x10 0 - 0 0 0x02 0 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf0164e 0xf0164e 0xf0164e NO_FUNC - NO_FUNC NO_FUNC 0xf0164e NO_FUNC >; - volt-sel-mask = ; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlh: pinctrl@f01698 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01698 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0x20 0x20 0 - 0 0 0 0 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf0164f 0xf0164f 0xf0164f 0xf0164f - 0xf0164f 0xf0164f 0xf0164f NO_FUNC>; - volt-sel-mask = ; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrli: pinctrl@f016a0 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f016a0 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0 0 - 0 0x08 0x08 0x08 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf01650 0xf01650 0xf01650 0xf01650 - 0xf01650 0xf01650 0xf01650 0xf01650>; - volt-sel-mask = ; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlj: pinctrl@f016a8 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f016a8 8>; /* GPCR */ - func3-gcr = <0xf03e14 NO_FUNC 0xf03e14 0xf03e14 - 0xf03e10 0xf03e10 NO_FUNC NO_FUNC>; - func3-en-mask = <0x01 0 0x01 0x02 - 0x02 0x03 0 0 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf01651 0xf01651 0xf01651 0xf01651 - 0xf01651 0xf01651 NO_FUNC NO_FUNC >; - volt-sel-mask = ; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlk: pinctrl@f016b0 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f016b0 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0 0 - 0 0 0 0 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf01652 0xf01652 0xf01652 0xf01652 - 0xf01652 0xf01652 0xf01652 0xf01652>; - volt-sel-mask = ; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrll: pinctrl@f016b8 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f016b8 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0 0 - 0 0 0 0 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf01653 0xf01653 0xf01653 0xf01653 - 0xf01653 0xf01653 0xf01653 0xf01653>; - volt-sel-mask = ; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlm: pinctrl@f016c0 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f016c0 8>; /* GPCR */ - func3-gcr = ; - func3-en-mask = <0 0 0 0 - 0 0 0 0 >; - func4-gcr = ; - func4-en-mask = <0 0 0 0 - 0 0 0 0 >; - volt-sel = <0xf03e2d 0xf03e2d 0xf03e2d 0xf03e2d - 0xf03e2d 0xf03e2d 0xf03e2d NO_FUNC >; - volt-sel-mask = ; - #pinmux-cells = <2>; - gpio-group; - }; - - pinctrlksi: pinctrl@f01d40 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01d40 8 /* KSIGCTRL */ - 0x00f01d05 1>; /* KSICTRL */ - pp-od-mask = ; - pullup-mask = ; - #pinmux-cells = <2>; - }; - - pinctrlksol: pinctrl@f01d48 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01d48 8 /* KSOLGCTRL */ - 0x00f01d02 1>; /* KSOCTRL */ - pp-od-mask = ; - pullup-mask = ; - #pinmux-cells = <2>; - }; - - pinctrlksoh: pinctrl@f01d50 { - compatible = "ite,it8xxx2-pinctrl-func"; - reg = <0x00f01d50 8 /* KSOHGCTRL */ - 0x00f01d02 1>; /* KSOCTRL */ - pp-od-mask = ; - pullup-mask = ; - #pinmux-cells = <2>; - }; + pinctrla: pinctrl@f01660 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01660 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0 0 + 0x02 0x02 0x10 0x0C >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf01648 0xf01648 0xf01648 0xf01648 + 0xf01648 0xf01648 0xf01648 0xf01648>; + volt-sel-mask = ; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlb: pinctrl@f01668 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01668 8>; /* GPCR */ + func3-gcr = <0xf03e15 0xf03e15 0xf03e16 NO_FUNC + NO_FUNC 0xf03e16 NO_FUNC NO_FUNC>; + func3-en-mask = <0x01 0x02 0x40 0 + 0 0x40 0 0 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf01649 0xf01649 0xf01649 0xf01649 + 0xf01649 0xf01649 0xf01649 NO_FUNC>; + volt-sel-mask = ; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlc: pinctrl@f01670 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01670 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0 0x10 + 0 0x10 0 0x02 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0x80 >; + volt-sel = <0xf0164a 0xf0164a 0xf0164a 0xf0164a + 0xf0164a 0xf0164a 0xf0164a 0xf0164a>; + volt-sel-mask = ; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrld: pinctrl@f01678 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01678 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0 0 + 0 0x02 0 0 >; + func4-gcr = <0xf03e16 NO_FUNC NO_FUNC NO_FUNC + NO_FUNC NO_FUNC NO_FUNC NO_FUNC>; + func4-en-mask = <0x80 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf0164b 0xf0164b 0xf0164b 0xf0164b + 0xf0164b 0xf0164b 0xf0164b 0xf0164b>; + volt-sel-mask = ; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrle: pinctrl@f01680 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01680 8>; /* GPCR */ + 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 + 0 0 0 0 >; + volt-sel = <0xf0164c 0xf0164c 0xf0164c 0xf0164c + 0xf0164c 0xf0164c 0xf0164c 0xf0164c>; + volt-sel-mask = ; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlf: pinctrl@f01688 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01688 8>; /* GPCR */ + func3-gcr = <0xf03e15 0xf03e15 0xf03e10 0xf03e10 + NO_FUNC NO_FUNC 0xf03e11 NO_FUNC>; + func3-en-mask = <0x04 0x08 0x02 0x02 + 0 0 0x10 0 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf0164d 0xf0164d 0xf0164d 0xf0164d + 0xf0164d 0xf0164d 0xf0164d 0xf0164d>; + volt-sel-mask = ; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlg: pinctrl@f01690 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01690 8>; /* GPCR */ + func3-gcr = <0xf03e10 0xf03e10 0xf03e10 NO_FUNC + NO_FUNC NO_FUNC 0xf03e10 NO_FUNC>; + func3-en-mask = <0x20 0x08 0x10 0 + 0 0 0x02 0 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf0164e 0xf0164e 0xf0164e NO_FUNC + NO_FUNC NO_FUNC 0xf0164e NO_FUNC >; + volt-sel-mask = ; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlh: pinctrl@f01698 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01698 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0x20 0x20 0 + 0 0 0 0 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf0164f 0xf0164f 0xf0164f 0xf0164f + 0xf0164f 0xf0164f 0xf0164f NO_FUNC>; + volt-sel-mask = ; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrli: pinctrl@f016a0 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f016a0 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0 0 + 0 0x08 0x08 0x08 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf01650 0xf01650 0xf01650 0xf01650 + 0xf01650 0xf01650 0xf01650 0xf01650>; + volt-sel-mask = ; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlj: pinctrl@f016a8 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f016a8 8>; /* GPCR */ + func3-gcr = <0xf03e14 NO_FUNC 0xf03e14 0xf03e14 + 0xf03e10 0xf03e10 NO_FUNC NO_FUNC>; + func3-en-mask = <0x01 0 0x01 0x02 + 0x02 0x03 0 0 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf01651 0xf01651 0xf01651 0xf01651 + 0xf01651 0xf01651 NO_FUNC NO_FUNC >; + volt-sel-mask = ; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlk: pinctrl@f016b0 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f016b0 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0 0 + 0 0 0 0 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf01652 0xf01652 0xf01652 0xf01652 + 0xf01652 0xf01652 0xf01652 0xf01652>; + volt-sel-mask = ; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrll: pinctrl@f016b8 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f016b8 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0 0 + 0 0 0 0 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf01653 0xf01653 0xf01653 0xf01653 + 0xf01653 0xf01653 0xf01653 0xf01653>; + volt-sel-mask = ; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlm: pinctrl@f016c0 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f016c0 8>; /* GPCR */ + func3-gcr = ; + func3-en-mask = <0 0 0 0 + 0 0 0 0 >; + func4-gcr = ; + func4-en-mask = <0 0 0 0 + 0 0 0 0 >; + volt-sel = <0xf03e2d 0xf03e2d 0xf03e2d 0xf03e2d + 0xf03e2d 0xf03e2d 0xf03e2d NO_FUNC >; + volt-sel-mask = ; + #pinmux-cells = <2>; + gpio-group; + }; + + pinctrlksi: pinctrl@f01d40 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01d40 8 /* KSIGCTRL */ + 0x00f01d05 1>; /* KSICTRL */ + pp-od-mask = ; + pullup-mask = ; + #pinmux-cells = <2>; + }; + + pinctrlksol: pinctrl@f01d48 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01d48 8 /* KSOLGCTRL */ + 0x00f01d02 1>; /* KSOCTRL */ + pp-od-mask = ; + pullup-mask = ; + #pinmux-cells = <2>; + }; + + pinctrlksoh: pinctrl@f01d50 { + compatible = "ite,it8xxx2-pinctrl-func"; + reg = <0x00f01d50 8 /* KSOHGCTRL */ + 0x00f01d02 1>; /* KSOCTRL */ + pp-od-mask = ; + pullup-mask = ; + #pinmux-cells = <2>; }; wuc1: wakeup-controller@f01b00 { @@ -885,6 +892,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpiob 3 0>; sda-gpios = <&gpiob 4 0>; clock-gate-offset = ; @@ -899,6 +907,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioc 1 0>; sda-gpios = <&gpioc 2 0>; clock-gate-offset = ; @@ -913,6 +922,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpiof 6 0>; sda-gpios = <&gpiof 7 0>; clock-gate-offset = ; @@ -927,6 +937,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioh 1 0>; sda-gpios = <&gpioh 2 0>; clock-gate-offset = ; @@ -941,6 +952,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioe 0 0>; sda-gpios = <&gpioe 7 0>; clock-gate-offset = ; @@ -955,6 +967,7 @@ interrupt-parent = <&intc>; status = "disabled"; port-num = ; + channel-switch-sel = ; scl-gpios = <&gpioa 4 0>; sda-gpios = <&gpioa 5 0>; clock-gate-offset = ; diff --git a/dts/riscv/ite/it8xxx2.dtsi b/dts/riscv/ite/it8xxx2.dtsi index 62734db267515ba..faa16fbaefee5db 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>; @@ -691,8 +691,8 @@ status = "disabled"; }; - kscan0: kscan@f01d00 { - compatible = "ite,it8xxx2-kscan"; + kbd: kbd@f01d00 { + compatible = "ite,it8xxx2-kbd"; reg = <0x00f01d00 0x29>; interrupt-parent = <&intc>; interrupts = ; diff --git a/dts/riscv/lowrisc/opentitan_earlgrey.dtsi b/dts/riscv/lowrisc/opentitan_earlgrey.dtsi index 2df96d71eeb0e28..1f6c23671dcd0ca 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 4ed4d45e30550be..000000000000000 --- 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 000000000000000..fe7a0a773c93388 --- /dev/null +++ b/dts/riscv/microchip/mpfs.dtsi @@ -0,0 +1,259 @@ +/* + * 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>; + }; + + 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/neorv32.dtsi b/dts/riscv/neorv32.dtsi index 429d4372418f09a..31fb06b1c49a5fb 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 90869676f2b194b..2022e984ff55267 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 88f8042383cf4b6..e6594a2354659d9 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/openisa/rv32m1.dtsi b/dts/riscv/openisa/rv32m1.dtsi index 567a6959f1f97a1..afbc7c41c23a0e9 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 000000000000000..a0db375501f7c34 --- /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 3eefacccf6d7cdc..8013decbafdfe51 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 c028db37c4e08cc..f2128e1d37bfb9f 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 ed56401d462065e..7ccd950129abf12 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 bbe45b98aab3ea5..61421cd557e1c53 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 c355ac89a5fe523..c36ea625b02fee3 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 caef8cb28d37ba7..20873731c6e9ddb 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/x86/intel/alder_lake.dtsi b/dts/x86/intel/alder_lake.dtsi index 5856f008f4ae4dc..973e95db1538e58 100644 --- a/dts/x86/intel/alder_lake.dtsi +++ b/dts/x86/intel/alder_lake.dtsi @@ -78,6 +78,12 @@ status = "disabled"; }; + uart1_dma: uart1_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; + }; + uart1: uart1 { compatible = "ns16550"; vendor-id = <0x8086>; @@ -87,6 +93,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 +113,8 @@ reg-shift = <2>; interrupts = ; interrupt-parent = <&intc>; + dmas = <&uart2_dma 0>, <&uart2_dma 1>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -258,6 +274,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>; @@ -430,6 +452,14 @@ 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>; diff --git a/dts/x86/intel/intel_ish5.dtsi b/dts/x86/intel/intel_ish5.dtsi index 375b9cc4ea469e4..5f2ef6a1960c3a3 100644 --- a/dts/x86/intel/intel_ish5.dtsi +++ b/dts/x86/intel/intel_ish5.dtsi @@ -163,5 +163,42 @@ status = "okay"; }; + + spi0: spi@8000000 { + compatible = "intel,sedi-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x8000000 0x1000>; + peripheral-id = <0>; + interrupt-parent = <&intc>; + interrupts = <19 IRQ_TYPE_LOWEST_LEVEL_HIGH 2>; + + status = "okay"; + }; + + spi1: spi@8002000 { + compatible = "intel,sedi-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x8002000 0x1000>; + peripheral-id = <1>; + interrupt-parent = <&intc>; + interrupts = <20 IRQ_TYPE_LOWEST_LEVEL_HIGH 2>; + + status = "disabled"; + }; + + dma0: dma@10100000 { + compatible = "intel,sedi_dma"; + #dma-cells = <2>; + dma-channels = <8>; + peripheral-id = <0>; + reg = <0x10100000 0x1000>; + interrupts = <11 IRQ_TYPE_LOWEST_LEVEL_HIGH 2>; + interrupt-parent = <&intc>; + dma-buf-size-alignment = <4>; + dma-copy-alignment = <4>; + status = "okay"; + }; }; }; diff --git a/dts/x86/intel/intel_ish5_8.dtsi b/dts/x86/intel/intel_ish5_8.dtsi index fba74881cf475a3..5600798d8e8723a 100644 --- a/dts/x86/intel/intel_ish5_8.dtsi +++ b/dts/x86/intel/intel_ish5_8.dtsi @@ -41,3 +41,15 @@ status = "okay"; }; + +&spi0 { + interrupts = <23 IRQ_TYPE_LOWEST_LEVEL_HIGH 2>; + + status = "okay"; +}; + +&spi1 { + interrupts = <24 IRQ_TYPE_LOWEST_LEVEL_HIGH 2>; + + status = "disabled"; +}; diff --git a/dts/x86/intel/raptor_lake.dtsi b/dts/x86/intel/raptor_lake.dtsi deleted file mode 100644 index c479d54dd9e836f..000000000000000 --- a/dts/x86/intel/raptor_lake.dtsi +++ /dev/null @@ -1,611 +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"; - }; - - uart3: uart3 { - compatible = "ns16550"; - vendor-id = <0x8086>; - device-id = <0x7adc>; - reg-shift = <2>; - clock-frequency = <1843200>; - interrupts = ; - interrupt-parent = <&intc>; - current-speed = <115200>; - status = "disabled"; - }; - - uart4: uart4 { - compatible = "ns16550"; - vendor-id = <0x8086>; - device-id = <0x7add>; - reg-shift = <2>; - clock-frequency = <1843200>; - interrupts = ; - interrupt-parent = <&intc>; - current-speed = <115200>; - status = "disabled"; - }; - - uart5: uart5 { - compatible = "ns16550"; - vendor-id = <0x8086>; - device-id = <0x7ade>; - reg-shift = <2>; - clock-frequency = <1843200>; - interrupts = ; - interrupt-parent = <&intc>; - current-speed = <115200>; - status = "disabled"; - }; - - uart6: uart6 { - compatible = "ns16550"; - vendor-id = <0x8086>; - device-id = <0x7adf>; - 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 000000000000000..8f7dec863e2b597 --- /dev/null +++ b/dts/x86/intel/raptor_lake_p.dtsi @@ -0,0 +1,474 @@ +/* + * 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 = "intel,pcie"; + #address-cells = <1>; + #size-cells = <1>; + 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 000000000000000..bafee1dc403ff0a --- /dev/null +++ b/dts/x86/intel/raptor_lake_s.dtsi @@ -0,0 +1,579 @@ +/* + * 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_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_appcpu.dtsi b/dts/xtensa/espressif/esp32/esp32_appcpu.dtsi new file mode 100644 index 000000000000000..b5357495666af03 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_appcpu.dtsi @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <20 1>, <24 1>, <28 4>; // NC +}; + +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_common.dtsi b/dts/xtensa/espressif/esp32/esp32_common.dtsi index 0f61150cead4a0d..b7aba9f23500baf 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/esp32/esp32_d0wd_v3.dtsi b/dts/xtensa/espressif/esp32/esp32_d0wd_v3.dtsi index 6511f3d351a211c..b2232505a9a04be 100644 --- a/dts/xtensa/espressif/esp32/esp32_d0wd_v3.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_d0wd_v3.dtsi @@ -8,7 +8,7 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <20>,<24>,<28 31>; // NC + gpio-reserved-ranges = <20 1>, <24 1>, <28 4>; // NC }; /* Add flash or psram on board or application level */ diff --git a/dts/xtensa/espressif/esp32/esp32_d0wdr2_v3.dtsi b/dts/xtensa/espressif/esp32/esp32_d0wdr2_v3.dtsi index eb5e239c1aaadb1..2703231b821d786 100644 --- a/dts/xtensa/espressif/esp32/esp32_d0wdr2_v3.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_d0wdr2_v3.dtsi @@ -8,9 +8,9 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <6 10>, // embeddef psram - <11>, // flash CS - <20>,<24>,<28 31>; // NC + gpio-reserved-ranges = <6 5>, // embeddef psram + <11 1>, // flash CS + <20 1>, <24 1>, <28 4>; // NC }; /* 2MB psram */ diff --git a/dts/xtensa/espressif/esp32/esp32_net.dtsi b/dts/xtensa/espressif/esp32/esp32_net.dtsi deleted file mode 100644 index 00657ac0425fd88..000000000000000 --- a/dts/xtensa/espressif/esp32/esp32_net.dtsi +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "esp32_common.dtsi" - -/* Reserved GPIO pins */ -&gpio0 { - gpio-reserved-ranges = <20>,<24>,<28 31>; // NC -}; - -&flash0 { - reg = <0x0 DT_SIZE_M(4)>; -}; diff --git a/dts/xtensa/espressif/esp32/esp32_pico_d4.dtsi b/dts/xtensa/espressif/esp32/esp32_pico_d4.dtsi index 8ed101d24bc2dce..580d6fed8922e58 100644 --- a/dts/xtensa/espressif/esp32/esp32_pico_d4.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_pico_d4.dtsi @@ -8,8 +8,8 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <6 8>,<11>,<16 17>, // embedded flash - <20>, <24>, <28 31>; // NC + gpio-reserved-ranges = <6 3>, <11 1>, <16 2>, // embedded flash + <20 1>, <24 1>, <28 4>; // NC }; /* 4MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_pico_v3.dtsi b/dts/xtensa/espressif/esp32/esp32_pico_v3.dtsi index 76e4d4c05ebb79d..d806b0b7c141521 100644 --- a/dts/xtensa/espressif/esp32/esp32_pico_v3.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_pico_v3.dtsi @@ -8,8 +8,8 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <16 18>,<23>, // limitations - <24>,<28 31>; // NC + gpio-reserved-ranges = <16 3>, <23 1>, // limitations + <24 1>, <28 4>; // NC }; /* 4MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_pico_v3_02.dtsi b/dts/xtensa/espressif/esp32/esp32_pico_v3_02.dtsi index 249debca7520f32..9d108bd4e572669 100644 --- a/dts/xtensa/espressif/esp32/esp32_pico_v3_02.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_pico_v3_02.dtsi @@ -8,8 +8,8 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <6 11>, // flash - <24 25>,<28 31>; // NC + gpio-reserved-ranges = <6 6>, // flash + <24 2>, <28 4>; // NC }; /* 8MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_u4wdh.dtsi b/dts/xtensa/espressif/esp32/esp32_u4wdh.dtsi index d26074898fa23c2..34ca79156ef83e5 100644 --- a/dts/xtensa/espressif/esp32/esp32_u4wdh.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_u4wdh.dtsi @@ -8,7 +8,7 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <20>, <24>, <28 31>; + gpio-reserved-ranges = <20 1>, <24 1>, <28 4>; }; /* 4MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n16.dtsi b/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n16.dtsi index 2461a80395440c8..43ce14117a51c65 100644 --- a/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n16.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n16.dtsi @@ -8,12 +8,12 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <6 11>, // flash - <20>, <24>, <28 31>; // NC + gpio-reserved-ranges = <6 6>, // flash + <20 1>, <24 1>, <28 4>; // NC }; &gpio1 { - gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC + gpio-reserved-ranges = <6 2>; // GPIO37-38 NC }; /* 16MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n4.dtsi b/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n4.dtsi index 9c8ef71acfdbf71..8f5f3d9dd1094d1 100644 --- a/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n4.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n4.dtsi @@ -8,12 +8,12 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <6 11>, // flash - <20>,<24>,<28 31>; // NC + gpio-reserved-ranges = <6 6>, // flash + <20 1>, <24 1>, <28 4>; // NC }; &gpio1 { - gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC + gpio-reserved-ranges = <6 2>; // GPIO37-38 NC }; /* 4MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n8.dtsi b/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n8.dtsi index 4dee1868cc34455..42813aa6e68826b 100644 --- a/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n8.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n8.dtsi @@ -8,12 +8,12 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <6 11>, // flash - <20>,<24>,<28 31>; // NC + gpio-reserved-ranges = <6 6>, // flash + <20 1>, <24 1>, <28 4>; // NC }; &gpio1 { - gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC + gpio-reserved-ranges = <6 2>; // GPIO37-38 NC }; /* 8MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_wroom_da_n16.dtsi b/dts/xtensa/espressif/esp32/esp32_wroom_da_n16.dtsi index f034a5b289853cb..f9f3bd8120105ae 100644 --- a/dts/xtensa/espressif/esp32/esp32_wroom_da_n16.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_wroom_da_n16.dtsi @@ -8,13 +8,13 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <2>,<25>, // NC/test - <6 11>, // flash - <20>,<24>,<28 31>; // NC + gpio-reserved-ranges = <2 1>, <25 1>, // NC/test + <6 6>, // flash + <20 1>, <24 1>, <28 4>; // NC }; &gpio1 { - gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC + gpio-reserved-ranges = <6 2>; // GPIO37-38 NC }; /* 16MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_wroom_da_n4.dtsi b/dts/xtensa/espressif/esp32/esp32_wroom_da_n4.dtsi index 324c1bba2de7d35..98f6d9dc9b2d543 100644 --- a/dts/xtensa/espressif/esp32/esp32_wroom_da_n4.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_wroom_da_n4.dtsi @@ -8,13 +8,13 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <2>,<25>, // NC/test - <6 11>, // flash - <20>,<24>,<28 31>; // NC + gpio-reserved-ranges = <2 1>, <25 1>, // NC/test + <6 6>, // flash + <20 1>, <24 1>, <28 4>; // NC }; &gpio1 { - gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC + gpio-reserved-ranges = <6 2>; // GPIO37-38 NC }; /* 4MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_wroom_da_n8.dtsi b/dts/xtensa/espressif/esp32/esp32_wroom_da_n8.dtsi index ec5583c440677fc..7beeda4e1365988 100644 --- a/dts/xtensa/espressif/esp32/esp32_wroom_da_n8.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_wroom_da_n8.dtsi @@ -8,13 +8,13 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <2>,<25>, // NC/test - <6 11>, // flash - <20>,<24>,<28 31>; // NC + gpio-reserved-ranges = <2 1>, <25 1>, // NC/test + <6 6>, // flash + <20 1>, <24 1>, <28 4>; // NC }; &gpio1 { - gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC + gpio-reserved-ranges = <6 2>; // GPIO37-38 NC }; /* 8MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r2.dtsi b/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r2.dtsi index 712d86fc0f4d66f..393dfa7b95133ea 100644 --- a/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r2.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r2.dtsi @@ -8,12 +8,12 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <6 11>,<16 17>, // flash&psram - <20>,<24>,<28 31>; // NC + gpio-reserved-ranges = <6 6>, <16 2>, // flash&psram + <20 1>, <24 1>, <28 4>; // NC }; &gpio1 { - gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC + gpio-reserved-ranges = <6 2>; // GPIO37-38 NC }; /* 16MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r4.dtsi b/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r4.dtsi index 119e3e3ed6aee3a..160800afdca8cfa 100644 --- a/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r4.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r4.dtsi @@ -8,12 +8,12 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <6 11>,<16 17>, // flash&psram - <20>,<24>,<28 31>; // NC + gpio-reserved-ranges = <6 6>, <16 2>, // flash&psram + <20 1>, <24 1>, <28 4>; // NC }; &gpio1 { - gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC + gpio-reserved-ranges = <6 2>; // GPIO37-38 NC }; /* 16MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r8.dtsi b/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r8.dtsi index 10ab7f11fa127b3..acac866076fff03 100644 --- a/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r8.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r8.dtsi @@ -8,12 +8,12 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <6 11>,<16 17>, // flash&psram - <20>,<24>,<28 31>; // NC + gpio-reserved-ranges = <6 6>, <16 2>, // flash&psram + <20 1>, <24 1>, <28 4>; // NC }; &gpio1 { - gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC + gpio-reserved-ranges = <6 2>; // GPIO37-38 NC }; /* 16MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_wrover_e_n4r2.dtsi b/dts/xtensa/espressif/esp32/esp32_wrover_e_n4r2.dtsi index b4367cc223d1025..8e463a3b3a7479b 100644 --- a/dts/xtensa/espressif/esp32/esp32_wrover_e_n4r2.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_wrover_e_n4r2.dtsi @@ -8,12 +8,12 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <6 11>,<16 17>, // flash&psram - <20>,<24>,<28 31>; // NC + gpio-reserved-ranges = <6 6>, <16 2>, // flash&psram + <20 1>, <24 1>, <28 4>; // NC }; &gpio1 { - gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC + gpio-reserved-ranges = <6 1>, <7 1>; // GPIO37-38 NC }; /* 4MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_wrover_e_n4r8.dtsi b/dts/xtensa/espressif/esp32/esp32_wrover_e_n4r8.dtsi index ef6037b394c3fe3..0197755fba5649d 100644 --- a/dts/xtensa/espressif/esp32/esp32_wrover_e_n4r8.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_wrover_e_n4r8.dtsi @@ -8,12 +8,12 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <6 11>,<16 17>, // flash&psram - <20>,<24>,<28 31>; // NC + gpio-reserved-ranges = <6 6>, <16 2>, // flash&psram + <20 1>, <24 1>, <28 4>; // NC }; &gpio1 { - gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC + gpio-reserved-ranges = <6 1>, <7 1>; // GPIO37-38 NC }; /* 4MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_wrover_e_n8r2.dtsi b/dts/xtensa/espressif/esp32/esp32_wrover_e_n8r2.dtsi index e8d902c73ae65ce..5bc98caf7068822 100644 --- a/dts/xtensa/espressif/esp32/esp32_wrover_e_n8r2.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_wrover_e_n8r2.dtsi @@ -8,12 +8,12 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <6 11>,<16 17>, // flash&psram - <20>,<24>,<28 31>; // NC + gpio-reserved-ranges = <6 6>, <16 2>, // flash&psram + <20 1>, <24 1>, <28 4>; // NC }; &gpio1 { - gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC + gpio-reserved-ranges = <6 2>; // GPIO37-38 NC }; /* 8MB flash */ diff --git a/dts/xtensa/espressif/esp32/esp32_wrover_e_n8r8.dtsi b/dts/xtensa/espressif/esp32/esp32_wrover_e_n8r8.dtsi index 1ab318f35898a98..0f73058de082e19 100644 --- a/dts/xtensa/espressif/esp32/esp32_wrover_e_n8r8.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_wrover_e_n8r8.dtsi @@ -8,13 +8,13 @@ /* Reserved GPIO pins */ &gpio0 { - gpio-reserved-ranges = <20>, <24>, <28 31>; - gpio-reserved-ranges = <6 11>,<16 17>, // flash&psram - <20>,<24>,<28 31>; // NC + gpio-reserved-ranges = <20 1>, <24 1>, <28 4>; + gpio-reserved-ranges = <6 6>, <16 2>, // flash&psram + <20 1>, <24 1>, <28 4>; // NC }; &gpio1 { - gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC + gpio-reserved-ranges = <6 2>; // GPIO37-38 NC }; /* 8MB flash */ diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi index b523ec53364c395..727b26e4a53304c 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 3c3732725937ed5..27a90f797d08242 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 000000000000000..c4c0929063d5951 --- /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 000000000000000..b8f733a3c547911 --- /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 000000000000000..b77169f172beea0 --- /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 eac737e3d619092..34ec0ec5ac1aae6 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_ace15_mtpm.dtsi b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi index 564ee3fe26df187..de8aa8ed6fd39b7 100644 --- a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi +++ b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi @@ -513,32 +513,6 @@ interrupt-parent = <&ace_intc>; }; - watchdog0: watchdog@78300 { - compatible = "snps,designware-watchdog"; - reg = <0x78300 0x100>; - interrupts = <8 0 0>; - interrupt-parent = <&core_intc>; - clock-frequency = <32768>; - reset-pulse-length = <2>; - status = "okay"; - }; - - watchdog1: watchdog@78400 { - compatible = "snps,designware-watchdog"; - reg = <0x78400 0x100>; - clock-frequency = <32768>; - reset-pulse-length = <2>; - status = "okay"; - }; - - watchdog2: watchdog@78500 { - compatible = "snps,designware-watchdog"; - reg = <0x78500 0x100>; - clock-frequency = <32768>; - reset-pulse-length = <2>; - status = "okay"; - }; - /* This is actually an array of per-core designware * controllers, but the special setup and extra * masking layer makes it easier for MTL to handle diff --git a/dts/xtensa/intel/intel_adsp_cavs18.dtsi b/dts/xtensa/intel/intel_adsp_cavs18.dtsi index 4ba04636a47a3db..def86567e7548ef 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/intel/intel_adsp_cavs25.dtsi b/dts/xtensa/intel/intel_adsp_cavs25.dtsi index 1039a00b094aa6e..36ad7afa2186406 100644 --- a/dts/xtensa/intel/intel_adsp_cavs25.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs25.dtsi @@ -98,7 +98,7 @@ wovcro-supported; }; - IMR1: memory@0xb0000000 { + IMR1: memory@b0000000 { compatible = "intel,adsp-imr"; reg = <0xB0000000 DT_SIZE_M(16)>; block-size = <0x1000>; diff --git a/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi b/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi index a03605df5152dbf..facb914904ca78c 100644 --- a/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi @@ -84,7 +84,7 @@ wovcro-supported; }; - IMR1: memory@0xb0000000 { + IMR1: memory@b0000000 { compatible = "intel,adsp-imr"; reg = <0xB0000000 DT_SIZE_M(16)>; block-size = <0x1000>; diff --git a/dts/xtensa/nxp/nxp_imx8.dtsi b/dts/xtensa/nxp/nxp_imx8.dtsi index 06b38e1bbee1c34..7a8c23cedc4302b 100644 --- a/dts/xtensa/nxp/nxp_imx8.dtsi +++ b/dts/xtensa/nxp/nxp_imx8.dtsi @@ -6,6 +6,7 @@ #include #include +#include / { cpus { @@ -16,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>; + }; }; }; @@ -30,4 +41,40 @@ compatible = "mmio-sram"; reg = <0x92c00000 DT_SIZE_K(512)>; }; + + /* LSIO MU2, used to interact with the SCFW */ + scu_mu: mailbox@5d1d0000 { + reg = <0x5d1d0000 DT_SIZE_K(64)>; + }; + + scu: system-controller { + ccm: clock-controller { + compatible = "nxp,imx-ccm"; + #clock-cells = <3>; + }; + + iomuxc: iomuxc { + compatible = "nxp,imx-iomuxc-scu"; + pinctrl: pinctrl { + compatible = "nxp,imx8-pinctrl"; + }; + }; + }; + + lpuart2: serial@5a080000 { + compatible = "nxp,imx-lpuart", "nxp,kinetis-lpuart"; + reg = <0x5a080000 DT_SIZE_K(4)>; + /* TODO: THIS INTID IS JUST A DUMMY ONE UNTIL IRQ_STEER + * DRIVER CAN BE USED ON i.MX8QM/QXP. DO NOT ATTEMPT TO + * ENABLE UART INTERRUPT SUPPORT. + * + * THE CURRENT INTID VALUE IS CHOSEN SUCH THAT gen_isr_tables.py + * WILL BREAK IF YOU ATTEMPT TO IRQ_CONNECT(). + */ + interrupt-parent = <&clic>; + interrupts = <259 0 0>; + /* this is actually LPUART2 clock but the macro indexing starts at 1 */ + clocks = <&ccm IMX_CCM_LPUART3_CLK 0x0 0x0>; + status = "disabled"; + }; }; diff --git a/dts/xtensa/nxp/nxp_imx8m.dtsi b/dts/xtensa/nxp/nxp_imx8m.dtsi index 9e72a3d59ed7bb3..70bfd50079859f5 100644 --- a/dts/xtensa/nxp/nxp_imx8m.dtsi +++ b/dts/xtensa/nxp/nxp_imx8m.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 NXP + * Copyright 2021, 2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -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)>; @@ -64,14 +66,20 @@ uart4: uart@30a60000 { compatible = "nxp,imx-iuart"; reg = <0x30a60000 0x10000>; + /* TODO: This INTID is just a dummy + * until we can support UART interrupts + */ + interrupt-parent = <&clic>; + interrupts = <29 0 0>; clocks = <&ccm IMX_CCM_UART4_CLK 0x6c 24>; status = "disabled"; }; mailbox0: mailbox@30e70000 { - compatible = "nxp,imx-mu-rev2"; + 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 000000000000000..71f3de1958bd14d --- /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 77a1f2e952784f5..b74f4f10a158359 100644 --- a/include/zephyr/acpi/acpi.h +++ b/include/zephyr/acpi/acpi.h @@ -35,9 +35,9 @@ union acpi_dmar_id { }; struct acpi_mcfg { - struct acpi_table_header header; + ACPI_TABLE_HEADER header; uint64_t _reserved; - struct acpi_mcfg_allocation pci_segs[]; + ACPI_MCFG_ALLOCATION pci_segs[]; } __packed; /** @@ -80,7 +80,7 @@ int acpi_current_resource_free(ACPI_RESOURCE *res); * * @param bus_name the name of the bus * @param rt_table the IRQ routing table - * @param rt_size the the size of 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); @@ -149,7 +149,7 @@ void *acpi_table_get(char *signature, int inst); * @param num_inst number of instance for the requested table * @return return 0 on success or error code */ -int acpi_madt_entry_get(int type, struct acpi_subtable_header **tables, int *num_inst); +int acpi_madt_entry_get(int type, ACPI_SUBTABLE_HEADER **tables, int *num_inst); /** * @brief retrieve DMA remapping structure for the given type. @@ -158,8 +158,7 @@ int acpi_madt_entry_get(int type, struct acpi_subtable_header **tables, int *num * @param tables pointer to the dmar id structure * @return return 0 on success or error code */ -int acpi_dmar_entry_get(enum AcpiDmarType type, - struct acpi_subtable_header **tables); +int acpi_dmar_entry_get(enum AcpiDmarType type, ACPI_SUBTABLE_HEADER **tables); /** * @brief retrieve acpi DRHD info for the given scope. @@ -171,14 +170,30 @@ int acpi_dmar_entry_get(enum AcpiDmarType type, * @param max_inst maximum number of entry for the given dmar_id buffer * @return return 0 on success or error code */ -int acpi_drhd_get(enum AcpiDmarScopeType scope, struct acpi_dmar_device_scope *dev_scope, - union acpi_dmar_id *dmar_id, int *num_inst, int max_inst); +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 lapic info for a specific cpu. + * @brief Retrieve the 'n'th enabled local apic info. * * @param cpu_num the cpu number - * @return lapic info on success or NULL + * @return local apic info on success or NULL otherwise */ -struct acpi_madt_local_apic *acpi_local_apic_get(uint32_t cpu_num); +ACPI_MADT_LOCAL_APIC *acpi_local_apic_get(int cpu_num); #endif diff --git a/include/zephyr/arch/arc/arch.h b/include/zephyr/arch/arc/arch.h index 1eadf5a14b0a720..1144faa6ebca772 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 000000000000000..8fb535be9ec3ba5 --- /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 a2b5d96d8d46cd8..b5e90327177f71b 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 edee6fb6aa022f7..65a85c3e3a7259f 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 b5c6a8ddf3e4a9f..000000000000000 --- 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 000000000000000..553024fa3a8c683 --- /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/arm/arch.h b/include/zephyr/arch/arm/arch.h index a726bba8502adde..804e1d23dbdd51e 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 5d86858b05b0f74..f5149799adfc330 100644 --- a/include/zephyr/arch/arm/arch_inlines.h +++ b/include/zephyr/arch/arm/arch_inlines.h @@ -4,10 +4,19 @@ * 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) +{ + return (_cpu_t *)(read_tpidruro() & TPIDRURO_CURR_CPU); +} +#else #ifndef CONFIG_SMP static ALWAYS_INLINE _cpu_t *arch_curr_cpu(void) @@ -16,6 +25,7 @@ static ALWAYS_INLINE _cpu_t *arch_curr_cpu(void) 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 c083adcd47a7a77..fe36fb2d0e1968b 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 63a118e97e67ab2..77729149e369335 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 @@ -18,8 +18,9 @@ #ifndef _ASMLANGUAGE +#include #include -#include +#include #if defined(CONFIG_CPU_AARCH32_CORTEX_R) || defined(CONFIG_CPU_AARCH32_CORTEX_A) #include @@ -43,8 +44,8 @@ static ALWAYS_INLINE unsigned int arch_irq_lock(void) { unsigned int key; -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) && !defined(CONFIG_ARMV8_M_BASELINE) -#if CONFIG_MP_MAX_NUM_CPUS == 1 +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) +#if CONFIG_MP_MAX_NUM_CPUS == 1 || defined(CONFIG_ARMV8_M_BASELINE) __asm__ volatile("mrs %0, PRIMASK;" "cpsid i" : "=r" (key) @@ -53,7 +54,7 @@ static ALWAYS_INLINE unsigned int arch_irq_lock(void) #else #error "Cortex-M0 and Cortex-M0+ require SoC specific support for cross core synchronisation." #endif -#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) || defined(CONFIG_ARMV8_M_BASELINE) +#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) unsigned int tmp; __asm__ volatile( @@ -61,22 +62,14 @@ static ALWAYS_INLINE unsigned int arch_irq_lock(void) "mrs %0, BASEPRI;" "msr BASEPRI_MAX, %1;" "isb;" - : "=r"(key), -#if defined(CONFIG_ARMV8_M_BASELINE) - /* armv8-m.baseline's mov is limited to registers r0-r7. - * Let the compiler know we have this constraint on tmp. - */ - "=l"(tmp) -#else - "=r"(tmp) -#endif + : "=r"(key), "=r"(tmp) : "i"(_EXC_IRQ_DEFAULT_PRIO) : "memory"); #elif defined(CONFIG_ARMV7_R) || defined(CONFIG_AARCH32_ARMV8_R) \ || defined(CONFIG_ARMV7_A) __asm__ volatile( "mrs %0, cpsr;" - "and %0, #" TOSTR(I_BIT) ";" + "and %0, #" STRINGIFY(I_BIT) ";" "cpsid i;" : "=r" (key) : @@ -95,7 +88,7 @@ static ALWAYS_INLINE unsigned int arch_irq_lock(void) static ALWAYS_INLINE void arch_irq_unlock(unsigned int key) { -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) && !defined(CONFIG_ARMV8_M_BASELINE) +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) if (key != 0U) { return; } @@ -103,7 +96,7 @@ static ALWAYS_INLINE void arch_irq_unlock(unsigned int key) "cpsie i;" "isb" : : : "memory"); -#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) || defined(CONFIG_ARMV8_M_BASELINE) +#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) __asm__ volatile( "msr BASEPRI, %0;" "isb;" @@ -133,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 806d28247ac57d3..61e520ffc23cd86 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 92f074f1b36a7b5..000000000000000 --- 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 000000000000000..3bef647566d3ca4 --- /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 a4e74b0daa42c2e..983654ce1387f97 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 @@ -72,6 +72,7 @@ MAKE_REG_HELPER(mair0, 0, 10, 2, 0); MAKE_REG_HELPER(vbar, 0, 12, 0, 0); MAKE_REG_HELPER(cntv_ctl, 0, 14, 3, 1); MAKE_REG_HELPER(ctr, 0, 0, 0, 1); +MAKE_REG_HELPER(tpidruro, 0, 13, 0, 3); MAKE_REG64_HELPER(ICC_SGI1R, 0, 12); MAKE_REG64_HELPER(cntvct, 1, 14); MAKE_REG64_HELPER(cntv_cval, 3, 14); @@ -98,5 +99,8 @@ MAKE_REG_HELPER(ICC_IGRPEN1_EL1, 0, 12, 12, 7); #define write_sysreg(val, reg) write_##reg(val) #define read_sysreg(reg) read_##reg() +#define sev() __asm__ volatile("sev" : : : "memory") +#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 a27dd55a8cf29ae..0514690689ce872 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,6 +81,8 @@ _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 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 c4598302aaef341..888e328e6b2d565 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 d513ecdffc86936..6cd10c5d8e0559f 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_a_r/tpidruro.h b/include/zephyr/arch/arm/cortex_a_r/tpidruro.h new file mode 100644 index 000000000000000..25eb275af9c2173 --- /dev/null +++ b/include/zephyr/arch/arm/cortex_a_r/tpidruro.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief tpidruro bits allocation + * + * Among other things, the tpidruro holds the address for the current + * CPU's struct _cpu instance. But such a pointer is at least 4-bytes + * aligned. That leaves two of free bits for other purposes. + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_TPIDRURO_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_TPIDRURO_H_ + +#define TPIDRURO_CURR_CPU 0xFFFFFFFCUL + +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_TPIDRURO_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 8a2cfc8cc3f4f69..000000000000000 --- 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 000000000000000..a9896cea1e4ed05 --- /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 17f75cec50e599c..cf01fddf4f93869 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 823102730195b01..b73a77f10ea2388 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 caececd3c0d17c2..947bfb6eaf56c5a 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 70eea9a5c6d1bab..42286ce95b749a8 100644 --- a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld +++ b/include/zephyr/arch/arm/cortex_m/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 * 1024 - CONFIG_FLASH_LOAD_OFFSET - ROM_END_OFFSET) #endif #if defined(CONFIG_XIP) @@ -75,10 +81,15 @@ _region_min_align = 4; . = ALIGN(_region_min_align) #endif +#include + MEMORY { FLASH (rx) : ORIGIN = ROM_ADDR, LENGTH = ROM_SIZE RAM (wx) : ORIGIN = RAM_ADDR, LENGTH = RAM_SIZE +#if defined(CONFIG_LINKER_DEVNULL_MEMORY) + DEVNULL_ROM (rx) : ORIGIN = DEVNULL_ADDR, LENGTH = DEVNULL_SIZE +#endif LINKER_DT_REGIONS() /* Used by and documented in include/linker/intlist.ld */ IDT_LIST (wx) : ORIGIN = 0xFFFFF7FF, LENGTH = 2K @@ -385,6 +396,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) @@ -419,6 +435,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 603e1d000888c79..a30c674c4ff084d 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 9cd664e2c6b5de5..000000000000000 --- 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 000000000000000..cc20225e4832c87 --- /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 000000000000000..e8e606d7def805b --- /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 aafc56a19a77c13..42a2a364fb3dfc4 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 @@ -75,14 +75,6 @@ extern void z_arm_int_exit(void); extern void z_arm_interrupt_init(void); -/* macros convert value of its argument to a string */ -#define DO_TOSTR(s) #s -#define TOSTR(s) DO_TOSTR(s) - -/* concatenate the values of the arguments into one */ -#define DO_CONCAT(x, y) x ## y -#define CONCAT(x, y) DO_CONCAT(x, y) - /* Flags for use with IRQ_CONNECT() */ /** * Set this interrupt up as a zero-latency IRQ. If CONFIG_ZERO_LATENCY_LEVELS @@ -241,7 +233,7 @@ extern void z_arm_irq_direct_dynamic_dispatch_no_reschedule(void); */ #define ARM_IRQ_DIRECT_DYNAMIC_CONNECT(irq_p, priority_p, flags_p, resch) \ IRQ_DIRECT_CONNECT(irq_p, priority_p, \ - CONCAT(z_arm_irq_direct_dynamic_dispatch_, resch), flags_p) + _CONCAT(z_arm_irq_direct_dynamic_dispatch_, resch), flags_p) #endif /* CONFIG_DYNAMIC_DIRECT_INTERRUPTS */ @@ -262,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 ab67a35e94cf4f7..99f99b59b2b59a9 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 a4f0fe34b4db457..4179436615d3460 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 857465a4824ccfd..9a8ffc7a7244e17 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 cf60cca99da9ce8..11d4a2e754708e3 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 2b40050afa4c672..b95565658027cac 100644 --- a/include/zephyr/arch/arm/mpu/nxp_mpu.h +++ b/include/zephyr/arch/arm/mpu/nxp_mpu.h @@ -3,15 +3,11 @@ * * 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 -#include - -#define NXP_MPU_BASE SYSMPU_BASE - #define NXP_MPU_REGION_NUMBER 12 /* Bus Master User Mode Access */ @@ -270,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 a4bd85802c1a745..33f46084248ed95 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/structs.h b/include/zephyr/arch/arm/structs.h new file mode 100644 index 000000000000000..4fbf588c5cdbc66 --- /dev/null +++ b/include/zephyr/arch/arm/structs.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ARM_STRUCTS_H_ +#define ZEPHYR_INCLUDE_ARM_STRUCTS_H_ + +#include + +#if defined(CONFIG_CPU_AARCH32_CORTEX_A) || defined(CONFIG_CPU_AARCH32_CORTEX_R) +/* Per CPU architecture specifics */ +struct _cpu_arch { + int8_t exc_depth; +}; + +#else + +/* Default definitions when no architecture specific definitions exist. */ + +/* Per CPU architecture specifics (empty) */ +struct _cpu_arch { +#ifdef __cplusplus + /* This struct will have a size 0 in C which is not allowed in C++ (it'll have a size 1). To + * prevent this, we add a 1 byte dummy variable. + */ + uint8_t dummy; +#endif +}; + +#endif + +#endif /* ZEPHYR_INCLUDE_ARM_STRUCTS_H_ */ diff --git a/include/zephyr/arch/arm/syscall.h b/include/zephyr/arch/arm/syscall.h index a4e067307ec78d2..e07dab12a9e2cd3 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 7ddd574c579a967..139f606809f9d98 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 @@ -32,6 +32,9 @@ struct _callee_saved { uint32_t v7; /* r10 */ uint32_t v8; /* r11 */ uint32_t psp; /* r13 */ +#ifdef CONFIG_USE_SWITCH + uint32_t lr; /* lr */ +#endif }; typedef struct _callee_saved _callee_saved_t; @@ -74,6 +77,10 @@ struct _thread_arch { struct _preempt_float preempt_float; #endif +#if defined(CONFIG_CPU_AARCH32_CORTEX_A) || defined(CONFIG_CPU_AARCH32_CORTEX_R) + int8_t exception_depth; +#endif + #if defined(CONFIG_ARM_STORE_EXC_RETURN) || defined(CONFIG_USERSPACE) /* * Status variable holding several thread status flags @@ -136,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 c181b08f55e2fe7..1f38bd84a2f094d 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_mem.h b/include/zephyr/arch/arm64/arm_mem.h index 23569f6c345fc7c..110f85a24caa60b 100644 --- a/include/zephyr/arch/arm64/arm_mem.h +++ b/include/zephyr/arch/arm64/arm_mem.h @@ -8,7 +8,7 @@ /* * Define ARM specific memory flags used by z_phys_map() - * followed public definitions in include/sys/mem_manage.h. + * followed public definitions in include/kernel/mm.h. */ /* For ARM64, K_MEM_CACHE_NONE is nGnRnE. */ #define K_MEM_ARM_DEVICE_nGnRnE K_MEM_CACHE_NONE diff --git a/include/zephyr/arch/arm64/arm_mmu.h b/include/zephyr/arch/arm64/arm_mmu.h index 6f71ac25897bb0a..b0c197b9b2bcbff 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/cpu.h b/include/zephyr/arch/arm64/cpu.h index bd2919579598277..468db381ef5faba 100644 --- a/include/zephyr/arch/arm64/cpu.h +++ b/include/zephyr/arch/arm64/cpu.h @@ -137,6 +137,7 @@ #define HCR_FMO_BIT BIT(3) #define HCR_IMO_BIT BIT(4) #define HCR_AMO_BIT BIT(5) +#define HCR_TGE_BIT BIT(27) #define HCR_RW_BIT BIT(31) /* System register interface to GICv3 */ diff --git a/include/zephyr/arch/arm64/error.h b/include/zephyr/arch/arm64/error.h index 34565107d081c44..d4d15fc3e9957bd 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 5a46671d157bca6..000000000000000 --- 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 000000000000000..4ccdc41f19cf73a --- /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 fa08b7303047853..38a7bac297b1b6a 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) diff --git a/include/zephyr/arch/cache.h b/include/zephyr/arch/cache.h index 59bdf61e0d02f23..f2943bdd7f9cf91 100644 --- a/include/zephyr/arch/cache.h +++ b/include/zephyr/arch/cache.h @@ -25,14 +25,14 @@ #include #endif -#if defined(CONFIG_DCACHE) +#if defined(CONFIG_DCACHE) || defined(__DOXYGEN__) /** * @brief Enable the d-cache * * Enable the data cache. */ -extern void arch_dcache_enable(void); +void arch_dcache_enable(void); #define cache_data_enable arch_dcache_enable @@ -41,7 +41,7 @@ extern void arch_dcache_enable(void); * * Disable the data cache. */ -extern void arch_dcache_disable(void); +void arch_dcache_disable(void); #define cache_data_disable arch_dcache_disable @@ -54,7 +54,7 @@ extern void arch_dcache_disable(void); * @retval -ENOTSUP If not supported. * @retval -errno Negative errno for other failures. */ -extern int arch_dcache_flush_all(void); +int arch_dcache_flush_all(void); #define cache_data_flush_all arch_dcache_flush_all @@ -67,7 +67,7 @@ extern int arch_dcache_flush_all(void); * @retval -ENOTSUP If not supported. * @retval -errno Negative errno for other failures. */ -extern int arch_dcache_invd_all(void); +int arch_dcache_invd_all(void); #define cache_data_invd_all arch_dcache_invd_all @@ -80,7 +80,7 @@ extern int arch_dcache_invd_all(void); * @retval -ENOTSUP If not supported. * @retval -errno Negative errno for other failures. */ -extern int arch_dcache_flush_and_invd_all(void); +int arch_dcache_flush_and_invd_all(void); #define cache_data_flush_and_invd_all arch_dcache_flush_and_invd_all @@ -103,7 +103,7 @@ extern int arch_dcache_flush_and_invd_all(void); * @retval -ENOTSUP If not supported. * @retval -errno Negative errno for other failures. */ -extern int arch_dcache_flush_range(void *addr, size_t size); +int arch_dcache_flush_range(void *addr, size_t size); #define cache_data_flush_range(addr, size) arch_dcache_flush_range(addr, size) @@ -127,7 +127,7 @@ extern int arch_dcache_flush_range(void *addr, size_t size); * @retval -ENOTSUP If not supported. * @retval -errno Negative errno for other failures. */ -extern int arch_dcache_invd_range(void *addr, size_t size); +int arch_dcache_invd_range(void *addr, size_t size); #define cache_data_invd_range(addr, size) arch_dcache_invd_range(addr, size) @@ -152,12 +152,12 @@ extern int arch_dcache_invd_range(void *addr, size_t size); * @retval -errno Negative errno for other failures. */ -extern int arch_dcache_flush_and_invd_range(void *addr, size_t size); +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__) /** * @@ -172,22 +172,22 @@ extern int arch_dcache_flush_and_invd_range(void *addr, size_t size); * @retval size Size of the d-cache line. * @retval 0 If the d-cache is not enabled. */ -extern size_t arch_dcache_line_size_get(void); +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 * * Enable the instruction cache. */ -extern void arch_icache_enable(void); +void arch_icache_enable(void); #define cache_instr_enable arch_icache_enable @@ -196,7 +196,7 @@ extern void arch_icache_enable(void); * * Disable the instruction cache. */ -extern void arch_icache_disable(void); +void arch_icache_disable(void); #define cache_instr_disable arch_icache_disable @@ -209,7 +209,7 @@ extern void arch_icache_disable(void); * @retval -ENOTSUP If not supported. * @retval -errno Negative errno for other failures. */ -extern int arch_icache_flush_all(void); +int arch_icache_flush_all(void); #define cache_instr_flush_all arch_icache_flush_all @@ -222,7 +222,7 @@ extern int arch_icache_flush_all(void); * @retval -ENOTSUP If not supported. * @retval -errno Negative errno for other failures. */ -extern int arch_icache_invd_all(void); +int arch_icache_invd_all(void); #define cache_instr_invd_all arch_icache_invd_all @@ -235,7 +235,7 @@ extern int arch_icache_invd_all(void); * @retval -ENOTSUP If not supported. * @retval -errno Negative errno for other failures. */ -extern int arch_icache_flush_and_invd_all(void); +int arch_icache_flush_and_invd_all(void); #define cache_instr_flush_and_invd_all arch_icache_flush_and_invd_all @@ -258,7 +258,7 @@ extern int arch_icache_flush_and_invd_all(void); * @retval -ENOTSUP If not supported. * @retval -errno Negative errno for other failures. */ -extern int arch_icache_flush_range(void *addr, size_t size); +int arch_icache_flush_range(void *addr, size_t size); #define cache_instr_flush_range(addr, size) arch_icache_flush_range(addr, size) @@ -282,7 +282,7 @@ extern int arch_icache_flush_range(void *addr, size_t size); * @retval -ENOTSUP If not supported. * @retval -errno Negative errno for other failures. */ -extern int arch_icache_invd_range(void *addr, size_t size); +int arch_icache_invd_range(void *addr, size_t size); #define cache_instr_invd_range(addr, size) arch_icache_invd_range(addr, size) @@ -306,12 +306,12 @@ extern int arch_icache_invd_range(void *addr, size_t size); * @retval -ENOTSUP If not supported. * @retval -errno Negative errno for other failures. */ -extern int arch_icache_flush_and_invd_range(void *addr, size_t size); +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__) /** * @@ -327,13 +327,13 @@ extern int arch_icache_flush_and_invd_range(void *addr, size_t size); * @retval 0 If the d-cache is not enabled. */ -extern size_t arch_icache_line_size_get(void); +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__ */ /** * @} diff --git a/include/zephyr/arch/mips/arch.h b/include/zephyr/arch/mips/arch.h index 67f6c8460415b15..f99744bf08650c6 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 000000000000000..d4403f1d5995eb2 --- /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 37b2cadb2fa6c48..000000000000000 --- 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 6958533eaf6b536..f7ba64088fc6ed3 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 99bccb74a08ae28..e7dcfbef3aed140 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 5bed82439d65f2f..8c3dee305f9e9f5 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,6 +29,12 @@ #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 + #ifdef CONFIG_XIP #if DT_NODE_HAS_COMPAT_STATUS(DT_CHOSEN(zephyr_flash), soc_nv_flash, okay) #ifdef CONFIG_FLASH_LOAD_OFFSET @@ -38,7 +43,7 @@ #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_SIZE (DT_REG_SIZE(DT_CHOSEN(zephyr_flash)) - ROM_END_OFFSET) #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 @@ -46,11 +51,11 @@ */ #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_SIZE (DT_REG_SIZE_BY_IDX(SPI_CTRL, 1) - ROM_END_OFFSET) #endif #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 @@ -72,6 +77,8 @@ #define MPU_ALIGN(region_size) . = ALIGN(4) #endif +#include + MEMORY { #ifdef CONFIG_XIP @@ -79,6 +86,10 @@ MEMORY #endif RAM (rwx) : ORIGIN = RAM_BASE, LENGTH = RAM_SIZE +#if defined(CONFIG_LINKER_DEVNULL_MEMORY) + DEVNULL_ROM (rx) : ORIGIN = DEVNULL_ADDR, LENGTH = DEVNULL_SIZE +#endif + LINKER_DT_REGIONS() /* Used by and documented in include/linker/intlist.ld */ @@ -316,6 +327,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) @@ -350,6 +366,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 e6af12f700e1576..a7c3e02b482970f 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 000000000000000..644df2cd1fbf911 --- /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 e661e5aa86ea1a4..000000000000000 --- 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 77c0d4057aaf3f6..c3764f8289be641 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); @@ -48,6 +71,7 @@ extern void z_riscv_irq_priority_set(unsigned int irq, { \ Z_ISR_DECLARE(irq_p + CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET, \ ISR_FLAG_DIRECT, isr_p, NULL); \ + 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/structs.h b/include/zephyr/arch/structs.h index 570c3959b7ea6a1..703ec81f889c4f5 100644 --- a/include/zephyr/arch/structs.h +++ b/include/zephyr/arch/structs.h @@ -27,6 +27,8 @@ #include #elif defined(CONFIG_RISCV) #include +#elif defined(CONFIG_ARM) +#include #else /* Default definitions when no architecture specific definitions exist. */ diff --git a/include/zephyr/arch/syscall.h b/include/zephyr/arch/syscall.h index b657717e3d4bc6b..5b41561b681907c 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/ia32/arch.h b/include/zephyr/arch/x86/ia32/arch.h index e4bc3c5dba96a92..bd6ae1ed040caba 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/ia32/linker.ld b/include/zephyr/arch/x86/ia32/linker.ld index 4d3ebe03f850acd..a0e2f5c6732ebde 100644 --- a/include/zephyr/arch/x86/ia32/linker.ld +++ b/include/zephyr/arch/x86/ia32/linker.ld @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include diff --git a/include/zephyr/arch/x86/memory.ld b/include/zephyr/arch/x86/memory.ld index 8cc19fd6484ca72..c9ede2b9d232930 100644 --- a/include/zephyr/arch/x86/memory.ld +++ b/include/zephyr/arch/x86/memory.ld @@ -29,7 +29,7 @@ #include #include -#include +#include /* Bounds of physical RAM from DTS */ #define PHYS_RAM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_sram)) @@ -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/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 2d13615a753ac9d..26325a984e16230 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,6 +160,19 @@ static inline bool arch_mem_coherent(void *ptr) } #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 inline bool arch_xtensa_is_ptr_cached(void *ptr) { size_t addr = (size_t) ptr; @@ -113,6 +180,19 @@ static inline bool arch_xtensa_is_ptr_cached(void *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_xtensa_is_ptr_uncached(void *ptr) { size_t addr = (size_t) ptr; @@ -140,6 +220,7 @@ static ALWAYS_INLINE uint32_t z_xtrpoflip(uint32_t addr, uint32_t rto, uint32_t return (addr & ~(7U << 29)) | rto; } } + /** * @brief Return cached pointer to a RAM address * @@ -238,14 +319,54 @@ 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) +/** + * @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 +#else /* CONFIG_XTENSA_RPO_CACHE */ -#ifdef CONFIG_XTENSA_MMU +static inline bool arch_xtensa_is_ptr_cached(void *ptr) +{ + ARG_UNUSED(ptr); + + return false; +} + +static inline bool arch_xtensa_is_ptr_uncached(void *ptr) +{ + ARG_UNUSED(ptr); + + return false; +} + +static inline void *arch_xtensa_cached_ptr(void *ptr) +{ + return ptr; +} + +static inline void *arch_xtensa_uncached_ptr(void *ptr) +{ + return ptr; +} + +#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 d5fcc55af47c80a..4e7b52002768ac0 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 c518f4df4ed4929..a8f5d0f78e95422 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 4f472b3667c59af..6fb64ef30d5e157 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,17 +172,20 @@ 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 */ } diff --git a/include/zephyr/arch/xtensa/exc.h b/include/zephyr/arch/xtensa/exc.h deleted file mode 100644 index e207261a0278c19..000000000000000 --- 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 000000000000000..51a5d5aef9036c0 --- /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 627bb79e6785bb4..89aabb029056286 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 69cef4e8627d4f9..938ab7b2303c2eb 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 000000000000000..b8b0bea8cdbce9f --- /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 4ec5da1ea2c048c..2bebe2722bcb2d5 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 000000000000000..b862b7a8c1e284d --- /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 d03f876af30b114..d4deca40b311b2e 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/codec.h b/include/zephyr/audio/codec.h index 18a26a01adb4baf..082fd3e4ae3e6f2 100644 --- a/include/zephyr/audio/codec.h +++ b/include/zephyr/audio/codec.h @@ -111,6 +111,35 @@ typedef union { bool mute; /**< Mute if @a true, unmute if @a false */ } audio_property_value_t; +/** + * @brief Codec error type + */ +enum audio_codec_error_type { + /** Output over-current */ + AUDIO_CODEC_ERROR_OVERCURRENT = BIT(0), + + /** Codec over-temperature */ + AUDIO_CODEC_ERROR_OVERTEMPERATURE = BIT(1), + + /** Power low voltage */ + AUDIO_CODEC_ERROR_UNDERVOLTAGE = BIT(2), + + /** Power high voltage */ + AUDIO_CODEC_ERROR_OVERVOLTAGE = BIT(3), + + /** Output direct-current */ + AUDIO_CODEC_ERROR_DC = BIT(4), +}; + +/** + * @typedef audio_codec_error_callback_t + * @brief Callback for error interrupt + * + * @param dev Pointer to the codec device + * @param errors Device errors (bitmask of @ref audio_codec_error_type values) + */ +typedef void (*audio_codec_error_callback_t)(const struct device *dev, uint32_t errors); + /** * @cond INTERNAL_HIDDEN * @@ -126,6 +155,9 @@ struct audio_codec_api { audio_channel_t channel, audio_property_value_t val); int (*apply_properties)(const struct device *dev); + int (*clear_errors)(const struct device *dev); + int (*register_error_callback)(const struct device *dev, + audio_codec_error_callback_t cb); }; /** * @endcond @@ -223,6 +255,55 @@ static inline int audio_codec_apply_properties(const struct device *dev) return api->apply_properties(dev); } +/** + * @brief Clear any codec errors + * + * Clear all codec errors. + * If an error interrupt exists, it will be de-asserted. + * + * @param dev Pointer to the device structure for codec driver instance. + * + * @return 0 on success, negative error code on failure + */ +static inline int audio_codec_clear_errors(const struct device *dev) +{ + const struct audio_codec_api *api = + (const struct audio_codec_api *)dev->api; + + if (api->clear_errors == NULL) { + return -ENOSYS; + } + + return api->clear_errors(dev); +} + +/** + * @brief Register a callback function for codec error + * + * The callback will be called from a thread, so I2C or SPI operations are + * safe. However, the thread's stack is limited and defined by the + * driver. It is currently up to the caller to ensure that the callback + * does not overflow the stack. + * + * @param dev Pointer to the audio codec device + * @param cb The function that should be called when an error is detected + * fires + * + * @return 0 if successful, negative errno code if failure. + */ +static inline int audio_codec_register_error_callback(const struct device *dev, + audio_codec_error_callback_t cb) +{ + const struct audio_codec_api *api = + (const struct audio_codec_api *)dev->api; + + if (api->register_error_callback == NULL) { + return -ENOSYS; + } + + return api->register_error_callback(dev, cb); +} + #ifdef __cplusplus } #endif diff --git a/include/zephyr/audio/dmic.h b/include/zephyr/audio/dmic.h index e6736b8676c8f34..e0582c45debb221 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/a2dp-codec.h b/include/zephyr/bluetooth/a2dp-codec.h index 9e4e5ea34792baf..3da36420dcd2186 100644 --- a/include/zephyr/bluetooth/a2dp-codec.h +++ b/include/zephyr/bluetooth/a2dp-codec.h @@ -26,36 +26,76 @@ extern "C" { #endif -/* Sampling Frequency */ -#define A2DP_SBC_SAMP_FREQ_16000 BIT(7) -#define A2DP_SBC_SAMP_FREQ_32000 BIT(6) -#define A2DP_SBC_SAMP_FREQ_44100 BIT(5) -#define A2DP_SBC_SAMP_FREQ_48000 BIT(4) +/** + * @name Sampling Frequency + * @{ + */ +#define A2DP_SBC_SAMP_FREQ_16000 BIT(7) /**< 16 kHz */ +#define A2DP_SBC_SAMP_FREQ_32000 BIT(6) /**< 32 kHz */ +#define A2DP_SBC_SAMP_FREQ_44100 BIT(5) /**< 44.1 kHz */ +#define A2DP_SBC_SAMP_FREQ_48000 BIT(4) /**< 48 kHz */ +/** @} */ -/* Channel Mode */ -#define A2DP_SBC_CH_MODE_MONO BIT(3) -#define A2DP_SBC_CH_MODE_DUAL BIT(2) -#define A2DP_SBC_CH_MODE_STREO BIT(1) -#define A2DP_SBC_CH_MODE_JOINT BIT(0) +/** + * @name Channel Mode + * @{ + */ +#define A2DP_SBC_CH_MODE_MONO BIT(3) /**< Mono */ +#define A2DP_SBC_CH_MODE_DUAL BIT(2) /**< Dual Channel */ +#define A2DP_SBC_CH_MODE_STREO BIT(1) /**< Stereo */ +#define A2DP_SBC_CH_MODE_JOINT BIT(0) /**< Joint Stereo */ +/** @} */ -/* Block Length */ -#define A2DP_SBC_BLK_LEN_4 BIT(7) -#define A2DP_SBC_BLK_LEN_8 BIT(6) -#define A2DP_SBC_BLK_LEN_12 BIT(5) -#define A2DP_SBC_BLK_LEN_16 BIT(4) +/** + * @name Block Length + * @{ + */ +#define A2DP_SBC_BLK_LEN_4 BIT(7) /**< 4 blocks */ +#define A2DP_SBC_BLK_LEN_8 BIT(6) /**< 8 blocks */ +#define A2DP_SBC_BLK_LEN_12 BIT(5) /**< 12 blocks */ +#define A2DP_SBC_BLK_LEN_16 BIT(4) /**< 16 blocks */ +/** @} */ -/* Subbands */ -#define A2DP_SBC_SUBBAND_4 BIT(3) -#define A2DP_SBC_SUBBAND_8 BIT(2) +/** + * @name Subbands + * @{ + */ +#define A2DP_SBC_SUBBAND_4 BIT(3) /**< 4 subbands */ +#define A2DP_SBC_SUBBAND_8 BIT(2) /**< 8 subbands */ +/** @} */ -/* Allocation Method */ -#define A2DP_SBC_ALLOC_MTHD_SNR BIT(1) -#define A2DP_SBC_ALLOC_MTHD_LOUDNESS BIT(0) +/** + * @name Bit pool Allocation Method + * @{ + */ +#define A2DP_SBC_ALLOC_MTHD_SNR BIT(1) /**< Allocate based on loudness of the subband signal */ +#define A2DP_SBC_ALLOC_MTHD_LOUDNESS BIT(0) /**< Allocate based on the signal-to-noise ratio */ +/** @} */ +/** + * Gets the sampling rate from a codec preset + * @param preset Codec preset + */ #define BT_A2DP_SBC_SAMP_FREQ(preset) ((preset->config[0] >> 4) & 0x0f) +/** + * Gets the channel mode from a codec preset + * @param preset Codec preset + */ #define BT_A2DP_SBC_CHAN_MODE(preset) ((preset->config[0]) & 0x0f) +/** + * Gets the block length from a codec preset + * @param preset Codec preset + */ #define BT_A2DP_SBC_BLK_LEN(preset) ((preset->config[1] >> 4) & 0x0f) +/** + * Gets the number subbands from a codec preset + * @param preset Codec preset + */ #define BT_A2DP_SBC_SUB_BAND(preset) ((preset->config[1] >> 2) & 0x03) +/** + * Gets the bitpool allocation method from a codec preset + * @param preset Codec preset + */ #define BT_A2DP_SBC_ALLOC_MTHD(preset) ((preset->config[1]) & 0x03) /** @brief SBC Codec */ diff --git a/include/zephyr/bluetooth/a2dp.h b/include/zephyr/bluetooth/a2dp.h index 3df6db1a6fd8175..f7e8ff35ea154a9 100644 --- a/include/zephyr/bluetooth/a2dp.h +++ b/include/zephyr/bluetooth/a2dp.h @@ -1,5 +1,5 @@ /** @file - * @brief Advance Audio Distribution Profile header. + * @brief Advanced Audio Distribution Profile header. */ /* diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index 5bf6fad74a60a55..772e93588fa5049 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 @@ -209,6 +211,7 @@ enum bt_audio_metadata_type { ((struct bt_audio_codec_cfg){ \ /* Use HCI data path as default, can be overwritten by application */ \ .path_id = BT_ISO_DATA_PATH_HCI, \ + .ctlr_transcode = false, \ .id = _id, \ .cid = _cid, \ .vid = _vid, \ @@ -231,6 +234,7 @@ enum bt_audio_metadata_type { ((struct bt_audio_codec_cap){ \ /* Use HCI data path as default, can be overwritten by application */ \ .path_id = BT_ISO_DATA_PATH_HCI, \ + .ctlr_transcode = false, \ .id = (_id), \ .cid = (_cid), \ .vid = (_vid), \ @@ -245,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), @@ -316,6 +320,12 @@ struct bt_audio_codec_cap { * vendor specific ID. */ uint8_t path_id; + /** Whether or not the local controller should transcode + * + * This effectively sets the coding format for the ISO data path to @ref + * BT_HCI_CODING_FORMAT_TRANSPARENT if false, else uses the @ref bt_audio_codec_cfg.id. + */ + bool ctlr_transcode; /** Codec ID */ uint8_t id; /** Codec Company ID */ @@ -344,6 +354,12 @@ struct bt_audio_codec_cfg { * vendor specific ID. */ uint8_t path_id; + /** Whether or not the local controller should transcode + * + * This effectively sets the coding format for the ISO data path to @ref + * BT_HCI_CODING_FORMAT_TRANSPARENT if false, else uses the @ref bt_audio_codec_cfg.id. + */ + bool ctlr_transcode; /** Codec ID */ uint8_t id; /** Codec Company ID */ @@ -479,6 +495,31 @@ struct bt_audio_codec_qos { * Value range 0 to @ref BT_AUDIO_PD_MAX. */ uint32_t pd; + +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + /** @brief Maximum PDU size + * + * Maximum size, in octets, of the payload from link layer to link + * layer. + * + * Value range @ref BT_ISO_PDU_MIN to @ref BT_ISO_PDU_MAX. + */ + uint16_t max_pdu; + + /** @brief Burst number + * + * Value range @ref BT_ISO_BN_MIN to @ref BT_ISO_BN_MAX. + */ + uint8_t burst_number; + + /** @brief Number of subevents + * + * Maximum number of subevents in each CIS or BIS event. + * + * Value range @ref BT_ISO_NSE_MIN to @ref BT_ISO_NSE_MAX. + */ + uint8_t num_subevents; +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; /** @@ -610,16 +651,49 @@ int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg); int bt_audio_codec_cfg_set_freq(struct bt_audio_codec_cfg *codec_cfg, enum bt_audio_codec_config_freq freq); +/** + * @brief Convert assigned numbers frame duration to duration in microseconds. + * + * @param frame_dur The assigned numbers frame duration to convert. + * + * @retval -EINVAL if arguments are invalid. + * @retval The converted frame duration value in microseconds. + */ +int bt_audio_codec_cfg_frame_dur_to_frame_dur_us(enum bt_audio_codec_config_frame_dur frame_dur); + +/** + * @brief Convert frame duration in microseconds to assigned numbers frame duration. + * + * @param frame_dur_us The frame duration in microseconds to convert. + * + * @retval -EINVAL if arguments are invalid. + * @retval The assigned numbers frame duration (@ref bt_audio_codec_config_frame_dur). + */ +int bt_audio_codec_cfg_frame_dur_us_to_frame_dur(uint32_t frame_dur_us); + /** @brief Extract frame duration from BT codec config * * @param codec_cfg The codec configuration to extract data from. * - * @retval Frame duration in microseconds + * @retval A @ref bt_audio_codec_config_frame_dur value * @retval -EINVAL if arguments are invalid * @retval -ENODATA if not found * @retval -EBADMSG if found value has invalid size or value */ -int bt_audio_codec_cfg_get_frame_duration_us(const struct bt_audio_codec_cfg *codec_cfg); +int bt_audio_codec_cfg_get_frame_dur(const struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Set the frame duration of a codec configuration. + * + * @param codec_cfg The codec configuration to set data for. + * @param frame_dur The assigned numbers frame duration to set. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_set_frame_dur(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_frame_dur frame_dur); /** @brief Extract channel allocation from BT codec config * @@ -730,8 +804,8 @@ int bt_audio_codec_cfg_set_frame_blocks_per_sdu(struct bt_audio_codec_cfg *codec * @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 */ -uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type, - const uint8_t **data); +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); /** * @brief Set or add a specific codec configuration value @@ -745,8 +819,23 @@ uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, u * @retval -EINVAL if arguments are invalid * @retval -ENOMEM if the new value could not set or added due to memory */ -int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, uint8_t type, - const uint8_t *data, size_t data_len); +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 * @@ -762,6 +851,35 @@ int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, uint8_t typ int bt_audio_codec_cfg_meta_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type, const uint8_t **data); +/** + * @brief Set or add a specific codec configuration metadata value. + * + * @param codec_cfg The codec configuration to set the value in. + * @param type The type id to set. + * @param data Pointer to the data-pointer to set. + * @param data_len Length of @p data. + * + * @retval The meta_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +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. @@ -775,6 +893,19 @@ int bt_audio_codec_cfg_meta_get_val(const struct bt_audio_codec_cfg *codec_cfg, */ int bt_audio_codec_cfg_meta_get_pref_context(const struct bt_audio_codec_cfg *codec_cfg); +/** + * @brief Set the preferred context of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param ctx The preferred context to set. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_pref_context(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_context ctx); + /** @brief Extract stream contexts * * See @ref BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT for more information about this value. @@ -788,6 +919,19 @@ int bt_audio_codec_cfg_meta_get_pref_context(const struct bt_audio_codec_cfg *co */ int bt_audio_codec_cfg_meta_get_stream_context(const struct bt_audio_codec_cfg *codec_cfg); +/** + * @brief Set the stream context of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param ctx The stream context to set. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_stream_context(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_context ctx); + /** @brief Extract program info * * See @ref BT_AUDIO_METADATA_TYPE_PROGRAM_INFO for more information about this value. @@ -802,6 +946,20 @@ int bt_audio_codec_cfg_meta_get_stream_context(const struct bt_audio_codec_cfg * int bt_audio_codec_cfg_meta_get_program_info(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **program_info); +/** + * @brief Set the program info of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param program_info The program info to set. + * @param program_info_len The length of @p program_info. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_program_info(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *program_info, size_t program_info_len); + /** @brief Extract stream language * * See @ref BT_AUDIO_METADATA_TYPE_STREAM_LANG for more information about this value. @@ -815,6 +973,19 @@ int bt_audio_codec_cfg_meta_get_program_info(const struct bt_audio_codec_cfg *co */ int bt_audio_codec_cfg_meta_get_stream_lang(const struct bt_audio_codec_cfg *codec_cfg); +/** + * @brief Set the stream language of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param stream_lang The 24-bit stream language to set. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_stream_lang(struct bt_audio_codec_cfg *codec_cfg, + uint32_t stream_lang); + /** @brief Extract CCID list * * See @ref BT_AUDIO_METADATA_TYPE_CCID_LIST for more information about this value. @@ -829,6 +1000,20 @@ int bt_audio_codec_cfg_meta_get_stream_lang(const struct bt_audio_codec_cfg *cod int bt_audio_codec_cfg_meta_get_ccid_list(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **ccid_list); +/** + * @brief Set the CCID list of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param ccid_list The program info to set. + * @param ccid_list_len The length of @p ccid_list. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_ccid_list(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *ccid_list, size_t ccid_list_len); + /** @brief Extract parental rating * * See @ref BT_AUDIO_METADATA_TYPE_PARENTAL_RATING for more information about this value. @@ -842,6 +1027,19 @@ int bt_audio_codec_cfg_meta_get_ccid_list(const struct bt_audio_codec_cfg *codec */ int bt_audio_codec_cfg_meta_get_parental_rating(const struct bt_audio_codec_cfg *codec_cfg); +/** + * @brief Set the parental rating of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param parental_rating The parental rating to set. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_parental_rating(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_parental_rating parental_rating); + /** @brief Extract program info URI * * See @ref BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI for more information about this value. @@ -856,6 +1054,21 @@ int bt_audio_codec_cfg_meta_get_parental_rating(const struct bt_audio_codec_cfg int bt_audio_codec_cfg_meta_get_program_info_uri(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **program_info_uri); +/** + * @brief Set the program info URI of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param program_info_uri The program info URI to set. + * @param program_info_uri_len The length of @p program_info_uri. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_program_info_uri(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *program_info_uri, + size_t program_info_uri_len); + /** @brief Extract audio active state * * See @ref BT_AUDIO_METADATA_TYPE_AUDIO_STATE for more information about this value. @@ -869,6 +1082,19 @@ int bt_audio_codec_cfg_meta_get_program_info_uri(const struct bt_audio_codec_cfg */ int bt_audio_codec_cfg_meta_get_audio_active_state(const struct bt_audio_codec_cfg *codec_cfg); +/** + * @brief Set the audio active state of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param state The audio active state to set. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_audio_active_state(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_active_state state); + /** @brief Extract broadcast audio immediate rendering flag * * See @ref BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE for more information about this value. @@ -882,6 +1108,18 @@ int bt_audio_codec_cfg_meta_get_audio_active_state(const struct bt_audio_codec_c int bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag( const struct bt_audio_codec_cfg *codec_cfg); +/** + * @brief Set the broadcast audio immediate rendering flag of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_bcast_audio_immediate_rend_flag( + struct bt_audio_codec_cfg *codec_cfg); + /** @brief Extract extended metadata * * See @ref BT_AUDIO_METADATA_TYPE_EXTENDED for more information about this value. @@ -896,6 +1134,20 @@ int bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag( int bt_audio_codec_cfg_meta_get_extended(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **extended_meta); +/** + * @brief Set the extended metadata of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param extended_meta The extended metadata to set. + * @param extended_meta_len The length of @p extended_meta. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_extended(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *extended_meta, size_t extended_meta_len); + /** @brief Extract vendor specific metadata * * See @ref BT_AUDIO_METADATA_TYPE_VENDOR for more information about this value. @@ -909,6 +1161,20 @@ int bt_audio_codec_cfg_meta_get_extended(const struct bt_audio_codec_cfg *codec_ */ int bt_audio_codec_cfg_meta_get_vendor(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **vendor_meta); + +/** + * @brief Set the vendor specific metadata of a codec configuration metadata. + * + * @param codec_cfg The codec configuration to set data for. + * @param vendor_meta The vendor specific metadata to set. + * @param vendor_meta_len The length of @p vendor_meta. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cfg_meta_set_vendor(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *vendor_meta, size_t vendor_meta_len); /** @} */ /* End of bt_audio_codec_cfg */ /** @@ -924,43 +1190,99 @@ int bt_audio_codec_cfg_meta_get_vendor(const struct bt_audio_codec_cfg *codec_cf /** * @brief Lookup a specific value based on type * - * @param[in] codec_cap The codec data to search in. - * @param[in] type The type id to look for + * @param[in] codec_cap 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 */ -uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type, - const uint8_t **data); +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); + +/** + * @brief Set or add a specific codec capability value + * + * @param codec_cap The codec data to set the value in. + * @param type The type id to set + * @param data Pointer to the data-pointer to set + * @param data_len Length of @p data + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +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. * - * @param codec_cap The codec configuration to extract data from. + * @param codec_cap The codec capabilities to extract data from. * - * @retval Bitfield of supported frequencies if 0 or positive + * @retval Bitfield of supported frequencies (@ref bt_audio_codec_cap_freq) if 0 or positive * @retval -EINVAL if arguments are invalid * @retval -ENODATA if not found * @retval -EBADMSG if found value has invalid size or value */ int bt_audio_codec_cap_get_freq(const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the supported frequencies of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param freq The supported frequencies to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_set_freq(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_cap_freq freq); + /** * @brief Extract the frequency from a codec capability. * - * @param codec_cap The codec configuration to extract data from. + * @param codec_cap The codec capabilities to extract data from. * * @retval Bitfield of supported frame durations if 0 or positive * @retval -EINVAL if arguments are invalid * @retval -ENODATA if not found * @retval -EBADMSG if found value has invalid size or value */ -int bt_audio_codec_cap_get_frame_duration(const struct bt_audio_codec_cap *codec_cap); +int bt_audio_codec_cap_get_frame_dur(const struct bt_audio_codec_cap *codec_cap); + +/** + * @brief Set the frame duration of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param frame_dur The frame duration to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_set_frame_dur(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_cap_frame_dur frame_dur); /** * @brief Extract the frequency from a codec capability. * - * @param codec_cap The codec configuration to extract data from. + * @param codec_cap The codec capabilities to extract data from. * * @retval Bitfield of supported channel counts if 0 or positive * @retval -EINVAL if arguments are invalid @@ -970,9 +1292,22 @@ int bt_audio_codec_cap_get_frame_duration(const struct bt_audio_codec_cap *codec int bt_audio_codec_cap_get_supported_audio_chan_counts(const struct bt_audio_codec_cap *codec_cap); /** - * @brief Extract the frequency from a codec capability. + * @brief Set the channel count of a codec capability. * - * @param[in] codec_cap The codec configuration to extract data from. + * @param codec_cap The codec capabilities to set data for. + * @param chan_count The channel count frequency to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_set_supported_audio_chan_counts( + struct bt_audio_codec_cap *codec_cap, enum bt_audio_codec_cap_chan_count chan_count); + +/** + * @brief Extract the supported octets per codec frame from a codec capability. + * + * @param[in] codec_cap The codec capabilities to extract data from. * @param[out] codec_frame Struct to place the resulting values in * * @retval 0 on success @@ -985,9 +1320,23 @@ int bt_audio_codec_cap_get_octets_per_frame( struct bt_audio_codec_octets_per_codec_frame *codec_frame); /** - * @brief Extract the frequency from a codec capability. + * @brief Set the octets per codec frame of a codec capability. * - * @param codec_cap The codec configuration to extract data from. + * @param codec_cap The codec capabilities to set data for. + * @param codec_frame The octets per codec frame to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_set_octets_per_frame( + struct bt_audio_codec_cap *codec_cap, + const struct bt_audio_codec_octets_per_codec_frame *codec_frame); + +/** + * @brief Extract the maximum codec frames per SDU from a codec capability. + * + * @param codec_cap The codec capabilities to extract data from. * * @retval Maximum number of codec frames per SDU supported * @retval -EINVAL if arguments are invalid @@ -996,6 +1345,19 @@ int bt_audio_codec_cap_get_octets_per_frame( */ int bt_audio_codec_cap_get_max_codec_frames_per_sdu(const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the maximum codec frames per SDU of a codec capability. + * + * @param codec_cap The codec capabilities to set data for. + * @param codec_frames_per_sdu The maximum codec frames per SDU to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_set_max_codec_frames_per_sdu(struct bt_audio_codec_cap *codec_cap, + uint8_t codec_frames_per_sdu); + /** @brief Lookup a specific metadata value based on type * * @param[in] codec_cap The codec data to search in. @@ -1009,6 +1371,36 @@ int bt_audio_codec_cap_get_max_codec_frames_per_sdu(const struct bt_audio_codec_ int bt_audio_codec_cap_meta_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type, const uint8_t **data); +/** + * @brief Set or add a specific codec capability metadata value. + * + * @param codec_cap The codec capability to set the value in. + * @param type The type id to set. + * @param data Pointer to the data-pointer to set. + * @param data_len Length of @p data. + * + * @retval The meta_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +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. @@ -1022,6 +1414,19 @@ int bt_audio_codec_cap_meta_get_val(const struct bt_audio_codec_cap *codec_cap, */ int bt_audio_codec_cap_meta_get_pref_context(const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the preferred context of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param ctx The preferred context to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_pref_context(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_context ctx); + /** @brief Extract stream contexts * * See @ref BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT for more information about this value. @@ -1035,6 +1440,19 @@ int bt_audio_codec_cap_meta_get_pref_context(const struct bt_audio_codec_cap *co */ int bt_audio_codec_cap_meta_get_stream_context(const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the stream context of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param ctx The stream context to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_stream_context(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_context ctx); + /** @brief Extract program info * * See @ref BT_AUDIO_METADATA_TYPE_PROGRAM_INFO for more information about this value. @@ -1049,6 +1467,20 @@ int bt_audio_codec_cap_meta_get_stream_context(const struct bt_audio_codec_cap * int bt_audio_codec_cap_meta_get_program_info(const struct bt_audio_codec_cap *codec_cap, const uint8_t **program_info); +/** + * @brief Set the program info of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param program_info The program info to set. + * @param program_info_len The length of @p program_info. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_program_info(struct bt_audio_codec_cap *codec_cap, + const uint8_t *program_info, size_t program_info_len); + /** @brief Extract stream language * * See @ref BT_AUDIO_METADATA_TYPE_STREAM_LANG for more information about this value. @@ -1062,6 +1494,19 @@ int bt_audio_codec_cap_meta_get_program_info(const struct bt_audio_codec_cap *co */ int bt_audio_codec_cap_meta_get_stream_lang(const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the stream language of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param stream_lang The 24-bit stream language to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_stream_lang(struct bt_audio_codec_cap *codec_cap, + uint32_t stream_lang); + /** @brief Extract CCID list * * See @ref BT_AUDIO_METADATA_TYPE_CCID_LIST for more information about this value. @@ -1076,6 +1521,20 @@ int bt_audio_codec_cap_meta_get_stream_lang(const struct bt_audio_codec_cap *cod int bt_audio_codec_cap_meta_get_ccid_list(const struct bt_audio_codec_cap *codec_cap, const uint8_t **ccid_list); +/** + * @brief Set the CCID list of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param ccid_list The program info to set. + * @param ccid_list_len The length of @p ccid_list. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_ccid_list(struct bt_audio_codec_cap *codec_cap, + const uint8_t *ccid_list, size_t ccid_list_len); + /** @brief Extract parental rating * * See @ref BT_AUDIO_METADATA_TYPE_PARENTAL_RATING for more information about this value. @@ -1089,6 +1548,19 @@ int bt_audio_codec_cap_meta_get_ccid_list(const struct bt_audio_codec_cap *codec */ int bt_audio_codec_cap_meta_get_parental_rating(const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the parental rating of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param parental_rating The parental rating to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_parental_rating(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_parental_rating parental_rating); + /** @brief Extract program info URI * * See @ref BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI for more information about this value. @@ -1103,6 +1575,21 @@ int bt_audio_codec_cap_meta_get_parental_rating(const struct bt_audio_codec_cap int bt_audio_codec_cap_meta_get_program_info_uri(const struct bt_audio_codec_cap *codec_cap, const uint8_t **program_info_uri); +/** + * @brief Set the program info URI of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param program_info_uri The program info URI to set. + * @param program_info_uri_len The length of @p program_info_uri. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_program_info_uri(struct bt_audio_codec_cap *codec_cap, + const uint8_t *program_info_uri, + size_t program_info_uri_len); + /** @brief Extract audio active state * * See @ref BT_AUDIO_METADATA_TYPE_AUDIO_STATE for more information about this value. @@ -1116,6 +1603,19 @@ int bt_audio_codec_cap_meta_get_program_info_uri(const struct bt_audio_codec_cap */ int bt_audio_codec_cap_meta_get_audio_active_state(const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the audio active state of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param state The audio active state to set. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_audio_active_state(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_active_state state); + /** @brief Extract broadcast audio immediate rendering flag * * See @ref BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE for more information about this value. @@ -1129,6 +1629,18 @@ int bt_audio_codec_cap_meta_get_audio_active_state(const struct bt_audio_codec_c int bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag( const struct bt_audio_codec_cap *codec_cap); +/** + * @brief Set the broadcast audio immediate rendering flag of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_bcast_audio_immediate_rend_flag( + struct bt_audio_codec_cap *codec_cap); + /** @brief Extract extended metadata * * See @ref BT_AUDIO_METADATA_TYPE_EXTENDED for more information about this value. @@ -1143,6 +1655,20 @@ int bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag( int bt_audio_codec_cap_meta_get_extended(const struct bt_audio_codec_cap *codec_cap, const uint8_t **extended_meta); +/** + * @brief Set the extended metadata of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param extended_meta The extended metadata to set. + * @param extended_meta_len The length of @p extended_meta. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_extended(struct bt_audio_codec_cap *codec_cap, + const uint8_t *extended_meta, size_t extended_meta_len); + /** @brief Extract vendor specific metadata * * See @ref BT_AUDIO_METADATA_TYPE_VENDOR for more information about this value. @@ -1156,6 +1682,21 @@ int bt_audio_codec_cap_meta_get_extended(const struct bt_audio_codec_cap *codec_ */ int bt_audio_codec_cap_meta_get_vendor(const struct bt_audio_codec_cap *codec_cap, const uint8_t **vendor_meta); + +/** + * @brief Set the vendor specific metadata of a codec capability metadata. + * + * @param codec_cap The codec capability to set data for. + * @param vendor_meta The vendor specific metadata to set. + * @param vendor_meta_len The length of @p vendor_meta. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the new value could not set or added due to memory + */ +int bt_audio_codec_cap_meta_set_vendor(struct bt_audio_codec_cap *codec_cap, + const uint8_t *vendor_meta, size_t vendor_meta_len); + /** @} */ /* End of bt_audio_codec_cap */ #ifdef __cplusplus diff --git a/include/zephyr/bluetooth/audio/bap.h b/include/zephyr/bluetooth/audio/bap.h index db5737f21520a89..793364435d34b5e 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 */ @@ -406,7 +383,9 @@ struct bt_bap_scan_delegator_cb { * requested for the sync. * @param[in] bis_sync_req Array of bitfields of which BIS indexes * that is requested to sync for each subgroup - * by the Broadcast Assistant. + * by the Broadcast Assistant. A value of 0 + * indicates a request to terminate the BIG + * sync. * * @return 0 in case of accept, or other value to reject. */ @@ -484,6 +463,10 @@ struct bt_bap_stream { /** Stream user data */ void *user_data; +#if defined(CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM) + uint16_t _prev_seq_num; +#endif /* CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM */ + /* Internally used list node */ sys_snode_t _node; }; @@ -591,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); }; /** @@ -1049,6 +1062,35 @@ struct bt_bap_unicast_group_param { * @note This is a recommendation to the controller, which the controller may ignore. */ uint8_t packing; + +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + /** @brief Central to Peripheral flush timeout + * + * The flush timeout in multiples of ISO_Interval for each payload sent + * from the Central to Peripheral. + * + * Value range from @ref BT_ISO_FT_MIN to @ref BT_ISO_FT_MAX + */ + uint8_t c_to_p_ft; + + /** @brief Peripheral to Central flush timeout + * + * The flush timeout in multiples of ISO_Interval for each payload sent + * from the Peripheral to Central. + * + * Value range from @ref BT_ISO_FT_MIN to @ref BT_ISO_FT_MAX. + */ + uint8_t p_to_c_ft; + + /** @brief ISO interval + * + * Time between consecutive CIS anchor points. + * + * Value range from @ref BT_ISO_ISO_INTERVAL_MIN to + * @ref BT_ISO_ISO_INTERVAL_MAX. + */ + uint16_t iso_interval; +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; /** @@ -1316,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); - /* Number of subgroups in the BASE */ - size_t subgroup_count; +/** + * @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); - /* Array of subgroups in the BASE */ - struct bt_bap_base_subgroup subgroups[BROADCAST_SNK_SUBGROUP_CNT]; -}; +/** + * @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); + +/** + * @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); + +/** + * @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 + * + * @param[in] subgroup The subgroup pointer + * @param[out] data Pointer that will point to the resulting codec configuration data * - * The BASE is sent via periodic advertising, and can be decoded into a - * bt_bap_base using this function. + * @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 data The periodic advertising data - * @param base The output struct to put the decode BASE in + * @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_decode_base(struct bt_data *data, struct bt_bap_base *base); +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_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 */ @@ -1439,6 +1604,34 @@ struct bt_bap_broadcast_source_param { * [42 72 6F 61 64 63 61 73 74 20 43 6F 64 65 00 00] */ uint8_t broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE]; + +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + /** @brief Immediate Repetition Count + * + * The number of times the scheduled payloads are transmitted in a + * given event. + * + * Value range from @ref BT_ISO_MIN_IRC to @ref BT_ISO_MAX_IRC. + */ + uint8_t irc; + + /** @brief Pre-transmission offset + * + * Offset used for pre-transmissions. + * + * Value range from @ref BT_ISO_MIN_PTO to @ref BT_ISO_MAX_PTO. + */ + uint8_t pto; + + /** @brief ISO interval + * + * Time between consecutive BIS anchor points. + * + * Value range from @ref BT_ISO_ISO_INTERVAL_MIN to + * @ref BT_ISO_ISO_INTERVAL_MAX. + */ + uint16_t iso_interval; +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; /** @@ -1586,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/bap_lc3_preset.h b/include/zephyr/bluetooth/audio/bap_lc3_preset.h index c8b82054e01bcbe..952451d4b162266 100644 --- a/include/zephyr/bluetooth/audio/bap_lc3_preset.h +++ b/include/zephyr/bluetooth/audio/bap_lc3_preset.h @@ -31,7 +31,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 8_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_8_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_1(_loc, _stream_context), \ @@ -41,7 +41,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 8_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_8_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ @@ -51,7 +51,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 16_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_16_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ @@ -63,7 +63,7 @@ struct bt_bap_lc3_preset { * 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_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_16_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ @@ -73,7 +73,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 24_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_24_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ @@ -85,7 +85,7 @@ struct bt_bap_lc3_preset { * Mandatory to support as unicast server * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_24_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ @@ -95,7 +95,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 32_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_32_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ @@ -105,7 +105,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 32_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_32_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ @@ -115,7 +115,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 441_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_441_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ @@ -126,7 +126,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 441_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_441_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ @@ -137,7 +137,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ @@ -147,7 +147,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ @@ -157,7 +157,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_3_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_3_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ @@ -167,7 +167,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_4_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_4_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ @@ -177,7 +177,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 8_5_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_5_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ @@ -187,7 +187,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_6_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_6_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ @@ -197,7 +197,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 8_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ /* Following presets are for unicast high reliability audio data */ #define BT_BAP_LC3_UNICAST_PRESET_8_1_2(_loc, _stream_context) \ @@ -208,7 +208,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 8_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_8_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ @@ -218,7 +218,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 16_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_16_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ @@ -228,7 +228,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 16_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_16_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ @@ -238,7 +238,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 24_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_24_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ @@ -248,7 +248,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 24_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_24_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ @@ -258,7 +258,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 32_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_32_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ @@ -268,7 +268,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 32_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_32_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ @@ -278,7 +278,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 441_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_441_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ @@ -289,7 +289,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 441_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_441_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ @@ -300,7 +300,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ @@ -310,7 +310,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ @@ -320,7 +320,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_3_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_3_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ @@ -330,7 +330,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_4_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_4_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ @@ -340,7 +340,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_5_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_5_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ @@ -350,7 +350,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Unicast 48_6_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_UNICAST_PRESET_48_6_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ @@ -360,7 +360,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 8_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ /* LC3 Broadcast presets defined by table 6.4 in the BAP v1.0 specification */ #define BT_BAP_LC3_BROADCAST_PRESET_8_1_1(_loc, _stream_context) \ @@ -371,7 +371,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 8_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_8_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ @@ -381,7 +381,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 16_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_16_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ @@ -393,7 +393,7 @@ struct bt_bap_lc3_preset { * Mandatory to support as both broadcast source and sink * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_16_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ @@ -403,7 +403,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 24_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_24_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ @@ -415,7 +415,7 @@ struct bt_bap_lc3_preset { * Mandatory to support as broadcast sink * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_24_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ @@ -425,7 +425,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 32_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_32_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ @@ -435,7 +435,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 32_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_32_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ @@ -445,7 +445,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 441_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_441_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ @@ -456,7 +456,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 441_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_441_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ @@ -467,7 +467,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_1_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_1_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ @@ -477,7 +477,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_2_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_2_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ @@ -487,7 +487,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_3_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_3_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ @@ -497,7 +497,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_4_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_4_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ @@ -507,7 +507,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_5_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_5_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ @@ -517,7 +517,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_6_1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_6_1(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ @@ -527,7 +527,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 8_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ /* Following presets are for broadcast high reliability audio data */ #define BT_BAP_LC3_BROADCAST_PRESET_8_1_2(_loc, _stream_context) \ @@ -538,7 +538,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 8_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_8_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ @@ -548,7 +548,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 16_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_16_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ @@ -560,7 +560,7 @@ struct bt_bap_lc3_preset { * Mandatory to support as both broadcast source and sink * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_16_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ @@ -570,7 +570,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 24_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_24_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ @@ -582,7 +582,7 @@ struct bt_bap_lc3_preset { * Mandatory to support as broadcast sink * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_24_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ @@ -592,7 +592,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 32_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_32_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ @@ -602,7 +602,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 32_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_32_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ @@ -612,7 +612,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 441_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_441_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ @@ -623,7 +623,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 441_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_441_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ @@ -634,7 +634,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_1_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_1_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ @@ -644,7 +644,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_2_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_2_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ @@ -654,7 +654,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_3_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_3_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ @@ -664,7 +664,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_4_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_4_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ @@ -674,7 +674,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_5_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_5_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ @@ -684,7 +684,7 @@ struct bt_bap_lc3_preset { * @brief Helper to declare LC3 Broadcast 48_6_2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_6_2(_loc, _stream_context) \ BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index fd2c455588c0175..a9370251d3d96de 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -131,7 +131,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); @@ -250,7 +253,7 @@ struct bt_cap_unicast_audio_update_param { }; /** - * @brief Register Common Audio Profile callbacks + * @brief Register Common Audio Profile Initiator callbacks * * @param cb The callback structure. Shall remain static. * @@ -314,7 +317,7 @@ int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_gro * 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 @@ -393,13 +396,41 @@ struct bt_cap_initiator_broadcast_create_param { * [42 72 6F 61 64 63 61 73 74 20 43 6F 64 65 00 00] */ uint8_t broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE]; + +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + /** @brief Immediate Repetition Count + * + * The number of times the scheduled payloads are transmitted in a + * given event. + * + * Value range from @ref BT_ISO_MIN_IRC to @ref BT_ISO_MAX_IRC. + */ + uint8_t irc; + + /** @brief Pre-transmission offset + * + * Offset used for pre-transmissions. + * + * Value range from @ref BT_ISO_MIN_PTO to @ref BT_ISO_MAX_PTO. + */ + uint8_t pto; + + /** @brief ISO interval + * + * Time between consecutive BIS anchor points. + * + * Value range from @ref BT_ISO_ISO_INTERVAL_MIN to + * @ref BT_ISO_ISO_INTERVAL_MAX. + */ + uint16_t iso_interval; +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; /** * @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. @@ -465,7 +496,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 @@ -608,6 +639,325 @@ 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); +#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. + * + * This will discover the Common Audio Service (CAS) on the remote device, to + * verify if the remote device supports the Common Audio Profile. + * + * @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_discover() or bt_cap_initiator_unicast_discover() is used. + * + * @param conn Connection to a remote server. + * + * @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_cancel(void); + +struct bt_cap_commander_broadcast_reception_start_member_param { + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member member; + + /** Address of the advertiser. */ + bt_addr_le_t addr; + + /** SID of the advertising set. */ + uint8_t adv_sid; + + /** + * @brief Periodic advertising interval in milliseconds. + * + * BT_BAP_PA_INTERVAL_UNKNOWN if unknown. + */ + uint16_t pa_interval; + + /** 24-bit broadcast ID */ + uint32_t broadcast_id; + + /** + * @brief Pointer to array of subgroups + * + * At least one bit in one of the subgroups bis_sync parameters shall be set. + */ + struct bt_bap_scan_delegator_subgroup *subgroups; + + /** Number of subgroups */ + size_t num_subgroups; +}; + +/** Parameters for starting broadcast reception */ +struct bt_cap_commander_broadcast_reception_start_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The set of devices for this procedure */ + struct bt_cap_commander_broadcast_reception_start_member_param *param; + + /** The number of parameters in @p param */ + size_t count; +}; + +/** + * @brief Starts the reception of broadcast audio on one or more remote Common Audio Profile + * Acceptors + * + * @param param The parameters to start the broadcast audio + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_broadcast_reception_start( + const struct bt_cap_commander_broadcast_reception_start_param *param); + +/** Parameters for stopping broadcast reception */ +struct bt_cap_commander_broadcast_reception_stop_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member *members; + + /** The number of members in @p members */ + size_t count; +}; + +/** + * @brief Stops the reception of broadcast audio on one or more remote Common Audio Profile + * Acceptors + * + * @param param The parameters to stop the broadcast audio + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_broadcast_reception_stop( + const struct bt_cap_commander_broadcast_reception_stop_param *param); + +/** Parameters for changing absolute volume */ +struct bt_cap_commander_change_volume_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member *members; + + /** The number of members in @p members */ + size_t count; + + /** The absolute volume to set */ + uint8_t volume; +}; + +/** + * @brief Change the volume on one or more Common Audio Profile Acceptors + * + * @param param The parameters for the volume change + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_change_volume(const struct bt_cap_commander_change_volume_param *param); + +struct bt_cap_commander_change_volume_offset_member_param { + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member member; + + /** + * @brief The offset to set + * + * Value shall be between @ref BT_VOCS_MIN_OFFSET and @ref BT_VOCS_MAX_OFFSET + */ + int16_t offset; +}; + +/** Parameters for changing volume offset */ +struct bt_cap_commander_change_volume_offset_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The set of devices for this procedure */ + struct bt_cap_commander_change_volume_offset_member_param *param; + + /** The number of parameters in @p param */ + size_t count; +}; + +/** + * @brief Change the volume offset on one or more Common Audio Profile Acceptors + * + * @param param The parameters for the volume offset change + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_change_volume_offset( + const struct bt_cap_commander_change_volume_offset_param *param); + +/** Parameters for changing volume mute state */ +struct bt_cap_commander_change_volume_mute_state_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member *members; + + /** The number of members in @p members */ + size_t count; + + /** + * @brief The volume mute state to set + * + * true to mute, and false to unmute + */ + bool mute; +}; + +/** + * @brief Change the volume mute state on one or more Common Audio Profile Acceptors + * + * @param param The parameters for the volume mute state change + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_change_volume_mute_state( + const struct bt_cap_commander_change_volume_mute_state_param *param); + +/** Parameters for changing microphone mute state */ +struct bt_cap_commander_change_microphone_mute_state_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member *members; + + /** The number of members in @p members */ + size_t count; + + /** + * @brief The microphone mute state to set + * + * true to mute, and false to unmute + */ + bool mute; +}; + +/** + * @brief Change the microphone mute state on one or more Common Audio Profile Acceptors + * + * @param param The parameters for the microphone mute state change + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_change_microphone_mute_state( + const struct bt_cap_commander_change_microphone_mute_state_param *param); + +struct bt_cap_commander_change_microphone_gain_setting_member_param { + /** Coordinated or ad-hoc set member. */ + union bt_cap_set_member member; + + /** @brief The microphone gain setting to set */ + int8_t gain; +}; + +/** Parameters for changing microphone mute state */ +struct bt_cap_commander_change_microphone_gain_setting_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The set of devices for this procedure */ + struct bt_cap_commander_change_microphone_gain_setting_member_param *param; + + /** The number of parameters in @p param */ + size_t count; +}; + +/** + * @brief Change the microphone gain setting on one or more Common Audio Profile Acceptors + * + * @param param The parameters for the microphone gain setting change + * + * @return 0 on success or negative error value on failure. + */ +int bt_cap_commander_change_microphone_gain_setting( + const struct bt_cap_commander_change_microphone_gain_setting_param *param); #ifdef __cplusplus } #endif diff --git a/include/zephyr/bluetooth/audio/gmap.h b/include/zephyr/bluetooth/audio/gmap.h new file mode 100644 index 000000000000000..292fd6eca2bc1bc --- /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 000000000000000..71289da22922285 --- /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/lc3.h b/include/zephyr/bluetooth/audio/lc3.h index 28737fc367f0557..ab42f9fdbdf7160 100644 --- a/include/zephyr/bluetooth/audio/lc3.h +++ b/include/zephyr/bluetooth/audio/lc3.h @@ -67,67 +67,129 @@ enum bt_audio_codec_capability_type { BT_AUDIO_CODEC_LC3_FRAME_COUNT = 0x05, }; -/** - * @brief LC3 8 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_8KHZ BIT(0) -/** - * @brief LC3 11.025 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_11KHZ BIT(1) -/** - * @brief LC3 16 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_16KHZ BIT(2) -/** - * @brief LC3 22.05 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_22KHZ BIT(3) -/** - * @brief LC3 24 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_24KHZ BIT(4) -/** - * @brief LC3 32 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_32KHZ BIT(5) -/** - * @brief LC3 44.1 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_44KHZ BIT(6) -/** - * @brief LC3 48 Khz frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_48KHZ BIT(7) -/** - * @brief LC3 any frequency capability - */ -#define BT_AUDIO_CODEC_LC3_FREQ_ANY \ - (BT_AUDIO_CODEC_LC3_FREQ_8KHZ | BT_AUDIO_CODEC_LC3_FREQ_16KHZ | \ - BT_AUDIO_CODEC_LC3_FREQ_24KHZ | BT_AUDIO_CODEC_LC3_FREQ_32KHZ | \ - BT_AUDIO_CODEC_LC3_FREQ_44KHZ | BT_AUDIO_CODEC_LC3_FREQ_48KHZ) +/** @brief Supported frequencies bitfield */ +enum bt_audio_codec_cap_freq { + /** + * @brief LC3 8 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_8KHZ = BIT(0), + /** + * @brief LC3 11.025 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_11KHZ = BIT(1), + /** + * @brief LC3 16 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_16KHZ = BIT(2), + /** + * @brief LC3 22.05 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_22KHZ = BIT(3), + /** + * @brief LC3 24 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_24KHZ = BIT(4), + /** + * @brief LC3 32 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_32KHZ = BIT(5), + /** + * @brief LC3 44.1 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_44KHZ = BIT(6), + /** + * @brief LC3 48 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_48KHZ = BIT(7), + /** + * @brief LC3 88.2 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_88KHZ = BIT(8), + /** + * @brief LC3 96 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_96KHZ = BIT(9), + /** + * @brief LC3 176.4 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_176KHZ = BIT(10), + /** + * @brief LC3 192 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_192KHZ = BIT(11), + /** + * @brief LC3 384 Khz frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_384KHZ = BIT(12), + /** + * @brief LC3 any frequency capability + */ + BT_AUDIO_CODEC_LC3_FREQ_ANY = + (BT_AUDIO_CODEC_LC3_FREQ_8KHZ | BT_AUDIO_CODEC_LC3_FREQ_11KHZ | + BT_AUDIO_CODEC_LC3_FREQ_16KHZ | BT_AUDIO_CODEC_LC3_FREQ_22KHZ | + BT_AUDIO_CODEC_LC3_FREQ_24KHZ | BT_AUDIO_CODEC_LC3_FREQ_32KHZ | + BT_AUDIO_CODEC_LC3_FREQ_44KHZ | BT_AUDIO_CODEC_LC3_FREQ_48KHZ | + BT_AUDIO_CODEC_LC3_FREQ_88KHZ | BT_AUDIO_CODEC_LC3_FREQ_96KHZ | + BT_AUDIO_CODEC_LC3_FREQ_176KHZ | BT_AUDIO_CODEC_LC3_FREQ_192KHZ | + BT_AUDIO_CODEC_LC3_FREQ_384KHZ), +}; -/** - * @brief LC3 7.5 msec frame duration capability - */ -#define BT_AUDIO_CODEC_LC3_DURATION_7_5 BIT(0) -/** - * @brief LC3 10 msec frame duration capability - */ -#define BT_AUDIO_CODEC_LC3_DURATION_10 BIT(1) -/** - * @brief LC3 any frame duration capability - */ -#define BT_AUDIO_CODEC_LC3_DURATION_ANY \ - (BT_AUDIO_CODEC_LC3_DURATION_7_5 | BT_AUDIO_CODEC_LC3_DURATION_10) -/** - * @brief LC3 7.5 msec preferred frame duration capability - */ -#define BT_AUDIO_CODEC_LC3_DURATION_PREFER_7_5 BIT(4) -/** - * @brief LC3 10 msec preferred frame duration capability - */ -#define BT_AUDIO_CODEC_LC3_DURATION_PREFER_10 BIT(5) +/** @brief Supported frame durations bitfield */ +enum bt_audio_codec_cap_frame_dur { + /** + * @brief LC3 7.5 msec frame duration capability + */ + BT_AUDIO_CODEC_LC3_DURATION_7_5 = BIT(0), + /** + * @brief LC3 10 msec frame duration capability + */ + BT_AUDIO_CODEC_LC3_DURATION_10 = BIT(1), + /** + * @brief LC3 any frame duration capability + */ + BT_AUDIO_CODEC_LC3_DURATION_ANY = + (BT_AUDIO_CODEC_LC3_DURATION_7_5 | BT_AUDIO_CODEC_LC3_DURATION_10), + + /** + * @brief LC3 7.5 msec preferred frame duration capability. + * + * This shall only be set if @ref BT_AUDIO_CODEC_LC3_DURATION_7_5 is also set, and if @ref + * BT_AUDIO_CODEC_LC3_DURATION_PREFER_10 is not set. + */ + BT_AUDIO_CODEC_LC3_DURATION_PREFER_7_5 = BIT(4), + /** + * @brief LC3 10 msec preferred frame duration capability + * + * This shall only be set if @ref BT_AUDIO_CODEC_LC3_DURATION_10 is also set, and if @ref + * BT_AUDIO_CODEC_LC3_DURATION_PREFER_7_5 is not set. + */ + BT_AUDIO_CODEC_LC3_DURATION_PREFER_10 = BIT(5), +}; + +enum bt_audio_codec_cap_chan_count { + /** Supporting 1 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_1 = BIT(0), + /** Supporting 2 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_2 = BIT(1), + /** Supporting 3 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_3 = BIT(2), + /** Supporting 4 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_4 = BIT(3), + /** Supporting 5 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_5 = BIT(4), + /** Supporting 6 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_6 = BIT(5), + /** Supporting 7 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_7 = BIT(6), + /** Supporting 8 channel */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_8 = BIT(7), + /** Supporting all channels */ + BT_AUDIO_CODEC_CAP_CHAN_COUNT_ALL = + (BT_AUDIO_CODEC_CAP_CHAN_COUNT_1 | BT_AUDIO_CODEC_CAP_CHAN_COUNT_2 | + BT_AUDIO_CODEC_CAP_CHAN_COUNT_3 | BT_AUDIO_CODEC_CAP_CHAN_COUNT_4 | + BT_AUDIO_CODEC_CAP_CHAN_COUNT_5 | BT_AUDIO_CODEC_CAP_CHAN_COUNT_6 | + BT_AUDIO_CODEC_CAP_CHAN_COUNT_7 | BT_AUDIO_CODEC_CAP_CHAN_COUNT_8), +}; /** * @brief LC3 minimum supported channel counts @@ -148,7 +210,7 @@ enum bt_audio_codec_capability_type { * BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1, 3) */ #define BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(...) \ - ((uint8_t)((FOR_EACH(BIT, (|), __VA_ARGS__)) >> 1)) + ((enum bt_audio_codec_cap_chan_count)((FOR_EACH(BIT, (|), __VA_ARGS__)) >> 1)) struct BT_AUDIO_CODEC_LC3_frame_len { uint16_t min; @@ -243,19 +305,21 @@ enum bt_audio_codec_config_freq { BT_AUDIO_CODEC_CONFIG_LC3_FREQ_384KHZ = 0x0d, }; -/** - * @brief LC3 7.5 msec Frame Duration configuration - */ -#define BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5 0x00 -/** - * @brief LC3 10 msec Frame Duration configuration - */ -#define BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10 0x01 +enum bt_audio_codec_config_frame_dur { + /** + * @brief LC3 7.5 msec Frame Duration configuration + */ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5 = 0x00, + /** + * @brief LC3 10 msec Frame Duration configuration + */ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10 = 0x01, +}; /** * @brief Helper to declare LC3 codec capability * - * _max_frames_per_sdu value is optional and will be included only if != 1 + * ``_max_frames_per_sdu`` value is optional and will be included only if != 1 */ /* COND_CODE_1 is used to omit an LTV entry in case the _frames_per_sdu is 1. * COND_CODE_1 will evaluate to second argument if the flag parameter(first argument) is 1 @@ -290,8 +354,8 @@ enum bt_audio_codec_config_freq { /** * @brief Helper to declare LC3 codec * - * @param _freq Supported Sampling Frequencies bitfield (see BT_AUDIO_CODEC_LC3_FREQ_*) - * @param _duration Supported Frame Durations bitfield (see BT_AUDIO_CODEC_LC3_DURATION_*) + * @param _freq Supported Sampling Frequencies bitfield (see ``BT_AUDIO_CODEC_LC3_FREQ_*``) + * @param _duration Supported Frame Durations bitfield (see ``BT_AUDIO_CODEC_LC3_DURATION_*``) * @param _chan_count Supported channels (see @ref BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT) * @param _len_min Minimum number of octets supported per codec frame * @param _len_max Maximum number of octets supported per codec frame @@ -309,8 +373,8 @@ enum bt_audio_codec_config_freq { /** * @brief Helper to declare LC3 codec data configuration * - * @param _freq Sampling frequency (BT_AUDIO_CODEC_CONFIG_LC3_FREQ_*) - * @param _duration Frame duration (BT_AUDIO_CODEC_CONFIG_LC3_DURATION_*) + * @param _freq Sampling frequency (``BT_AUDIO_CODEC_CONFIG_LC3_FREQ_*``) + * @param _duration Frame duration (``BT_AUDIO_CODEC_CONFIG_LC3_DURATION_*``) * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _len Octets per frame (16-bit integer) * @param _frames_per_sdu Frames per SDU (8-bit integer). This value is optional and will be @@ -341,12 +405,12 @@ enum bt_audio_codec_config_freq { /** * @brief Helper to declare LC3 codec configuration. * - * @param _freq Sampling frequency (BT_AUDIO_CODEC_CONFIG_LC3_FREQ_*) - * @param _duration Frame duration (BT_AUDIO_CODEC_CONFIG_LC3_DURATION_*) + * @param _freq Sampling frequency (``BT_AUDIO_CODEC_CONFIG_LC3_FREQ_*``) + * @param _duration Frame duration (``BT_AUDIO_CODEC_CONFIG_LC3_DURATION_*``) * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _len Octets per frame (16-bit integer) * @param _frames_per_sdu Frames per SDU (8-bit integer) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG(_freq, _duration, _loc, _len, _frames_per_sdu, _stream_context) \ BT_AUDIO_CODEC_CFG( \ @@ -358,7 +422,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 8.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_8_1(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_8KHZ, \ @@ -368,7 +432,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 8.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_8KHZ, \ @@ -378,7 +442,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 16.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ, \ @@ -388,7 +452,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 16.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ, \ @@ -399,7 +463,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 24.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ, \ @@ -409,7 +473,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 24.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ, \ @@ -419,7 +483,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 32.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ, \ @@ -429,7 +493,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 32.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ, \ @@ -439,7 +503,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 441.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_44KHZ, \ @@ -449,7 +513,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 441.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_44KHZ, \ @@ -459,7 +523,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 48.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ @@ -469,7 +533,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 48.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ @@ -479,7 +543,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 48.3 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ @@ -489,7 +553,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 48.4 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ @@ -499,7 +563,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 48.5 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ @@ -509,7 +573,7 @@ enum bt_audio_codec_config_freq { * @brief Helper to declare LC3 48.6 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) - * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) */ #define BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context) \ BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ diff --git a/include/zephyr/bluetooth/audio/micp.h b/include/zephyr/bluetooth/audio/micp.h index e5cbf523be02340..f33d1d8ebef86aa 100644 --- a/include/zephyr/bluetooth/audio/micp.h +++ b/include/zephyr/bluetooth/audio/micp.h @@ -217,6 +217,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 4b9b7e29a2ae033..6db4d34b0a285bf 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 000000000000000..2ea85564fa7ca3d --- /dev/null +++ b/include/zephyr/bluetooth/audio/pbp.h @@ -0,0 +1,80 @@ +/* + * 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 data Advertising data to be checked + * @param features Public broadcast source features + * @param meta Pointer to copy the metadata present in the advertising data + * + * @return parsed metadata length on success or an appropriate error code + */ +uint8_t 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 961fed483d5a0b0..a902ceaed4d2980 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 * diff --git a/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index c97e1445cb35944..0cfad9b1f6b7898 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/conn.h b/include/zephyr/bluetooth/conn.h index 09b8321d685d184..df79a8967f912dd 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -479,6 +479,42 @@ struct bt_conn_le_tx_power { int8_t max_level; }; + +/** LE Transmit Power Reporting Structure */ +struct bt_conn_le_tx_power_report { + + /** Reason for Transmit power reporting, + * as documented in Core Spec. Version 5.4 Vol. 4, Part E, 7.7.65.33. + */ + uint8_t reason; + + /** Phy of Transmit power reporting. */ + enum bt_conn_le_tx_power_phy phy; + + /** Transmit power level + * - 0xXX - Transmit power level + * + Range: -127 to 20 + * + Units: dBm + * + * - 0x7E - Remote device is not managing power levels on this PHY. + * - 0x7F - Transmit power level is not available + */ + int8_t tx_power_level; + + /** Bit 0: Transmit power level is at minimum level. + * Bit 1: Transmit power level is at maximum level. + */ + uint8_t tx_power_level_flag; + + /** Change in transmit power level + * - 0xXX - Change in transmit power level (positive indicates increased + * power, negative indicates decreased power, zero indicates unchanged) + * Units: dB + * - 0x7F - Change is not available or is out of range. + */ + int8_t delta; +}; + /** @brief Passkey Keypress Notification type * * The numeric values are the same as in the Core specification for Pairing @@ -530,6 +566,41 @@ int bt_conn_get_remote_info(struct bt_conn *conn, int bt_conn_le_get_tx_power_level(struct bt_conn *conn, struct bt_conn_le_tx_power *tx_power_level); +/** @brief Get local enhanced connection transmit power level. + * + * @param conn Connection object. + * @param tx_power Transmit power level descriptor. + * + * @return Zero on success or (negative) error code on failure. + * @retval -ENOBUFS HCI command buffer is not available. + */ +int bt_conn_le_enhanced_get_tx_power_level(struct bt_conn *conn, + struct bt_conn_le_tx_power *tx_power); + +/** @brief Get remote (peer) transmit power level. + * + * @param conn Connection object. + * @param phy PHY information. + * + * @return Zero on success or (negative) error code on failure. + * @retval -ENOBUFS HCI command buffer is not available. + */ +int bt_conn_le_get_remote_tx_power_level(struct bt_conn *conn, + enum bt_conn_le_tx_power_phy phy); + +/** @brief Enable transmit power reporting. + * + * @param conn Connection object. + * @param local_enable Enable/disable reporting for local. + * @param remote_enable Enable/disable reporting for remote. + * + * @return Zero on success or (negative) error code on failure. + * @retval -ENOBUFS HCI command buffer is not available. + */ +int bt_conn_le_set_tx_power_report_enable(struct bt_conn *conn, + bool local_enable, + bool remote_enable); + /** @brief Update the connection parameters. * * If the local device is in the peripheral role then updating the connection @@ -800,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 @@ -817,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 */ @@ -1052,6 +1124,22 @@ struct bt_conn_cb { const struct bt_df_conn_iq_samples_report *iq_report); #endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */ +#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL) + /** @brief LE Read Remote Transmit Power Level procedure has completed or LE + * Transmit Power Reporting event. + * + * This callback notifies the application that either the remote transmit power level + * has been read from the peer or transmit power level has changed for the local or + * remote controller when transmit power reporting is enabled for the respective side + * using @ref bt_conn_le_set_tx_power_report_enable. + * + * @param conn Connection object. + * @param report Transmit power report. + */ + void (*tx_power_report)(struct bt_conn *conn, + const struct bt_conn_le_tx_power_report *report); +#endif /* CONFIG_BT_TRANSMIT_POWER_CONTROL */ + struct bt_conn_cb *_next; }; diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index 7d4ac72495b0824..585387a02aadcba 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -72,7 +72,7 @@ enum bt_gatt_perm { /** @brief Attribute prepare write permission. * - * If set, allows prepare writes with use of BT_GATT_WRITE_FLAG_PREPARE + * If set, allows prepare writes with use of ``BT_GATT_WRITE_FLAG_PREPARE`` * passed to write callback. */ BT_GATT_PERM_PREPARE_WRITE = BIT(6), @@ -140,7 +140,7 @@ struct bt_gatt_attr; * @param offset Offset to start reading from * * @return Number of bytes read, or in case of an error - * BT_GATT_ERR() with a specific BT_ATT_ERR_* error code. + * ``BT_GATT_ERR()`` with a specific ``BT_ATT_ERR_*`` error code. */ typedef ssize_t (*bt_gatt_attr_read_func_t)(struct bt_conn *conn, const struct bt_gatt_attr *attr, @@ -155,10 +155,10 @@ typedef ssize_t (*bt_gatt_attr_read_func_t)(struct bt_conn *conn, * @param buf Buffer with the data to write * @param len Number of bytes in the buffer * @param offset Offset to start writing from - * @param flags Flags (BT_GATT_WRITE_FLAG_*) + * @param flags Flags (``BT_GATT_WRITE_FLAG_*``) * * @return Number of bytes written, or in case of an error - * BT_GATT_ERR() with a specific BT_ATT_ERR_* error code. + * ``BT_GATT_ERR()`` with a specific ``BT_ATT_ERR_*`` error code. */ typedef ssize_t (*bt_gatt_attr_write_func_t)(struct bt_conn *conn, const struct bt_gatt_attr *attr, @@ -178,7 +178,7 @@ struct bt_gatt_attr { uint16_t handle; /** @brief Attribute permissions. * - * Will be 0 if returned from bt_gatt_discover(). + * Will be 0 if returned from ``bt_gatt_discover()``. */ uint16_t perm; }; @@ -235,6 +235,37 @@ struct bt_gatt_cb { sys_snode_t node; }; +/** @brief GATT authorization callback structure. */ +struct bt_gatt_authorization_cb { + /** @brief Authorize the GATT read operation. + * + * This callback allows the application to authorize the GATT + * read operation for the attribute that is being read. + * + * @param conn Connection object. + * @param attr The attribute that is being read. + * + * @retval true Authorize the operation and allow it to execute. + * @retval false Reject the operation and prevent it from executing. + */ + bool (*read_operation_authorize)(struct bt_conn *conn, + const struct bt_gatt_attr *attr); + + /** @brief Authorize the GATT write operation. + * + * This callback allows the application to authorize the GATT + * write operation for the attribute that is being written. + * + * @param conn Connection object. + * @param attr The attribute that is being written. + * + * @retval true Authorize the operation and allow it to execute. + * @retval false Reject the operation and prevent it from executing. + */ + bool (*write_operation_authorize)(struct bt_conn *conn, + const struct bt_gatt_attr *attr); +}; + /** Characteristic Properties Bit field values */ /** @@ -370,17 +401,38 @@ struct bt_gatt_cpf { /** @brief Register GATT callbacks. * - * Register callbacks to monitor the state of GATT. + * Register callbacks to monitor the state of GATT. The callback struct + * must remain valid for the remainder of the program. * * @param cb Callback struct. */ void bt_gatt_cb_register(struct bt_gatt_cb *cb); +/** @brief Register GATT authorization callbacks. + * + * Register callbacks to perform application-specific authorization of GATT + * operations on all registered GATT attributes. The callback structure must + * remain valid throughout the entire duration of the Bluetooth subsys + * activity. + * + * The @kconfig{CONFIG_BT_GATT_AUTHORIZATION_CUSTOM} Kconfig must be enabled + * to make this API functional. + * + * This API allows the user to register only one callback structure + * concurrently. Passing NULL unregisters the previous set of callbacks + * and makes it possible to register a new one. + * + * @param cb Callback struct. + * + * @return Zero on success or negative error code otherwise + */ +int bt_gatt_authorization_cb_register(const struct bt_gatt_authorization_cb *cb); + /** @brief Register GATT service. * * Register GATT service. Applications can make use of - * macros such as BT_GATT_PRIMARY_SERVICE, BT_GATT_CHARACTERISTIC, - * BT_GATT_DESCRIPTOR, etc. + * macros such as ``BT_GATT_PRIMARY_SERVICE``, ``BT_GATT_CHARACTERISTIC``, + * ``BT_GATT_DESCRIPTOR``, etc. * * When using @kconfig{CONFIG_BT_SETTINGS} then all services that should have * bond configuration loaded, i.e. CCC values, must be registered before @@ -400,7 +452,7 @@ void bt_gatt_cb_register(struct bt_gatt_cb *cb); * @param svc Service containing the available attributes * * @return 0 in case of success or negative value in case of error. - * @return -EAGAIN if `bt_init()` has been called but `settings_load()` hasn't yet. + * @return -EAGAIN if ``bt_init()`` has been called but ``settings_load()`` hasn't yet. */ int bt_gatt_service_register(struct bt_gatt_service *svc); @@ -432,8 +484,8 @@ enum { * @param handle Attribute handle found. * @param user_data Data given. * - * @return BT_GATT_ITER_CONTINUE if should continue to the next attribute. - * @return BT_GATT_ITER_STOP to stop. + * @return ``BT_GATT_ITER_CONTINUE`` if should continue to the next attribute. + * @return ``BT_GATT_ITER_STOP`` to stop. */ typedef uint8_t (*bt_gatt_attr_func_t)(const struct bt_gatt_attr *attr, uint16_t handle, @@ -488,7 +540,7 @@ struct bt_gatt_attr *bt_gatt_attr_next(const struct bt_gatt_attr *attr); * * Find the attribute with the matching UUID. * To limit the search to a service set the attr to the service attributes and - * the attr_count to the service attribute count . + * the ``attr_count`` to the service attribute count . * * @param attr Pointer to an attribute that serves as the starting point * for the search of a match for the UUID. @@ -515,7 +567,7 @@ uint16_t bt_gatt_attr_get_handle(const struct bt_gatt_attr *attr); * * @param attr A Characteristic Attribute. * - * @note The user_data of the attribute must of type @ref bt_gatt_chrc. + * @note The ``user_data`` of the attribute must of type @ref bt_gatt_chrc. * * @return the handle of the corresponding Characteristic Value. The value will * be zero (the invalid handle) if @p attr was not a characteristic @@ -546,7 +598,7 @@ ssize_t bt_gatt_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, * * Read service attribute value from local database storing the result into * buffer after encoding it. - * @note Only use this with attributes which user_data is a bt_uuid. + * @note Only use this with attributes which ``user_data`` is a ``bt_uuid``. * * @param conn Connection object. * @param attr Attribute to read. @@ -583,7 +635,7 @@ ssize_t bt_gatt_attr_read_service(struct bt_conn *conn, * * Helper macro to statically define service structure array. Each element * of the array is linked to the service attribute array which is also - * defined in this scope using _attrs_def macro. + * defined in this scope using ``_attrs_def`` macro. * * @param _name Name of service structure array. * @param _instances Array of instances to pass as user context to the @@ -625,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. @@ -639,13 +691,13 @@ 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. * * Read include service attribute value from local database storing the result * into buffer after encoding it. - * @note Only use this with attributes which user_data is a bt_gatt_include. + * @note Only use this with attributes which user_data is a ``bt_gatt_include``. * * @param conn Connection object. * @param attr Attribute to read. @@ -675,7 +727,7 @@ ssize_t bt_gatt_attr_read_included(struct bt_conn *conn, * * Read characteristic attribute value from local database storing the result * into buffer after encoding it. - * @note Only use this with attributes which user_data is a bt_gatt_chrc. + * @note Only use this with attributes which ``user_data`` is a ``bt_gatt_chrc``. * * @param conn Connection object. * @param attr Attribute to read. @@ -705,7 +757,7 @@ ssize_t bt_gatt_attr_read_chrc(struct bt_conn *conn, * * @param _uuid Characteristic attribute uuid. * @param _props Characteristic attribute properties, - * a bitmap of BT_GATT_CHRC_* macros. + * a bitmap of ``BT_GATT_CHRC_*`` macros. * @param _perm Characteristic Attribute access permissions, * a bitmap of @ref bt_gatt_perm values. * @param _read Characteristic Attribute read callback @@ -1335,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. */ @@ -1501,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); @@ -1572,6 +1624,8 @@ struct bt_gatt_read_params { #if defined(CONFIG_BT_EATT) enum bt_att_chan_opt chan_opt; #endif /* CONFIG_BT_EATT */ + /** Internal */ + uint16_t _att_mtu; }; /** @brief Read Attribute Value by handle @@ -1582,9 +1636,21 @@ struct bt_gatt_read_params { * depending on how many instances of given the UUID exists with the * start_handle being updated for each instance. * - * If an instance does contain a long value which cannot be read entirely the - * caller will need to read the remaining data separately using the handle and - * offset. + * To perform a GATT Long Read procedure, start with a Characteristic Value + * Read (by setting @c offset @c 0 and @c handle_count @c 1) and then return + * @ref BT_GATT_ITER_CONTINUE from the callback. This is equivalent to calling + * @ref bt_gatt_read again, but with the correct offset to continue the read. + * This may be repeated until the procedure is complete, which is signaled by + * the callback being called with @p data set to @c NULL. + * + * Note that returning @ref BT_GATT_ITER_CONTINUE is really starting a new ATT + * operation, so this can fail to allocate resources. However, all API errors + * are reported as if the server returned @ref BT_ATT_ERR_UNLIKELY. There is no + * way to distinguish between this condition and a @ref BT_ATT_ERR_UNLIKELY + * response from the server itself. + * + * Note that the effect of returning @ref BT_GATT_ITER_CONTINUE from the + * callback varies depending on the type of read operation. * * The Response comes in callback @p params->func. The callback is run from * the context specified by 'config BT_RECV_CONTEXT'. @@ -1602,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); @@ -1655,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); @@ -1692,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, @@ -1718,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, @@ -1880,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); @@ -1926,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/hci.h b/include/zephyr/bluetooth/hci.h index 8dd7434e4458a71..258f86519b61a91 100644 --- a/include/zephyr/bluetooth/hci.h +++ b/include/zephyr/bluetooth/hci.h @@ -97,6 +97,19 @@ int bt_hci_get_conn_handle(const struct bt_conn *conn, uint16_t *conn_handle); */ int bt_hci_get_adv_handle(const struct bt_le_ext_adv *adv, uint8_t *adv_handle); +/** @brief Obtain the version string given a core version number. + * + * The core version of a controller can be obtained by issuing + * the HCI Read Local Version Information command. + * + * See also the defines prefixed with BT_HCI_VERSION_. + * + * @param core_version The core version. + * + * @return Version string corresponding to the core version number. + */ +const char *bt_hci_get_ver_str(uint8_t core_version); + /** @typedef bt_hci_vnd_evt_cb_t * @brief Callback type for vendor handling of HCI Vendor-Specific Events. * diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index 4d637bbe4e28052..f1cb92f372c553b 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -571,6 +571,35 @@ struct bt_hci_rp_read_tx_power_level { int8_t tx_power_level; } __packed; +#define BT_HCI_LE_TX_POWER_PHY_1M 0x01 +#define BT_HCI_LE_TX_POWER_PHY_2M 0x02 +#define BT_HCI_LE_TX_POWER_PHY_CODED_S8 0x03 +#define BT_HCI_LE_TX_POWER_PHY_CODED_S2 0x04 +#define BT_HCI_OP_LE_ENH_READ_TX_POWER_LEVEL BT_OP(BT_OGF_LE, 0x0076) +struct bt_hci_cp_le_read_tx_power_level { + uint16_t handle; + uint8_t phy; +} __packed; + +struct bt_hci_rp_le_read_tx_power_level { + uint8_t status; + uint16_t handle; + uint8_t phy; + int8_t current_tx_power_level; + int8_t max_tx_power_level; +} __packed; + +#define BT_HCI_OP_LE_READ_REMOTE_TX_POWER_LEVEL BT_OP(BT_OGF_LE, 0x0077) + +#define BT_HCI_LE_TX_POWER_REPORT_DISABLE 0x00 +#define BT_HCI_LE_TX_POWER_REPORT_ENABLE 0x01 +#define BT_HCI_OP_LE_SET_TX_POWER_REPORT_ENABLE BT_OP(BT_OGF_LE, 0x007A) +struct bt_hci_cp_le_set_tx_power_report_enable { + uint16_t handle; + uint8_t local_enable; + uint8_t remote_enable; +} __packed; + #define BT_HCI_CTL_TO_HOST_FLOW_DISABLE 0x00 #define BT_HCI_CTL_TO_HOST_FLOW_ENABLE 0x01 #define BT_HCI_OP_SET_CTL_TO_HOST_FLOW BT_OP(BT_OGF_BASEBAND, 0x0031) @@ -2905,6 +2934,26 @@ struct bt_hci_evt_le_req_peer_sca_complete { uint8_t sca; } __packed; +/** Reason for Transmit power reporting. + */ +/* Local Transmit power changed. */ +#define BT_HCI_LE_TX_POWER_REPORT_REASON_LOCAL_CHANGED 0x00 +/* Remote Transmit power changed. */ +#define BT_HCI_LE_TX_POWER_REPORT_REASON_REMOTE_CHANGED 0x01 +/* HCI_LE_Read_Remote_Transmit_Power_Level command completed. */ +#define BT_HCI_LE_TX_POWER_REPORT_REASON_READ_REMOTE_COMPLETED 0x02 + +#define BT_HCI_EVT_LE_TRANSMIT_POWER_REPORT 0x21 +struct bt_hci_evt_le_transmit_power_report { + uint8_t status; + uint16_t handle; + uint8_t reason; + uint8_t phy; + int8_t tx_power_level; + uint8_t tx_power_level_flag; + int8_t delta; +} __packed; + #define BT_HCI_EVT_LE_BIGINFO_ADV_REPORT 0x22 struct bt_hci_evt_le_biginfo_adv_report { uint16_t sync_handle; diff --git a/include/zephyr/bluetooth/iso.h b/include/zephyr/bluetooth/iso.h index 05b9b0fbed9b8aa..e280951eda75364 100644 --- a/include/zephyr/bluetooth/iso.h +++ b/include/zephyr/bluetooth/iso.h @@ -200,7 +200,7 @@ struct bt_iso_chan_io_qos { */ struct bt_iso_chan_path *path; -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) /** @brief Maximum PDU size * * Maximum size, in octets, of the payload from link layer to link @@ -219,7 +219,7 @@ struct bt_iso_chan_io_qos { * Value range @ref BT_ISO_BN_MIN to @ref BT_ISO_BN_MAX. */ uint8_t burst_number; -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; /** @brief ISO Channel QoS structure. */ @@ -241,7 +241,7 @@ struct bt_iso_chan_qos { */ struct bt_iso_chan_io_qos *tx; -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) /** @brief Number of subevents * * Maximum number of subevents in each CIS or BIS event. @@ -249,7 +249,7 @@ struct bt_iso_chan_qos { * Value range @ref BT_ISO_NSE_MIN to @ref BT_ISO_NSE_MAX. */ uint8_t num_subevents; -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; /** @brief ISO Channel Data Path structure. */ @@ -335,19 +335,33 @@ struct bt_iso_cig_param { */ uint8_t num_cis; - /** @brief Channel interval in us. + /** @brief Channel interval in us for SDUs sent from Central to Peripheral. * * Value range BT_ISO_SDU_INTERVAL_MIN - BT_ISO_SDU_INTERVAL_MAX. */ - uint32_t interval; + uint32_t c_to_p_interval; - /** @brief Channel Latency in ms. + /** @brief Channel interval in us for SDUs sent from Peripheral to Central. + * + * Value range BT_ISO_SDU_INTERVAL_MIN - BT_ISO_SDU_INTERVAL_MAX. + */ + uint32_t p_to_c_interval; + + /** @brief Channel Latency in ms for SDUs sent from Central to Peripheral * * Value range BT_ISO_LATENCY_MIN - BT_ISO_LATENCY_MAX. * * This value is ignored if any advanced ISO parameters are set. */ - uint16_t latency; + uint16_t c_to_p_latency; + + /** @brief Channel Latency in ms for SDUs sent from Peripheral to Central + * + * Value range BT_ISO_LATENCY_MIN - BT_ISO_LATENCY_MAX. + * + * This value is ignored if any advanced ISO parameters are set. + */ + uint16_t p_to_c_latency; /** @brief Channel peripherals sleep clock accuracy Only for CIS * @@ -371,7 +385,7 @@ struct bt_iso_cig_param { */ uint8_t framing; -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) /** @brief Central to Peripheral flush timeout * * The flush timeout in multiples of ISO_Interval for each payload sent @@ -398,8 +412,7 @@ struct bt_iso_cig_param { * @ref BT_ISO_ISO_INTERVAL_MAX. */ uint16_t iso_interval; -#endif /* CONFIG_BT_ISO_ADVANCED */ - +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; /** ISO connection parameters structure */ @@ -470,7 +483,7 @@ struct bt_iso_big_create_param { */ uint8_t bcode[BT_ISO_BROADCAST_CODE_SIZE]; -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) /** @brief Immediate Repetition Count * * The number of times the scheduled payloads are transmitted in a @@ -496,7 +509,7 @@ struct bt_iso_big_create_param { * @ref BT_ISO_ISO_INTERVAL_MAX. */ uint16_t iso_interval; -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; /** @brief Broadcast Isochronous Group (BIG) Sync Parameters */ @@ -650,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 34d1f2dc2ab08ff..dfd01dcc455a259 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.h b/include/zephyr/bluetooth/mesh.h index a4ef70dc6ded899..fc84814fa4421fb 100644 --- a/include/zephyr/bluetooth/mesh.h +++ b/include/zephyr/bluetooth/mesh.h @@ -1,5 +1,5 @@ /** @file - * @brief Bluetooth mesh Profile APIs. + * @brief Bluetooth Mesh Profile APIs. */ /* diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index 2db8a55e986f6d0..a236ede525d84ce 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -30,6 +30,9 @@ #define BT_MESH_MODEL_UUIDS_UNASSIGNED() #endif +#define BT_MESH_MODEL_RUNTIME_INIT(_user_data) \ + .rt = &(struct bt_mesh_model_rt_ctx){ .user_data = (_user_data) }, + /** * @brief Access layer * @defgroup bt_mesh_access Access layer @@ -137,19 +140,23 @@ extern "C" { * @param _mods Array of models. * @param _vnd_mods Array of vendor models. */ -#define BT_MESH_ELEM(_loc, _mods, _vnd_mods) \ -{ \ - .loc = (_loc), \ - .model_count = ARRAY_SIZE(_mods), \ - .vnd_model_count = ARRAY_SIZE(_vnd_mods), \ - .models = (_mods), \ - .vnd_models = (_vnd_mods), \ +#define BT_MESH_ELEM(_loc, _mods, _vnd_mods) \ +{ \ + .rt = &(struct bt_mesh_elem_rt_ctx) { 0 }, \ + .loc = (_loc), \ + .model_count = ARRAY_SIZE(_mods), \ + .vnd_model_count = ARRAY_SIZE(_vnd_mods), \ + .models = (_mods), \ + .vnd_models = (_vnd_mods), \ } /** Abstraction that describes a Mesh Element */ struct bt_mesh_elem { - /** Unicast Address. Set at runtime during provisioning. */ - uint16_t addr; + /** Mesh Element runtime information */ + struct bt_mesh_elem_rt_ctx { + /** Unicast Address. Set at runtime during provisioning. */ + uint16_t addr; + } * const rt; /** Location Descriptor (GATT Bluetooth Namespace Descriptors) */ const uint16_t loc; @@ -159,9 +166,9 @@ struct bt_mesh_elem { const uint8_t vnd_model_count; /** The list of SIG models in this element */ - struct bt_mesh_model * const models; + const struct bt_mesh_model * const models; /** The list of vendor models in this element */ - struct bt_mesh_model * const vnd_models; + const struct bt_mesh_model * const vnd_models; }; /** @@ -370,7 +377,7 @@ struct bt_mesh_model_op { * * @return Zero on success or (negative) error code otherwise. */ - int (*const func)(struct bt_mesh_model *model, + int (*const func)(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); }; @@ -403,7 +410,7 @@ struct bt_mesh_model_op { * This macro uses compound literal feature of C99 standard and thus is available only from C, * not C++. */ -#define BT_MESH_MODEL_NONE ((struct bt_mesh_model []){}) +#define BT_MESH_MODEL_NONE ((const struct bt_mesh_model []){}) /** * @brief Composition data SIG model entry with callback functions @@ -425,6 +432,7 @@ struct bt_mesh_model_op { #define BT_MESH_MODEL_CNT_CB(_id, _op, _pub, _user_data, _keys, _grps, _cb) \ { \ .id = (_id), \ + BT_MESH_MODEL_RUNTIME_INIT(_user_data) \ .pub = _pub, \ .keys = (uint16_t []) BT_MESH_MODEL_KEYS_UNUSED(_keys), \ .keys_cnt = _keys, \ @@ -433,7 +441,6 @@ struct bt_mesh_model_op { BT_MESH_MODEL_UUIDS_UNASSIGNED() \ .op = _op, \ .cb = _cb, \ - .user_data = _user_data, \ } /** @@ -458,6 +465,7 @@ struct bt_mesh_model_op { { \ .vnd.company = (_company), \ .vnd.id = (_id), \ + BT_MESH_MODEL_RUNTIME_INIT(_user_data) \ .op = _op, \ .pub = _pub, \ .keys = (uint16_t []) BT_MESH_MODEL_KEYS_UNUSED(_keys), \ @@ -465,7 +473,6 @@ struct bt_mesh_model_op { .groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps), \ .groups_cnt = _grps, \ BT_MESH_MODEL_UUIDS_UNASSIGNED() \ - .user_data = _user_data, \ .cb = _cb, \ } @@ -505,6 +512,7 @@ struct bt_mesh_model_op { #define BT_MESH_MODEL_METADATA_CB(_id, _op, _pub, _user_data, _cb, _metadata) \ { \ .id = (_id), \ + BT_MESH_MODEL_RUNTIME_INIT(_user_data) \ .pub = _pub, \ .keys = (uint16_t []) BT_MESH_MODEL_KEYS_UNUSED(CONFIG_BT_MESH_MODEL_KEY_COUNT), \ .keys_cnt = CONFIG_BT_MESH_MODEL_KEY_COUNT, \ @@ -513,7 +521,6 @@ struct bt_mesh_model_op { BT_MESH_MODEL_UUIDS_UNASSIGNED() \ .op = _op, \ .cb = _cb, \ - .user_data = _user_data, \ .metadata = _metadata, \ } #else @@ -559,6 +566,7 @@ struct bt_mesh_model_op { { \ .vnd.company = (_company), \ .vnd.id = (_id), \ + BT_MESH_MODEL_RUNTIME_INIT(_user_data) \ .op = _op, \ .pub = _pub, \ .keys = (uint16_t []) BT_MESH_MODEL_KEYS_UNUSED(CONFIG_BT_MESH_MODEL_KEY_COUNT), \ @@ -566,7 +574,6 @@ struct bt_mesh_model_op { .groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(CONFIG_BT_MESH_MODEL_GROUP_COUNT), \ .groups_cnt = CONFIG_BT_MESH_MODEL_GROUP_COUNT, \ BT_MESH_MODEL_UUIDS_UNASSIGNED() \ - .user_data = _user_data, \ .cb = _cb, \ .metadata = _metadata, \ } @@ -690,7 +697,7 @@ struct bt_mesh_model_op { */ struct bt_mesh_model_pub { /** The model the context belongs to. Initialized by the stack. */ - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; uint16_t addr; /**< Publish Address. */ const uint8_t *uuid; /**< Label UUID if Publish Address is Virtual Address. */ @@ -706,6 +713,8 @@ struct bt_mesh_model_pub { uint8_t period_div:4, /**< Divisor for the Period. */ count:4; /**< Transmissions left. */ + uint8_t delayable:1; /**< Use random delay for publishing. */ + uint32_t period_start; /**< Start of the current period. */ /** @brief Publication buffer, containing the publication message. @@ -735,7 +744,7 @@ struct bt_mesh_model_pub { * * @return Zero on success or (negative) error code otherwise. */ - int (*update)(struct bt_mesh_model *mod); + int (*update)(const struct bt_mesh_model *mod); /** Publish Period Timer. Only for stack-internal use. */ struct k_work_delayable timer; @@ -805,7 +814,7 @@ struct bt_mesh_model_cb { * * @return 0 on success, error otherwise. */ - int (*const settings_set)(struct bt_mesh_model *model, + int (*const settings_set)(const struct bt_mesh_model *model, const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg); @@ -821,7 +830,7 @@ struct bt_mesh_model_cb { * * @return 0 on success, error otherwise. */ - int (*const start)(struct bt_mesh_model *model); + int (*const start)(const struct bt_mesh_model *model); /** @brief Model init callback. * @@ -835,7 +844,7 @@ struct bt_mesh_model_cb { * * @return 0 on success, error otherwise. */ - int (*const init)(struct bt_mesh_model *model); + int (*const init)(const struct bt_mesh_model *model); /** @brief Model reset callback. * @@ -847,7 +856,7 @@ struct bt_mesh_model_cb { * * @param model Model this callback belongs to. */ - void (*const reset)(struct bt_mesh_model *model); + void (*const reset)(const struct bt_mesh_model *model); /** @brief Callback used to store pending model's user data. * @@ -857,7 +866,7 @@ struct bt_mesh_model_cb { * * @param model Model this callback belongs to. */ - void (*const pending_store)(struct bt_mesh_model *model); + void (*const pending_store)(const struct bt_mesh_model *model); }; /** Vendor model ID */ @@ -877,10 +886,19 @@ struct bt_mesh_model { const struct bt_mesh_mod_id_vnd vnd; }; - /* Internal information, mainly for persistent storage */ - uint8_t elem_idx; /* Belongs to Nth element */ - uint8_t mod_idx; /* Is the Nth model in the element */ - uint16_t flags; /* Model flags for internal bookkeeping */ + /* Model runtime information */ + struct bt_mesh_model_rt_ctx { + uint8_t elem_idx; /* Belongs to Nth element */ + uint8_t mod_idx; /* Is the Nth model in the element */ + uint16_t flags; /* Model flags for internal bookkeeping */ + +#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS + /* Pointer to the next model in a model extension list. */ + const struct bt_mesh_model *next; +#endif + /** Model-specific user data */ + void *user_data; + } * const rt; /** Model Publication */ struct bt_mesh_model_pub * const pub; @@ -904,18 +922,10 @@ struct bt_mesh_model { /** Model callback structure. */ const struct bt_mesh_model_cb * const cb; -#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS - /* Pointer to the next model in a model extension list. */ - struct bt_mesh_model *next; -#endif - #if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV) || defined(__DOXYGEN__) /* Pointer to the array of model metadata entries. */ struct bt_mesh_models_metadata_entry **metadata; #endif - - /** Model-specific user data */ - void *user_data; }; /** Callback structure for monitoring model message sending */ @@ -952,7 +962,7 @@ struct bt_mesh_send_cb { * * @return 0 on success, or (negative) error code on failure. */ -int bt_mesh_model_send(struct bt_mesh_model *model, +int bt_mesh_model_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, @@ -971,7 +981,7 @@ int bt_mesh_model_send(struct bt_mesh_model *model, * * @return 0 on success, or (negative) error code on failure. */ -int bt_mesh_model_publish(struct bt_mesh_model *model); +int bt_mesh_model_publish(const struct bt_mesh_model *model); /** @brief Check if a message is being retransmitted. * @@ -992,7 +1002,7 @@ static inline bool bt_mesh_model_pub_is_retransmission(const struct bt_mesh_mode * * @return Pointer to the element that the given model belongs to. */ -struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod); +const struct bt_mesh_elem *bt_mesh_model_elem(const struct bt_mesh_model *mod); /** @brief Find a SIG model. * @@ -1002,8 +1012,8 @@ struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod); * @return A pointer to the Mesh model matching the given parameters, or NULL * if no SIG model with the given ID exists in the given element. */ -struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, - uint16_t id); +const struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, + uint16_t id); /** @brief Find a vendor model. * @@ -1014,8 +1024,8 @@ struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, * @return A pointer to the Mesh model matching the given parameters, or NULL * if no vendor model with the given ID exists in the given element. */ -struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, - uint16_t company, uint16_t id); +const struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, + uint16_t company, uint16_t id); /** @brief Get whether the model is in the primary element of the device. * @@ -1025,7 +1035,7 @@ struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, */ static inline bool bt_mesh_model_in_primary(const struct bt_mesh_model *mod) { - return (mod->elem_idx == 0); + return (mod->rt->elem_idx == 0); } /** @brief Immediately store the model's user data in persistent storage. @@ -1039,7 +1049,7 @@ static inline bool bt_mesh_model_in_primary(const struct bt_mesh_model *mod) * * @return 0 on success, or (negative) error code on failure. */ -int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, +int bt_mesh_model_data_store(const struct bt_mesh_model *mod, bool vnd, const char *name, const void *data, size_t data_len); @@ -1054,7 +1064,7 @@ int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, * * @param mod Mesh model. */ -void bt_mesh_model_data_store_schedule(struct bt_mesh_model *mod); +void bt_mesh_model_data_store_schedule(const struct bt_mesh_model *mod); /** @brief Let a model extend another. * @@ -1070,13 +1080,17 @@ void bt_mesh_model_data_store_schedule(struct bt_mesh_model *mod); * extension list and element, giving the models extended subscription list * capacity. * + * If @kconfig{CONFIG_BT_MESH_COMP_PAGE_1} is enabled, it is not allowed to call + * this function before the @ref bt_mesh_model_cb.init callback is called + * for both models, except if it is called as part of the final callback. + * * @param extending_mod Mesh model that is extending the base model. * @param base_mod The model being extended. * * @retval 0 Successfully extended the base_mod model. */ -int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, - struct bt_mesh_model *base_mod); +int bt_mesh_model_extend(const struct bt_mesh_model *extending_mod, + const struct bt_mesh_model *base_mod); /** @brief Let a model correspond to another. * @@ -1098,8 +1112,8 @@ int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, * @retval -ENOTSUP Composition Data Page 1 is not supported. */ -int bt_mesh_model_correspond(struct bt_mesh_model *corresponding_mod, - struct bt_mesh_model *base_mod); +int bt_mesh_model_correspond(const struct bt_mesh_model *corresponding_mod, + const struct bt_mesh_model *base_mod); /** @brief Check if model is extended by another model. * @@ -1107,7 +1121,7 @@ int bt_mesh_model_correspond(struct bt_mesh_model *corresponding_mod, * * @retval true If model is extended by another model, otherwise false */ -bool bt_mesh_model_is_extended(struct bt_mesh_model *model); +bool bt_mesh_model_is_extended(const struct bt_mesh_model *model); /** @brief Indicate that the composition data will change on next bootup. * @@ -1134,7 +1148,7 @@ struct bt_mesh_comp { uint16_t vid; /**< Version ID */ size_t elem_count; /**< The number of elements in this device. */ - struct bt_mesh_elem *elem; /**< List of elements. */ + const struct bt_mesh_elem *elem; /**< List of elements. */ }; /** Composition data page 2 record. */ diff --git a/include/zephyr/bluetooth/mesh/blob_cli.h b/include/zephyr/bluetooth/mesh/blob_cli.h index 3bf65beae39f74b..9b591cfdd350592 100644 --- a/include/zephyr/bluetooth/mesh/blob_cli.h +++ b/include/zephyr/bluetooth/mesh/blob_cli.h @@ -265,10 +265,10 @@ struct blob_cli_broadcast_ctx { void (*send)(struct bt_mesh_blob_cli *cli, uint16_t dst); /** Called after every @ref blob_cli_broadcast_ctx::send callback. */ void (*send_complete)(struct bt_mesh_blob_cli *cli, uint16_t dst); - /** If @ref blob_cli_broadcast_ctx::acked is true, called after all Target nodes - * have confirmed reception by @ref blob_cli_broadcast_rsp. Otherwise, called - * after transmission has been completed. - */ + /** If @ref blob_cli_broadcast_ctx::acked is true, called after all Target nodes + * have confirmed reception by @ref blob_cli_broadcast_rsp. Otherwise, called + * after transmission has been completed. + */ void (*next)(struct bt_mesh_blob_cli *cli); /** If true, every transmission needs to be confirmed by @ref blob_cli_broadcast_rsp before * @ref blob_cli_broadcast_ctx::next is called. @@ -291,7 +291,7 @@ struct bt_mesh_blob_cli { const struct bt_mesh_blob_cli_cb *cb; /* Runtime state */ - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct { struct bt_mesh_blob_target *target; diff --git a/include/zephyr/bluetooth/mesh/blob_srv.h b/include/zephyr/bluetooth/mesh/blob_srv.h index 57237f1d4bb860d..92c809bd6b5b931 100644 --- a/include/zephyr/bluetooth/mesh/blob_srv.h +++ b/include/zephyr/bluetooth/mesh/blob_srv.h @@ -108,7 +108,7 @@ struct bt_mesh_blob_srv_cb { /** @brief Transfer recovery callback. * - * Called when the Bluetooth mesh subsystem is started if the device is rebooted + * Called when the Bluetooth Mesh subsystem is started if the device is rebooted * in the middle of a transfer. * * Transfers will not be resumed after a reboot if this callback is not @@ -136,7 +136,7 @@ struct bt_mesh_blob_srv { const struct bt_mesh_blob_io *io; struct k_work_delayable rx_timeout; struct bt_mesh_blob_block block; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; enum bt_mesh_blob_xfer_phase phase; struct bt_mesh_blob_srv_state { diff --git a/include/zephyr/bluetooth/mesh/cdb.h b/include/zephyr/bluetooth/mesh/cdb.h index 800ae07edc499d7..8ea35ec2e55aaec 100644 --- a/include/zephyr/bluetooth/mesh/cdb.h +++ b/include/zephyr/bluetooth/mesh/cdb.h @@ -231,7 +231,7 @@ enum { * or BT_MESH_CDB_ITER_STOP to stop. */ typedef uint8_t (*bt_mesh_cdb_node_func_t)(struct bt_mesh_cdb_node *node, - void *user_data); + void *user_data); /** @brief Node iterator. * diff --git a/include/zephyr/bluetooth/mesh/cfg.h b/include/zephyr/bluetooth/mesh/cfg.h index 7d1ca4e868f5e67..9bfd067da9b817c 100644 --- a/include/zephyr/bluetooth/mesh/cfg.h +++ b/include/zephyr/bluetooth/mesh/cfg.h @@ -26,7 +26,7 @@ extern "C" { #endif -/** Bluetooth mesh feature states */ +/** Bluetooth Mesh feature states */ enum bt_mesh_feat_state { /** Feature is supported, but disabled. */ BT_MESH_FEATURE_DISABLED, diff --git a/include/zephyr/bluetooth/mesh/cfg_cli.h b/include/zephyr/bluetooth/mesh/cfg_cli.h index 1a7c8ed7e2c1276..4aca0c17451d022 100644 --- a/include/zephyr/bluetooth/mesh/cfg_cli.h +++ b/include/zephyr/bluetooth/mesh/cfg_cli.h @@ -96,8 +96,8 @@ struct bt_mesh_cfg_cli_cb { * @param buf Message buffer containing subscription addresses. */ void (*mod_sub_list)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, - uint16_t elem_addr, uint16_t mod_id, uint16_t cid, - struct net_buf_simple *buf); + uint16_t elem_addr, uint16_t mod_id, uint16_t cid, + struct net_buf_simple *buf); /** @brief Optional callback for Node Reset Status messages. * @@ -128,7 +128,7 @@ struct bt_mesh_cfg_cli_cb { * @param status Status Code for requesting message. */ void (*ttl_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, - uint8_t status); + uint8_t status); /** @brief Optional callback for Friend Status messages. * @@ -139,7 +139,7 @@ struct bt_mesh_cfg_cli_cb { * @param status Status Code for requesting message. */ void (*friend_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, - uint8_t status); + uint8_t status); /** @brief Optional callback for GATT Proxy Status messages. * @@ -150,7 +150,7 @@ struct bt_mesh_cfg_cli_cb { * @param status Status Code for requesting message. */ void (*gatt_proxy_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, - uint8_t status); + uint8_t status); /** @brief Optional callback for Network Transmit Status messages. * @@ -199,7 +199,7 @@ struct bt_mesh_cfg_cli_cb { * @param buf Message buffer containing key indexes. */ void (*net_key_list)(struct bt_mesh_cfg_cli *cli, uint16_t addr, - struct net_buf_simple *buf); + struct net_buf_simple *buf); /** @brief Optional callback for AppKey Status messages. * @@ -229,7 +229,7 @@ struct bt_mesh_cfg_cli_cb { * @param buf Message buffer containing key indexes. */ void (*app_key_list)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, - uint16_t net_idx, struct net_buf_simple *buf); + uint16_t net_idx, struct net_buf_simple *buf); /** @brief Optional callback for Model App Status messages. * @@ -262,8 +262,8 @@ struct bt_mesh_cfg_cli_cb { * @param buf Message buffer containing key indexes. */ void (*mod_app_list)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, - uint16_t elem_addr, uint16_t mod_id, uint16_t cid, - struct net_buf_simple *buf); + uint16_t elem_addr, uint16_t mod_id, uint16_t cid, + struct net_buf_simple *buf); /** @brief Optional callback for Node Identity Status messages. * @@ -326,13 +326,13 @@ struct bt_mesh_cfg_cli_cb { * @param sub HB subscription configuration parameters. */ void (*hb_sub_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, - struct bt_mesh_cfg_cli_hb_sub *sub); + struct bt_mesh_cfg_cli_hb_sub *sub); }; /** Mesh Configuration Client Model Context */ struct bt_mesh_cfg_cli { /** Composition data model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /** Optional callback for Mesh Configuration Client Status messages. */ const struct bt_mesh_cfg_cli_cb *cb; diff --git a/include/zephyr/bluetooth/mesh/dfd_srv.h b/include/zephyr/bluetooth/mesh/dfd_srv.h index 666e0d8ad3d36ac..f15768080d79696 100644 --- a/include/zephyr/bluetooth/mesh/dfd_srv.h +++ b/include/zephyr/bluetooth/mesh/dfd_srv.h @@ -210,7 +210,7 @@ struct bt_mesh_dfd_srv_cb { /** Firmware Distribution Server instance. */ struct bt_mesh_dfd_srv { const struct bt_mesh_dfd_srv_cb *cb; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct bt_mesh_dfu_cli dfu; struct bt_mesh_dfu_target targets[CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX]; struct bt_mesh_blob_target_pull pull_ctxs[CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX]; diff --git a/include/zephyr/bluetooth/mesh/dfu_cli.h b/include/zephyr/bluetooth/mesh/dfu_cli.h index 51f534f2828ce8c..ad8881ebc26ef93 100644 --- a/include/zephyr/bluetooth/mesh/dfu_cli.h +++ b/include/zephyr/bluetooth/mesh/dfu_cli.h @@ -9,7 +9,7 @@ * @defgroup bt_mesh_dfu_cli Firmware Uppdate Client model * @ingroup bt_mesh_dfu * @{ - * @brief API for the Bluetooth mesh Firmware Update Client model + * @brief API for the Bluetooth Mesh Firmware Update Client model */ #ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_CLI_H__ @@ -190,7 +190,7 @@ struct bt_mesh_dfu_cli { /* runtime state */ uint32_t op; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct { const struct bt_mesh_dfu_slot *slot; diff --git a/include/zephyr/bluetooth/mesh/dfu_metadata.h b/include/zephyr/bluetooth/mesh/dfu_metadata.h index 8aea661ede74c8d..21d032236a7eb0f 100644 --- a/include/zephyr/bluetooth/mesh/dfu_metadata.h +++ b/include/zephyr/bluetooth/mesh/dfu_metadata.h @@ -6,10 +6,10 @@ /** * @file - * @defgroup bt_mesh_dfu_metadata Bluetooth mesh Device Firmware Update (DFU) metadata + * @defgroup bt_mesh_dfu_metadata Bluetooth Mesh Device Firmware Update (DFU) metadata * @ingroup bt_mesh_dfu * @{ - * @brief Common types and functions for the Bluetooth mesh DFU metadata. + * @brief Common types and functions for the Bluetooth Mesh DFU metadata. */ #ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_METADATA_H__ @@ -87,7 +87,7 @@ int bt_mesh_dfu_metadata_encode(const struct bt_mesh_dfu_metadata *metadata, /** @brief Compute hash of the Composition Data state. * - * The format of the Composition Data is defined in MshPRFv1.0.1, section 4.2.1.1. + * The format of the Composition Data is defined in MshPRTv1.1: 4.2.2.1. * * @param buf Pointer to buffer holding Composition Data. * @param key 128-bit key to be used in the hash computation. diff --git a/include/zephyr/bluetooth/mesh/dfu_srv.h b/include/zephyr/bluetooth/mesh/dfu_srv.h index 53d9144713c2a54..2beaf2d977207fe 100644 --- a/include/zephyr/bluetooth/mesh/dfu_srv.h +++ b/include/zephyr/bluetooth/mesh/dfu_srv.h @@ -9,7 +9,7 @@ * @defgroup bt_mesh_dfu_srv Firmware Update Server model * @ingroup bt_mesh_dfu * @{ - * @brief API for the Bluetooth mesh Firmware Update Server model + * @brief API for the Bluetooth Mesh Firmware Update Server model */ #ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_SRV_H__ @@ -136,7 +136,7 @@ struct bt_mesh_dfu_srv_cb { /** @brief Transfer recovery callback. * * If the device reboots in the middle of a transfer, the Firmware Update Server - * calls this function when the Bluetooth mesh subsystem is started. + * calls this function when the Bluetooth Mesh subsystem is started. * * This callback is optional, but transfers will not be recovered after * a reboot without it. @@ -184,7 +184,7 @@ struct bt_mesh_dfu_srv { size_t img_count; /* Runtime state */ - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; struct { /* Effect of transfer, @see bt_mesh_dfu_effect. */ uint8_t effect; diff --git a/include/zephyr/bluetooth/mesh/health_cli.h b/include/zephyr/bluetooth/mesh/health_cli.h index 2f13dd88ccfb258..2d8904ea6f279a7 100644 --- a/include/zephyr/bluetooth/mesh/health_cli.h +++ b/include/zephyr/bluetooth/mesh/health_cli.h @@ -26,7 +26,7 @@ extern "C" { /** Health Client Model Context */ struct bt_mesh_health_cli { /** Composition data model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /** Publication structure instance */ struct bt_mesh_model_pub pub; diff --git a/include/zephyr/bluetooth/mesh/health_srv.h b/include/zephyr/bluetooth/mesh/health_srv.h index 9665e3bc62a9d36..3eef7e459f70b82 100644 --- a/include/zephyr/bluetooth/mesh/health_srv.h +++ b/include/zephyr/bluetooth/mesh/health_srv.h @@ -53,7 +53,7 @@ struct bt_mesh_health_srv_cb { * * @return 0 on success, or (negative) error code otherwise. */ - int (*fault_get_cur)(struct bt_mesh_model *model, uint8_t *test_id, + int (*fault_get_cur)(const struct bt_mesh_model *model, uint8_t *test_id, uint16_t *company_id, uint8_t *faults, uint8_t *fault_count); @@ -79,7 +79,7 @@ struct bt_mesh_health_srv_cb { * * @return 0 on success, or (negative) error code otherwise. */ - int (*fault_get_reg)(struct bt_mesh_model *model, uint16_t company_id, + int (*fault_get_reg)(const struct bt_mesh_model *model, uint16_t company_id, uint8_t *test_id, uint8_t *faults, uint8_t *fault_count); @@ -91,7 +91,7 @@ struct bt_mesh_health_srv_cb { * * @return 0 on success, or (negative) error code otherwise. */ - int (*fault_clear)(struct bt_mesh_model *model, uint16_t company_id); + int (*fault_clear)(const struct bt_mesh_model *model, uint16_t company_id); /** @brief Run a self-test. * @@ -108,7 +108,7 @@ struct bt_mesh_health_srv_cb { * (negative) error code otherwise. Note that the fault array will not * be reported back to the client if the test execution didn't start. */ - int (*fault_test)(struct bt_mesh_model *model, uint8_t test_id, + int (*fault_test)(const struct bt_mesh_model *model, uint8_t test_id, uint16_t company_id); /** @brief Start calling attention to the device. @@ -125,7 +125,7 @@ struct bt_mesh_health_srv_cb { * * @param model Health Server model to start the attention state of. */ - void (*attn_on)(struct bt_mesh_model *model); + void (*attn_on)(const struct bt_mesh_model *model); /** @brief Stop the attention state. * @@ -134,7 +134,7 @@ struct bt_mesh_health_srv_cb { * * @param model */ - void (*attn_off)(struct bt_mesh_model *model); + void (*attn_off)(const struct bt_mesh_model *model); }; /** @@ -149,7 +149,7 @@ struct bt_mesh_health_srv_cb { /** Mesh Health Server Model Context */ struct bt_mesh_health_srv { /** Composition data model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /** Optional callback struct */ const struct bt_mesh_health_srv_cb *cb; @@ -219,7 +219,7 @@ struct bt_mesh_health_srv { * * @return 0 on success, or (negative) error code otherwise. */ -int bt_mesh_health_srv_fault_update(struct bt_mesh_elem *elem); +int bt_mesh_health_srv_fault_update(const struct bt_mesh_elem *elem); /** @cond INTERNAL_HIDDEN */ extern const struct bt_mesh_model_op bt_mesh_health_srv_op[]; diff --git a/include/zephyr/bluetooth/mesh/large_comp_data_cli.h b/include/zephyr/bluetooth/mesh/large_comp_data_cli.h index b7ed07762045253..520fcb3a6b53785 100644 --- a/include/zephyr/bluetooth/mesh/large_comp_data_cli.h +++ b/include/zephyr/bluetooth/mesh/large_comp_data_cli.h @@ -69,7 +69,7 @@ struct bt_mesh_large_comp_data_cli_cb { /** Large Composition Data Client model context */ struct bt_mesh_large_comp_data_cli { /** Model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /** Internal parameters for tracking message responses. */ struct bt_mesh_msg_ack_ctx ack_ctx; diff --git a/include/zephyr/bluetooth/mesh/main.h b/include/zephyr/bluetooth/mesh/main.h index ab274729cf8b946..1622ccebbd8db8b 100644 --- a/include/zephyr/bluetooth/mesh/main.h +++ b/include/zephyr/bluetooth/mesh/main.h @@ -1,5 +1,5 @@ /** @file - * @brief Bluetooth mesh Profile APIs. + * @brief Bluetooth Mesh Protocol APIs. */ /* @@ -550,8 +550,8 @@ bool bt_mesh_is_provisioned(void); */ /** - * @brief Bluetooth mesh - * @defgroup bt_mesh Bluetooth mesh + * @brief Bluetooth Mesh + * @defgroup bt_mesh Bluetooth Mesh * @ingroup bluetooth * @{ */ @@ -607,6 +607,10 @@ void bt_mesh_reset(void); * If at all possible, the Friendship feature should be used instead, to * make the node into a Low Power Node. * + * @note Should not be called from work queue due to undefined behavior. + * This is due to k_work_flush_delayable() being used in disabling of the + * extended advertising. + * * @return 0 on success, or (negative) error code on failure. */ int bt_mesh_suspend(void); @@ -779,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]; @@ -793,7 +796,6 @@ struct bt_mesh_prb { /** Authentication tag */ uint64_t auth_tag; }; -#endif /** Beacon callback functions. */ struct bt_mesh_beacon_cb { @@ -806,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 @@ -815,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/mesh/msg.h b/include/zephyr/bluetooth/mesh/msg.h index e52ca85e3a410e0..8a7ce1a712887ec 100644 --- a/include/zephyr/bluetooth/mesh/msg.h +++ b/include/zephyr/bluetooth/mesh/msg.h @@ -98,6 +98,9 @@ struct bt_mesh_msg_ctx { /** Force sending reliably by using segment acknowledgment */ bool send_rel; + /** Send message with a random delay according to the Access layer transmitting rules. */ + bool rnd_delay; + /** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */ uint8_t send_ttl; }; diff --git a/include/zephyr/bluetooth/mesh/od_priv_proxy_cli.h b/include/zephyr/bluetooth/mesh/od_priv_proxy_cli.h index f9734d78d3ebb34..0234158b04691d1 100644 --- a/include/zephyr/bluetooth/mesh/od_priv_proxy_cli.h +++ b/include/zephyr/bluetooth/mesh/od_priv_proxy_cli.h @@ -22,7 +22,7 @@ extern "C" { /** On-Demand Private Proxy Client Model Context */ struct bt_mesh_od_priv_proxy_cli { /** Solicitation PDU RPL model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /* Internal parameters for tracking message responses. */ struct bt_mesh_msg_ack_ctx ack_ctx; diff --git a/include/zephyr/bluetooth/mesh/priv_beacon_cli.h b/include/zephyr/bluetooth/mesh/priv_beacon_cli.h index 835dc38c773d602..ac77b45839fddfb 100644 --- a/include/zephyr/bluetooth/mesh/priv_beacon_cli.h +++ b/include/zephyr/bluetooth/mesh/priv_beacon_cli.h @@ -90,7 +90,7 @@ struct bt_mesh_priv_beacon_cli_cb { /** Mesh Private Beacon Client model */ struct bt_mesh_priv_beacon_cli { - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /* Internal parameters for tracking message responses. */ struct bt_mesh_msg_ack_ctx ack_ctx; @@ -101,14 +101,20 @@ struct bt_mesh_priv_beacon_cli { /** @brief Set the target's Private Beacon state. * + * This method can be used asynchronously by setting @p rsp as NULL. + * This way the method will not wait for response and will return + * immediately after sending the command. + * @param net_idx Network index to encrypt with. * @param addr Target node address. - * @param val New Private Beacon value. Returns response status on success. + * @param val New Private Beacon value. + * @param rsp If set, returns response status on success. * * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_priv_beacon_cli_set(uint16_t net_idx, uint16_t addr, - struct bt_mesh_priv_beacon *val); + struct bt_mesh_priv_beacon *val, + struct bt_mesh_priv_beacon *rsp); /** @brief Get the target's Private Beacon state. * @@ -122,16 +128,20 @@ int bt_mesh_priv_beacon_cli_get(uint16_t net_idx, uint16_t addr, struct bt_mesh_priv_beacon *val); /** @brief Set the target's Private GATT Proxy state. + * + * This method can be used asynchronously by setting @p rsp as NULL. + * This way the method will not wait for response and will return + * immediately after sending the command. * * @param net_idx Network index to encrypt with. * @param addr Target node address. - * @param val New Private GATT Proxy value. Returns response status on - * success. + * @param val New Private GATT Proxy value. + * @param rsp If set, returns response status on success. * * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_priv_beacon_cli_gatt_proxy_set(uint16_t net_idx, uint16_t addr, - uint8_t *val); + uint8_t val, uint8_t *rsp); /** @brief Get the target's Private GATT Proxy state. * @@ -145,16 +155,21 @@ int bt_mesh_priv_beacon_cli_gatt_proxy_get(uint16_t net_idx, uint16_t addr, uint8_t *val); /** @brief Set the target's Private Node Identity state. + * + * This method can be used asynchronously by setting @p rsp as NULL. + * This way the method will not wait for response and will return + * immediately after sending the command. * * @param net_idx Network index to encrypt with. * @param addr Target node address. - * @param val New Private Node Identity value. Returns response status on - * success. + * @param val New Private Node Identity value. + * @param rsp If set, returns response status on success. * * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_priv_beacon_cli_node_id_set(uint16_t net_idx, uint16_t addr, - struct bt_mesh_priv_node_id *val); + struct bt_mesh_priv_node_id *val, + struct bt_mesh_priv_node_id *rsp); /** @brief Get the target's Private Node Identity state. * diff --git a/include/zephyr/bluetooth/mesh/proxy.h b/include/zephyr/bluetooth/mesh/proxy.h index 60a397b9484cb98..03576acf9bf945e 100644 --- a/include/zephyr/bluetooth/mesh/proxy.h +++ b/include/zephyr/bluetooth/mesh/proxy.h @@ -97,9 +97,9 @@ int bt_mesh_proxy_connect(uint16_t net_idx); */ int bt_mesh_proxy_disconnect(uint16_t net_idx); -/** @brief Schedule advertising of Solicitation PDUs on Proxy Client . +/** @brief Schedule advertising of Solicitation PDUs. * - * Once called Proxy Client will schedule advertising Solicitation PDUs for the amount of time + * Once called, the device will schedule advertising Solicitation PDUs for the amount of time * defined by @c adv_int * (@c CONFIG_BT_MESH_SOL_ADV_XMIT + 1), where @c adv_int is 20ms * for Bluetooth v5.0 or higher, or 100ms otherwise. * diff --git a/include/zephyr/bluetooth/mesh/rpr_cli.h b/include/zephyr/bluetooth/mesh/rpr_cli.h index 5c0374fecc3bb5d..414e2887bdf059f 100644 --- a/include/zephyr/bluetooth/mesh/rpr_cli.h +++ b/include/zephyr/bluetooth/mesh/rpr_cli.h @@ -91,7 +91,7 @@ struct bt_mesh_rpr_cli { enum bt_mesh_rpr_link_state state; } link; - struct bt_mesh_model *mod; + const struct bt_mesh_model *mod; }; /** @brief Get scanning capabilities of Remote Provisioning Server. diff --git a/include/zephyr/bluetooth/mesh/sar_cfg_cli.h b/include/zephyr/bluetooth/mesh/sar_cfg_cli.h index 7882174512e4b03..5e8409d38412a99 100644 --- a/include/zephyr/bluetooth/mesh/sar_cfg_cli.h +++ b/include/zephyr/bluetooth/mesh/sar_cfg_cli.h @@ -27,7 +27,7 @@ extern "C" { /** Mesh SAR Configuration Client Model Context */ struct bt_mesh_sar_cfg_cli { /** Access model pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /* Publication structure instance */ struct bt_mesh_model_pub pub; diff --git a/include/zephyr/bluetooth/mesh/sol_pdu_rpl_cli.h b/include/zephyr/bluetooth/mesh/sol_pdu_rpl_cli.h index 5a3dcdd784dc224..5a6c49bd2119ace 100644 --- a/include/zephyr/bluetooth/mesh/sol_pdu_rpl_cli.h +++ b/include/zephyr/bluetooth/mesh/sol_pdu_rpl_cli.h @@ -22,7 +22,7 @@ extern "C" { /** Solicitation PDU RPL Client Model Context */ struct bt_mesh_sol_pdu_rpl_cli { /** Solicitation PDU RPL model entry pointer. */ - struct bt_mesh_model *model; + const struct bt_mesh_model *model; /* Internal parameters for tracking message responses. */ struct bt_mesh_msg_ack_ctx ack_ctx; diff --git a/include/zephyr/bluetooth/services/hrs.h b/include/zephyr/bluetooth/services/hrs.h index 097998f5caf3940..f19b2924ce07a1a 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/testing.h b/include/zephyr/bluetooth/testing.h index 9cfda4e11779908..58aae9726ffa1a3 100644 --- a/include/zephyr/bluetooth/testing.h +++ b/include/zephyr/bluetooth/testing.h @@ -39,9 +39,9 @@ struct bt_test_cb { const void *payload, size_t payload_len); void (*mesh_model_recv)(uint16_t src, uint16_t dst, const void *payload, size_t payload_len); - void (*mesh_model_bound)(uint16_t addr, struct bt_mesh_model *model, + void (*mesh_model_bound)(uint16_t addr, const struct bt_mesh_model *model, uint16_t key_idx); - void (*mesh_model_unbound)(uint16_t addr, struct bt_mesh_model *model, + void (*mesh_model_unbound)(uint16_t addr, const struct bt_mesh_model *model, uint16_t key_idx); void (*mesh_prov_invalid_bearer)(uint8_t opcode); void (*mesh_trans_incomp_timer_exp)(void); diff --git a/include/zephyr/bluetooth/uuid.h b/include/zephyr/bluetooth/uuid.h index cab12eac74b0deb..16943f89e6338fb 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/canbus/isotp.h b/include/zephyr/canbus/isotp.h index d162b8dc531282c..222cef70a315217 100644 --- a/include/zephyr/canbus/isotp.h +++ b/include/zephyr/canbus/isotp.h @@ -153,10 +153,10 @@ extern "C" { /** Message uses extended (29-bit) CAN ID */ #define ISOTP_MSG_IDE BIT(2) -/** Message uses CAN-FD format (FDF) */ +/** Message uses CAN FD format (FDF) */ #define ISOTP_MSG_FDF BIT(3) -/** Message uses CAN-FD Baud Rate Switch (BRS). Only valid in combination with ``ISOTP_MSG_FDF``. */ +/** Message uses CAN FD Baud Rate Switch (BRS). Only valid in combination with ``ISOTP_MSG_FDF``. */ #define ISOTP_MSG_BRS BIT(4) /** @} */ @@ -182,7 +182,7 @@ struct isotp_msg_id { /** * ISO-TP frame data length (TX_DL for TX address or RX_DL for RX address). * - * Valid values are 8 for classical CAN or 8, 12, 16, 20, 24, 32, 48 and 64 for CAN-FD. + * Valid values are 8 for classical CAN or 8, 12, 16, 20, 24, 32, 48 and 64 for CAN FD. * * 0 will be interpreted as 8 or 64 (if ISOTP_MSG_FDF is set). * diff --git a/include/zephyr/console/console.h b/include/zephyr/console/console.h index 9ce09c081de8ae1..fbecfdad0d3bc88 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/data/navigation.h b/include/zephyr/data/navigation.h new file mode 100644 index 000000000000000..0759df984ea4351 --- /dev/null +++ b/include/zephyr/data/navigation.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DATA_NAVIGATION_H_ +#define ZEPHYR_INCLUDE_DATA_NAVIGATION_H_ + +#include + +/** + * @brief Navigation utilities + * @defgroup navigation Navigation + * @ingroup utilities + * @{ + */ + +/** + * @brief Navigation data structure + * + * @details The structure describes the momentary navigation details of a + * point relative to a sphere (commonly Earth) + */ +struct navigation_data { + /** Latitudal position in nanodegrees (0 to +-180E9) */ + int64_t latitude; + /** Longitudal position in nanodegrees (0 to +-180E9) */ + int64_t longitude; + /** Bearing angle in millidegrees (0 to 360E3) */ + uint32_t bearing; + /** Speed in millimeters per second */ + uint32_t speed; + /** Altitude in millimeters */ + int32_t altitude; +}; + +/** + * @brief Calculate the distance between two navigation points along the + * surface of the sphere they are relative to. + * + * @param distance Destination for calculated distance in millimeters + * @param p1 First navigation point + * @param p2 Second navigation point + * + * @return 0 if successful + * @return -EINVAL if either navigation point is invalid + */ +int navigation_distance(uint64_t *distance, const struct navigation_data *p1, + const struct navigation_data *p2); + +/** + * @brief Calculate the bearing from one navigation point to another + * + * @param bearing Destination for calculated bearing angle in millidegrees + * @param from First navigation point + * @param to Second navigation point + * + * @return 0 if successful + * @return -EINVAL if either navigation point is invalid + */ +int navigation_bearing(uint32_t *bearing, const struct navigation_data *from, + const struct navigation_data *to); + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_DATA_NAVIGATION_H_ */ diff --git a/include/zephyr/device.h b/include/zephyr/device.h index ca59579500090b5..c55958924ff8203 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 */ /** @@ -924,12 +928,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 +966,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), \ + }, \ } /** @@ -1005,7 +1013,6 @@ static inline bool z_impl_device_is_ready(const struct device *dev) \ Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn, level, prio) -#if defined(CONFIG_HAS_DTS) || defined(__DOXYGEN__) /** * @brief Declare a device for each status "okay" devicetree node. * @@ -1016,11 +1023,11 @@ 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) -#endif /* CONFIG_HAS_DTS */ /** @endcond */ diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index c249ad371e2e4ae..483a659f46ca914 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -17,6 +17,7 @@ #define DEVICETREE_H #include +#include #if !defined(_LINKER) && !defined(_ASMLANGUAGE) #include @@ -355,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 @@ -777,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 * @@ -1218,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 @@ -1393,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) @@ -1486,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 @@ -2297,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? * @@ -2409,6 +2407,181 @@ */ #define DT_IRQ(node_id, cell) DT_IRQ_BY_IDX(node_id, 0, cell) +/** + * @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) + +/** + * @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_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_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) \ + DT_IRQN_LVL_INTERNAL(node_id, idx, DT_IRQ_LEVEL(node_id)) + +/** + * INTERNAL_HIDDEN @endcond + */ + +/** + * @brief Get the node's Zephyr interrupt number at index + * If @kconfig{CONFIG_MULTI_LEVEL_INTERRUPTS} is enabled, the interrupt number at index will be + * multi-level encoded + * @param node_id node identifier + * @param idx logical index into the interrupt specifier array + * @return the Zephyr interrupt number + */ +#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_IRQ_BY_IDX(node_id, idx, irq))) + /** * @brief Get a node's (only) irq number * @@ -2419,7 +2592,7 @@ * @param node_id node identifier * @return the interrupt number for the node's only interrupt */ -#define DT_IRQN(node_id) DT_IRQ(node_id, irq) +#define DT_IRQN(node_id) DT_IRQN_BY_IDX(node_id, 0) /** * @} @@ -2914,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)), \ ()) /** @@ -2963,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__)), \ ()) @@ -3188,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? * @@ -3509,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. @@ -3792,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 @@ -3802,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 @@ -3825,24 +4016,22 @@ * @param inst instance number * @return the interrupt number for the node's only interrupt */ -#define DT_INST_IRQN(inst) DT_INST_IRQ(inst, irq) +#define DT_INST_IRQN(inst) DT_IRQN(DT_DRV_INST(inst)) /** - * @brief Get a `DT_DRV_COMPAT`'s bus node identifier + * @brief Get a `DT_DRV_COMPAT`'s irq number at index * @param inst instance number - * @return node identifier for the instance's bus node + * @param idx logical index into the interrupt specifier array + * @return the interrupt number for the node's idx-th interrupt */ -#define DT_INST_BUS(inst) DT_BUS(DT_DRV_INST(inst)) +#define DT_INST_IRQN_BY_IDX(inst, idx) DT_IRQN_BY_IDX(DT_DRV_INST(inst), idx) /** - * @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 + * @brief Get a `DT_DRV_COMPAT`'s bus node identifier * @param inst instance number - * @return the label property of the instance's bus controller + * @return node identifier for the instance's bus node */ -#define DT_INST_BUS_LABEL(inst) DT_BUS_LABEL(DT_DRV_INST(inst)) __DEPRECATED_MACRO +#define DT_INST_BUS(inst) DT_BUS(DT_DRV_INST(inst)) /** * @brief Test if a `DT_DRV_COMPAT`'s bus type is a given type @@ -3918,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 965de6f7149cab0..93426796f896573 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 e7994982a7e6c81..d1f916c3df99f29 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/drivers/adc/adc_emul.h b/include/zephyr/drivers/adc/adc_emul.h index a07b86e38c9c48a..03c2fbbb3fd0def 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 c305ecc37c38891..e8a26b2cb9471e2 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__)*/ }; @@ -245,7 +255,7 @@ int bt_hci_transport_setup(const struct device *dev); /** * @brief Teardown the HCI transport. * - * @note A weak version of this function is included in the RPMSG driver, so + * @note A weak version of this function is included in the IPC driver, so * defining it is optional. NRF5340 includes support to put network core * in reset state. * diff --git a/include/zephyr/drivers/can.h b/include/zephyr/drivers/can.h index 54a75b93dc322d5..59be684fd385d5c 100644 --- a/include/zephyr/drivers/can.h +++ b/include/zephyr/drivers/can.h @@ -6,6 +6,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @file + * @brief Controller Area Network (CAN) driver API. + */ + #ifndef ZEPHYR_INCLUDE_DRIVERS_CAN_H_ #define ZEPHYR_INCLUDE_DRIVERS_CAN_H_ @@ -55,7 +60,7 @@ extern "C" { */ #define CAN_MAX_DLC 8U /** - * @brief Maximum data length code for CAN-FD. + * @brief Maximum data length code for CAN FD. */ #define CANFD_MAX_DLC 15U @@ -89,7 +94,7 @@ extern "C" { /** Controller is not allowed to send dominant bits. */ #define CAN_MODE_LISTENONLY BIT(1) -/** Controller allows transmitting/receiving CAN-FD frames. */ +/** Controller allows transmitting/receiving CAN FD frames. */ #define CAN_MODE_FD BIT(2) /** Controller does not retransmit in case of lost arbitration or missing ACK */ @@ -139,13 +144,13 @@ enum can_state { /** Frame is a Remote Transmission Request (RTR) */ #define CAN_FRAME_RTR BIT(1) -/** Frame uses CAN-FD format (FDF) */ +/** Frame uses CAN FD format (FDF) */ #define CAN_FRAME_FDF BIT(2) -/** Frame uses CAN-FD Baud Rate Switch (BRS). Only valid in combination with ``CAN_FRAME_FDF``. */ +/** Frame uses CAN FD Baud Rate Switch (BRS). Only valid in combination with ``CAN_FRAME_FDF``. */ #define CAN_FRAME_BRS BIT(3) -/** CAN-FD Error State Indicator (ESI). Indicates that the transmitting node is in error-passive +/** CAN FD Error State Indicator (ESI). Indicates that the transmitting node is in error-passive * state. Only valid in combination with ``CAN_FRAME_FDF``. */ #define CAN_FRAME_ESI BIT(4) @@ -181,7 +186,9 @@ struct can_frame { #endif /** The frame payload data. */ union { + /** Payload data accessed as unsigned 8 bit values. */ uint8_t data[CAN_MAX_DLEN]; + /** Payload data accessed as unsigned 32 bit values. */ uint32_t data_32[DIV_ROUND_UP(CAN_MAX_DLEN, sizeof(uint32_t))]; }; }; @@ -196,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) /** @} */ @@ -318,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 @@ -326,7 +392,7 @@ typedef int (*can_set_timing_t)(const struct device *dev, const struct can_timing *timing); /** - * @brief Optional callback API upon setting CAN-FD bus timing for the data phase. + * @brief Optional callback API upon setting CAN FD bus timing for the data phase. * See @a can_set_timing_data() for argument description */ typedef int (*can_set_timing_data_t)(const struct device *dev, @@ -416,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; @@ -438,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 */ @@ -461,6 +520,7 @@ __subsystem struct can_driver_api { /** @cond INTERNAL_HIDDEN */ STATS_SECT_START(can) +STATS_SECT_ENTRY32(bit_error) STATS_SECT_ENTRY32(bit0_error) STATS_SECT_ENTRY32(bit1_error) STATS_SECT_ENTRY32(stuff_error) @@ -471,6 +531,7 @@ STATS_SECT_ENTRY32(rx_overrun) STATS_SECT_END; STATS_NAME_START(can) +STATS_NAME(can, bit_error) STATS_NAME(can, bit0_error) STATS_NAME(can, bit1_error) STATS_NAME(can, stuff_error) @@ -487,7 +548,9 @@ STATS_NAME_END(can); * additions */ struct can_device_state { + /** Common device state. */ struct device_state devstate; + /** CAN device statistics */ struct stats_can stats; }; @@ -501,16 +564,41 @@ struct can_device_state { /** @endcond */ +/** + * @brief Increment the bit error counter for a CAN device + * + * The bit error counter is incremented when the CAN controller is unable to + * transmit either a dominant or a recessive bit. + * + * @note This error counter should only be incremented if the CAN controller is unable to + * distinquish between failure to transmit a dominant versus failure to transmit a recessive bit. If + * the CAN controller supports distinguishing between the two, the `bit0` or `bit1` error counter + * shall be incremented instead. + * + * @see CAN_STATS_BIT0_ERROR_INC() + * @see CAN_STATS_BIT1_ERROR_INC() + * + * @param dev_ Pointer to the device structure for the driver instance. + */ +#define CAN_STATS_BIT_ERROR_INC(dev_) \ + STATS_INC(Z_CAN_GET_STATS(dev_), bit_error) + /** * @brief Increment the bit0 error counter for a CAN device * * The bit0 error counter is incremented when the CAN controller is unable to * transmit a dominant bit. * + * Incrementing this counter will automatically increment the bit error counter. + * @see CAN_STATS_BIT_ERROR_INC() + * * @param dev_ Pointer to the device structure for the driver instance. */ -#define CAN_STATS_BIT0_ERROR_INC(dev_) \ - STATS_INC(Z_CAN_GET_STATS(dev_), bit0_error) +#define CAN_STATS_BIT0_ERROR_INC(dev_) \ + do { \ + STATS_INC(Z_CAN_GET_STATS(dev_), bit0_error); \ + CAN_STATS_BIT_ERROR_INC(dev_); \ + } while (0) /** * @brief Increment the bit1 (recessive) error counter for a CAN device @@ -518,10 +606,16 @@ struct can_device_state { * The bit1 error counter is incremented when the CAN controller is unable to * transmit a recessive bit. * + * Incrementing this counter will automatically increment the bit error counter. + * @see CAN_STATS_BIT_ERROR_INC() + * * @param dev_ Pointer to the device structure for the driver instance. */ -#define CAN_STATS_BIT1_ERROR_INC(dev_) \ - STATS_INC(Z_CAN_GET_STATS(dev_), bit1_error) +#define CAN_STATS_BIT1_ERROR_INC(dev_) \ + do { \ + STATS_INC(Z_CAN_GET_STATS(dev_), bit1_error); \ + CAN_STATS_BIT_ERROR_INC(dev_); \ + } while (0) /** * @brief Increment the stuffing error counter for a CAN device @@ -610,7 +704,7 @@ struct can_device_state { { \ struct can_device_state *state = \ CONTAINER_OF(dev->state, struct can_device_state, devstate); \ - stats_init(&state->stats.s_hdr, STATS_SIZE_32, 7, \ + stats_init(&state->stats.s_hdr, STATS_SIZE_32, 8, \ STATS_NAME_INIT_PARMS(can)); \ stats_register(dev->name, &(state->stats.s_hdr)); \ if (init_fn != NULL) { \ @@ -655,6 +749,7 @@ struct can_device_state { #else /* CONFIG_CAN_STATS */ +#define CAN_STATS_BIT_ERROR_INC(dev_) #define CAN_STATS_BIT0_ERROR_INC(dev_) #define CAN_STATS_BIT1_ERROR_INC(dev_) #define CAN_STATS_STUFF_ERROR_INC(dev_) @@ -722,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; } /** @@ -798,7 +895,7 @@ __syscall int can_calc_timing(const struct device *dev, struct can_timing *res, * @param dev Pointer to the device structure for the driver instance. * * @return Pointer to the minimum supported timing parameter values, or NULL if - * CAN-FD support is not implemented by the driver. + * CAN FD support is not implemented by the driver. */ __syscall const struct can_timing *can_get_timing_data_min(const struct device *dev); @@ -822,7 +919,7 @@ static inline const struct can_timing *z_impl_can_get_timing_data_min(const stru * @param dev Pointer to the device structure for the driver instance. * * @return Pointer to the maximum supported timing parameter values, or NULL if - * CAN-FD support is not implemented by the driver. + * CAN FD support is not implemented by the driver. */ __syscall const struct can_timing *can_get_timing_data_max(const struct device *dev); @@ -858,7 +955,7 @@ __syscall int can_calc_timing_data(const struct device *dev, struct can_timing * uint32_t bitrate, uint16_t sample_pnt); /** - * @brief Configure the bus timing for the data phase of a CAN-FD controller. + * @brief Configure the bus timing for the data phase of a CAN FD controller. * * @note @kconfig{CONFIG_CAN_FD_MODE} must be selected for this function to be * available. @@ -872,13 +969,13 @@ __syscall int can_calc_timing_data(const struct device *dev, struct can_timing * * @retval -EBUSY if the CAN controller is not in stopped state. * @retval -EIO General input/output error, failed to configure device. * @retval -ENOTSUP if the timing parameters are not supported by the driver. - * @retval -ENOSYS if CAN-FD support is not implemented by the driver. + * @retval -ENOSYS if CAN FD support is not implemented by the driver. */ __syscall int can_set_timing_data(const struct device *dev, const struct can_timing *timing_data); /** - * @brief Set the bitrate for the data phase of the CAN-FD controller + * @brief Set the bitrate for the data phase of the CAN FD controller * * CAN in Automation (CiA) 301 v4.2.0 recommends a sample point location of * 87.5% percent for all bitrates. However, some CAN controllers have @@ -964,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 * @@ -971,6 +1086,8 @@ static inline int z_impl_can_get_capabilities(const struct device *dev, can_mode * enable the CAN controller to participate in CAN communication, and enable the CAN tranceiver, if * supported. * + * Starting the CAN controller resets all the CAN controller statistics. + * * @see can_stop() * @see can_transceiver_enable() * @@ -1031,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 * @@ -1150,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; } @@ -1333,6 +1466,187 @@ static inline void can_set_state_change_callback(const struct device *dev, /** @} */ +/** + * @name CAN statistics + * + * @{ + */ + +/** + * @brief Get the bit error counter for a CAN device + * + * The bit error counter is incremented when the CAN controller is unable to + * transmit either a dominant or a recessive bit. + * + * @note @kconfig{CONFIG_CAN_STATS} must be selected for this function to be + * available. + * + * @param dev Pointer to the device structure for the driver instance. + * @return bit error counter + */ +__syscall uint32_t can_stats_get_bit_errors(const struct device *dev); + +#ifdef CONFIG_CAN_STATS +static inline uint32_t z_impl_can_stats_get_bit_errors(const struct device *dev) +{ + return Z_CAN_GET_STATS(dev).bit_error; +} +#endif /* CONFIG_CAN_STATS */ + +/** + * @brief Get the bit0 error counter for a CAN device + * + * The bit0 error counter is incremented when the CAN controller is unable to + * transmit a dominant bit. + * + * @note @kconfig{CONFIG_CAN_STATS} must be selected for this function to be + * available. + * + * @see can_stats_get_bit_errors() + * + * @param dev Pointer to the device structure for the driver instance. + * @return bit0 error counter + */ +__syscall uint32_t can_stats_get_bit0_errors(const struct device *dev); + +#ifdef CONFIG_CAN_STATS +static inline uint32_t z_impl_can_stats_get_bit0_errors(const struct device *dev) +{ + return Z_CAN_GET_STATS(dev).bit0_error; +} +#endif /* CONFIG_CAN_STATS */ + +/** + * @brief Get the bit1 error counter for a CAN device + * + * The bit1 error counter is incremented when the CAN controller is unable to + * transmit a recessive bit. + * + * @note @kconfig{CONFIG_CAN_STATS} must be selected for this function to be + * available. + * + * @see can_stats_get_bit_errors() + * + * @param dev Pointer to the device structure for the driver instance. + * @return bit1 error counter + */ +__syscall uint32_t can_stats_get_bit1_errors(const struct device *dev); + +#ifdef CONFIG_CAN_STATS +static inline uint32_t z_impl_can_stats_get_bit1_errors(const struct device *dev) +{ + return Z_CAN_GET_STATS(dev).bit1_error; +} +#endif /* CONFIG_CAN_STATS */ + +/** + * @brief Get the stuffing error counter for a CAN device + * + * The stuffing error counter is incremented when the CAN controller detects a + * bit stuffing error. + * + * @note @kconfig{CONFIG_CAN_STATS} must be selected for this function to be + * available. + * + * @param dev Pointer to the device structure for the driver instance. + * @return stuffing error counter + */ +__syscall uint32_t can_stats_get_stuff_errors(const struct device *dev); + +#ifdef CONFIG_CAN_STATS +static inline uint32_t z_impl_can_stats_get_stuff_errors(const struct device *dev) +{ + return Z_CAN_GET_STATS(dev).stuff_error; +} +#endif /* CONFIG_CAN_STATS */ + +/** + * @brief Get the CRC error counter for a CAN device + * + * The CRC error counter is incremented when the CAN controller detects a frame + * with an invalid CRC. + * + * @note @kconfig{CONFIG_CAN_STATS} must be selected for this function to be + * available. + * + * @param dev Pointer to the device structure for the driver instance. + * @return CRC error counter + */ +__syscall uint32_t can_stats_get_crc_errors(const struct device *dev); + +#ifdef CONFIG_CAN_STATS +static inline uint32_t z_impl_can_stats_get_crc_errors(const struct device *dev) +{ + return Z_CAN_GET_STATS(dev).crc_error; +} +#endif /* CONFIG_CAN_STATS */ + +/** + * @brief Get the form error counter for a CAN device + * + * The form error counter is incremented when the CAN controller detects a + * fixed-form bit field containing illegal bits. + * + * @note @kconfig{CONFIG_CAN_STATS} must be selected for this function to be + * available. + * + * @param dev Pointer to the device structure for the driver instance. + * @return form error counter + */ +__syscall uint32_t can_stats_get_form_errors(const struct device *dev); + +#ifdef CONFIG_CAN_STATS +static inline uint32_t z_impl_can_stats_get_form_errors(const struct device *dev) +{ + return Z_CAN_GET_STATS(dev).form_error; +} +#endif /* CONFIG_CAN_STATS */ + +/** + * @brief Get the acknowledge error counter for a CAN device + * + * The acknowledge error counter is incremented when the CAN controller does not + * monitor a dominant bit in the ACK slot. + * + * @note @kconfig{CONFIG_CAN_STATS} must be selected for this function to be + * available. + * + * @param dev Pointer to the device structure for the driver instance. + * @return acknowledge error counter + */ +__syscall uint32_t can_stats_get_ack_errors(const struct device *dev); + +#ifdef CONFIG_CAN_STATS +static inline uint32_t z_impl_can_stats_get_ack_errors(const struct device *dev) +{ + return Z_CAN_GET_STATS(dev).ack_error; +} +#endif /* CONFIG_CAN_STATS */ + +/** + * @brief Get the RX overrun counter for a CAN device + * + * The RX overrun counter is incremented when the CAN controller receives a CAN + * frame matching an installed filter but lacks the capacity to store it (either + * due to an already full RX mailbox or a full RX FIFO). + * + * @note @kconfig{CONFIG_CAN_STATS} must be selected for this function to be + * available. + * + * @param dev Pointer to the device structure for the driver instance. + * @return RX overrun counter + */ +__syscall uint32_t can_stats_get_rx_overruns(const struct device *dev); + +#ifdef CONFIG_CAN_STATS +static inline uint32_t z_impl_can_stats_get_rx_overruns(const struct device *dev) +{ + return Z_CAN_GET_STATS(dev).rx_overrun; +} +#endif /* CONFIG_CAN_STATS */ + +/** @} */ + /** * @name CAN utility functions * @@ -1393,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_mcan.h b/include/zephyr/drivers/can/can_mcan.h index 6cc632fb13e3da6..a20f98648806d22 100644 --- a/include/zephyr/drivers/can/can_mcan.h +++ b/include/zephyr/drivers/can/can_mcan.h @@ -640,7 +640,7 @@ enum can_mcan_psr_lec { */ #define CAN_MCAN_DT_MRAM_DEFINE(node_id, _name) \ BUILD_ASSERT(CAN_MCAN_DT_MRAM_OFFSET(node_id) == 0, "offset must be 0"); \ - static char __noinit __nocache __aligned(4) _name[CAN_MCAN_DT_MRAM_ELEMENTS_SIZE(node_id)]; + static char __nocache_noinit __aligned(4) _name[CAN_MCAN_DT_MRAM_ELEMENTS_SIZE(node_id)]; /** * @brief Assert that the Message RAM configuration meets the Bosch M_CAN IP core restrictions @@ -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 fe826296db93d9f..a3a316c26b89162 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 e4c6828983cf017..19c22e7733d596d 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 000000000000000..fba05e6e4401c28 --- /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 8e72ae03b0b733a..cf55fd88402d91f 100644 --- a/include/zephyr/drivers/charger.h +++ b/include/zephyr/drivers/charger.h @@ -4,6 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @file + * @brief Charger APIs + */ + #ifndef ZEPHYR_INCLUDE_DRIVERS_CHARGER_H_ #define ZEPHYR_INCLUDE_DRIVERS_CHARGER_H_ @@ -37,6 +42,41 @@ enum charger_property { /** Represents the charging status of the charger. */ /** Value should be of type enum charger_status */ CHARGER_PROP_STATUS, + /** Represents the charging algo type of the charger. */ + /** Value should be of type enum charger_charge_type */ + CHARGER_PROP_CHARGE_TYPE, + /** Represents the health of the charger. */ + /** Value should be of type enum charger_health */ + CHARGER_PROP_HEALTH, + /** Configuration of current sink used for charging in µA */ + CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA, + /** Configuration of current sink used for conditioning in µA */ + CHARGER_PROP_PRECHARGE_CURRENT_UA, + /** Configuration of charge termination target in µA */ + 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, /** @@ -84,6 +124,100 @@ enum charger_status { CHARGER_STATUS_FULL, }; +/** + * @brief Charge algorithm types + */ +enum charger_charge_type { + /** Charge type is unknown */ + CHARGER_CHARGE_TYPE_UNKNOWN = 0, + /** Charging is not occurring */ + CHARGER_CHARGE_TYPE_NONE, + /** + * Charging is occurring at the slowest desired charge rate, + * typically for battery detection or preconditioning + */ + CHARGER_CHARGE_TYPE_TRICKLE, + /** Charging is occurring at the fastest desired charge rate */ + CHARGER_CHARGE_TYPE_FAST, + /** Charging is occurring at a moderate charge rate */ + CHARGER_CHARGE_TYPE_STANDARD, + /* + * Charging is being dynamically adjusted by the charger device + */ + CHARGER_CHARGE_TYPE_ADAPTIVE, + /* + * Charging is occurring at a reduced charge rate to preserve + * battery health + */ + CHARGER_CHARGE_TYPE_LONGLIFE, + /* + * The charger device is being bypassed and the power conversion + * is being handled externally, typically by a "smart" wall adaptor + */ + CHARGER_CHARGE_TYPE_BYPASS, +}; + +/** + * @brief Charger health conditions + * + * These conditions determine the ability to, or the rate of, charge + */ +enum charger_health { + /** Charger health condition is unknown */ + CHARGER_HEALTH_UNKNOWN = 0, + /** Charger health condition is good */ + CHARGER_HEALTH_GOOD, + /** The charger device is overheated */ + CHARGER_HEALTH_OVERHEAT, + /** The battery voltage has exceeded its overvoltage threshold */ + CHARGER_HEALTH_OVERVOLTAGE, + /** + * The battery or charger device is experiencing an unspecified + * failure. + */ + CHARGER_HEALTH_UNSPEC_FAILURE, + /** The battery temperature is below the "cold" threshold */ + CHARGER_HEALTH_COLD, + /** The charger device's watchdog timer has expired */ + CHARGER_HEALTH_WATCHDOG_TIMER_EXPIRE, + /** The charger device's safety timer has expired */ + CHARGER_HEALTH_SAFETY_TIMER_EXPIRE, + /** The charger device requires calibration */ + CHARGER_HEALTH_CALIBRATION_REQUIRED, + /** The battery temperature is in the "warm" range */ + CHARGER_HEALTH_WARM, + /** The battery temperature is in the "cool" range */ + CHARGER_HEALTH_COOL, + /** The battery temperature is below the "hot" threshold */ + CHARGER_HEALTH_HOT, + /** The charger device does not detect a battery */ + 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 * @@ -99,6 +233,24 @@ union charger_propval { bool present; /** CHARGER_PROP_STATUS */ enum charger_status status; + /** CHARGER_PROP_CHARGE_TYPE */ + enum charger_charge_type charge_type; + /** CHARGER_PROP_HEALTH */ + enum charger_health health; + /** CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA */ + uint32_t const_charge_current_ua; + /** CHARGER_PROP_PRECHARGE_CURRENT_UA */ + uint32_t precharge_current_ua; + /** CHARGER_PROP_CHARGE_TERM_CURRENT_UA */ + 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; }; /** @@ -119,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 * @@ -127,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; }; /** @@ -171,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/clock_control_ambiq.h b/include/zephyr/drivers/clock_control/clock_control_ambiq.h new file mode 100644 index 000000000000000..02ca16b54dbf81e --- /dev/null +++ b/include/zephyr/drivers/clock_control/clock_control_ambiq.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_CLOCK_CONTROL_AMBIQ_H_ +#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_CLOCK_CONTROL_AMBIQ_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Clocks handled by the CLOCK peripheral. + * + * Enum shall be used as a sys argument in clock_control API. + */ +enum clock_control_ambiq_type { + CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE, + CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_USB, + CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_ADC, + CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_AUADC, + CLOCK_CONTROL_AMBIQ_TYPE_HCXTAL_DBGCTRL, + CLOCK_CONTROL_AMBIQ_TYPE_HCXTAL_CLKGEN_MISC, + CLOCK_CONTROL_AMBIQ_TYPE_HCXTAL_CLKGEN_CLKOUT, + CLOCK_CONTROL_AMBIQ_TYPE_HCXTAL_PDM, + CLOCK_CONTROL_AMBIQ_TYPE_HCXTAL_IIS, + CLOCK_CONTROL_AMBIQ_TYPE_HCXTAL_IOM, + CLOCK_CONTROL_AMBIQ_TYPE_LFXTAL, + CLOCK_CONTROL_AMBIQ_TYPE_MAX +}; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_CLOCK_CONTROL_AMBIQ_H_ */ diff --git a/include/zephyr/drivers/clock_control/stm32_clock_control.h b/include/zephyr/drivers/clock_control/stm32_clock_control.h index 36df690220b91b2..062fae034e31140 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) @@ -385,6 +386,10 @@ #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(clk_hsi48), fixed_clock, okay) #define STM32_HSI48_ENABLED 1 #define STM32_HSI48_FREQ DT_PROP(DT_NODELABEL(clk_hsi48), clock_frequency) +#elif DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(clk_hsi48), st_stm32_hsi48_clock, okay) +#define STM32_HSI48_ENABLED 1 +#define STM32_HSI48_FREQ DT_PROP(DT_NODELABEL(clk_hsi48), clock_frequency) +#define STM32_HSI48_CRS_USB_SOF DT_PROP(DT_NODELABEL(clk_hsi48), crs_usb_sof) #endif #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(perck), st_stm32_clock_mux, okay) @@ -456,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 da124b4512d5df3..e0969292fbbce22 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 a72534b4e50b816..010443e319f89a6 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.h b/include/zephyr/drivers/dma.h index eb04334101d0066..2905c6fc43456d4 100644 --- a/include/zephyr/drivers/dma.h +++ b/include/zephyr/drivers/dma.h @@ -28,12 +28,21 @@ extern "C" { * @{ */ +/** + * @brief DMA channel direction + */ enum dma_channel_direction { + /** Memory to memory */ MEMORY_TO_MEMORY = 0x0, + /** Memory to peripheral */ MEMORY_TO_PERIPHERAL, + /** Peripheral to memory */ PERIPHERAL_TO_MEMORY, + /** Peripheral to peripheral */ PERIPHERAL_TO_PERIPHERAL, + /** Host to memory */ HOST_TO_MEMORY, + /** Memory to host */ MEMORY_TO_HOST, /** @@ -53,20 +62,31 @@ enum dma_channel_direction { DMA_CHANNEL_DIRECTION_MAX = 0x7 }; -/** Valid values for @a source_addr_adj and @a dest_addr_adj */ +/** + * @brief DMA address adjustment + * + * Valid values for @a source_addr_adj and @a dest_addr_adj + */ enum dma_addr_adj { + /** Increment the address */ DMA_ADDR_ADJ_INCREMENT, + /** Decrement the address */ DMA_ADDR_ADJ_DECREMENT, + /** No change the address */ DMA_ADDR_ADJ_NO_CHANGE, }; -/* channel attributes */ +/** + * @brief DMA channel attributes + */ enum dma_channel_filter { DMA_CHANNEL_NORMAL, /* normal DMA channel */ DMA_CHANNEL_PERIODIC, /* can be triggered by periodic sources */ }; -/* DMA attributes */ +/** + * @brief DMA attributes + */ enum dma_attribute_type { DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, DMA_ATTR_BUFFER_SIZE_ALIGNMENT, @@ -78,65 +98,73 @@ enum dma_attribute_type { * @struct dma_block_config * @brief DMA block configuration structure. * - * @param source_address is block starting address at source - * @param source_gather_interval is the address adjustment at gather boundary - * @param dest_address is block starting address at destination - * @param dest_scatter_interval is the address adjustment at scatter boundary - * @param dest_scatter_count is the continuous transfer count between scatter - * boundaries - * @param source_gather_count is the continuous transfer count between gather - * boundaries - * - * @param block_size is the number of bytes to be transferred for this block. - * - * @param config is a bit field with the following parts: - * - * source_gather_en [ 0 ] - 0-disable, 1-enable. - * dest_scatter_en [ 1 ] - 0-disable, 1-enable. - * source_addr_adj [ 2 : 3 ] - 00-increment, 01-decrement, - * 10-no change. - * dest_addr_adj [ 4 : 5 ] - 00-increment, 01-decrement, - * 10-no change. - * source_reload_en [ 6 ] - reload source address at the end of - * block transfer - * 0-disable, 1-enable. - * dest_reload_en [ 7 ] - reload destination address at the end - * of block transfer - * 0-disable, 1-enable. - * fifo_mode_control [ 8 : 11 ] - How full of the fifo before transfer - * start. HW specific. - * flow_control_mode [ 12 ] - 0-source request served upon data - * availability. - * 1-source request postponed until - * destination request happens. - * reserved [ 13 : 15 ] + * Aside from source address, destination address, and block size many of these options are hardware + * and driver dependent. */ struct dma_block_config { #ifdef CONFIG_DMA_64BIT + /** block starting address at source */ uint64_t source_address; + /** block starting address at destination */ uint64_t dest_address; #else + /** block starting address at source */ uint32_t source_address; + /** block starting address at destination */ uint32_t dest_address; #endif + /** Address adjustment at gather boundary */ uint32_t source_gather_interval; + /** Address adjustment at scatter boundary */ uint32_t dest_scatter_interval; + /** Continuous transfer count between scatter boundaries */ uint16_t dest_scatter_count; + /** Continuous transfer count between gather boundaries */ uint16_t source_gather_count; + /** Number of bytes to be transferred for this block */ uint32_t block_size; + /** Pointer to next block in a transfer list */ struct dma_block_config *next_block; + /** Enable source gathering when set to 1 */ uint16_t source_gather_en : 1; + /** Enable destination scattering when set to 1 */ uint16_t dest_scatter_en : 1; + /** + * Source address adjustment option + * + * - 0b00 increment + * - 0b01 decrement + * - 0b10 no change + */ uint16_t source_addr_adj : 2; + /** + * Destination address adjustment + * + * - 0b00 increment + * - 0b01 decrement + * - 0b10 no change + */ uint16_t dest_addr_adj : 2; + /** Reload source address at the end of block transfer */ uint16_t source_reload_en : 1; + /** Reload destination address at the end of block transfer */ uint16_t dest_reload_en : 1; + /** FIFO fill before starting transfer, HW specific meaning */ uint16_t fifo_mode_control : 4; + /** + * Transfer flow control mode + * + * - 0b0 source request service upon data availability + * - 0b1 source request postponed until destination request happens + */ uint16_t flow_control_mode : 1; - uint16_t reserved : 3; + + uint16_t _reserved : 3; }; +/** The DMA callback event has occurred at the completion of a transfer list */ #define DMA_STATUS_COMPLETE 0 +/** The DMA callback has occurred at the completion of a single transfer block in a transfer list */ #define DMA_STATUS_BLOCK 1 /** @@ -151,10 +179,11 @@ struct dma_block_config { * @param dev Pointer to the DMA device calling the callback. * @param user_data A pointer to some user data or NULL * @param channel The channel number - * @param status - 0-DMA_STATUS_COMPLETE buffer fully consumed - * - 1-DMA_STATUS_BLOCK buffer consumption reached a configured block + * @param status Status of the transfer + * - DMA_STATUS_COMPLETE buffer fully consumed + * - DMA_STATUS_BLOCK buffer consumption reached a configured block * or water mark - * - a negative errno otherwise + * - A negative errno otherwise */ typedef void (*dma_callback_t)(const struct device *dev, void *user_data, uint32_t channel, int status); @@ -162,86 +191,99 @@ typedef void (*dma_callback_t)(const struct device *dev, void *user_data, /** * @struct dma_config * @brief DMA configuration structure. - * - * @param dma_slot [ 0 : 7 ] - which peripheral and direction - * (HW specific) - * @param channel_direction [ 8 : 10 ] - 000-memory to memory, - * 001-memory to peripheral, - * 010-peripheral to memory, - * 011-peripheral to peripheral, - * 100-host to memory - * 101-memory to host - * ... - * @param complete_callback_en [ 11 ] - 0-callback invoked at completion only - * 1-callback invoked at completion of - * each block - * @param error_callback_en [ 12 ] - 0-error callback enabled - * 1-error callback disabled - * @param source_handshake [ 13 ] - 0-HW, 1-SW - * @param dest_handshake [ 14 ] - 0-HW, 1-SW - * @param channel_priority [ 15 : 18 ] - DMA channel priority - * @param source_chaining_en [ 19 ] - enable/disable source block chaining - * 0-disable, 1-enable - * @param dest_chaining_en [ 20 ] - enable/disable destination block - * chaining. - * 0-disable, 1-enable - * @param linked_channel [ 21 : 27 ] - after channel count exhaust will - * initiate a channel service request - * at this channel - * @param cyclic [ 28 ] - enable/disable cyclic buffer - * 0-disable, 1-enable - * @param reserved [ 29 : 31 ] - * @param source_data_size [ 0 : 15 ] - width of source data (in bytes) - * @param dest_data_size [ 16 : 31 ] - width of dest data (in bytes) - * @param source_burst_length [ 0 : 15 ] - number of source data units - * @param dest_burst_length [ 16 : 31 ] - number of destination data units - * @param block_count is the number of blocks used for block chaining, this - * depends on availability of the DMA controller. - * @param user_data private data from DMA client. - * @param dma_callback see dma_callback_t for details */ struct dma_config { + /** Which peripheral and direction, HW specific */ uint32_t dma_slot : 8; + /** + * Direction the transfers are occurring + * + * - 0b000 memory to memory, + * - 0b001 memory to peripheral, + * - 0b010 peripheral to memory, + * - 0b011 peripheral to peripheral, + * - 0b100 host to memory + * - 0b101 memory to host + * - others hardware specific + */ uint32_t channel_direction : 3; + /** + * Completion callback enable + * + * - 0b0 callback invoked at transfer list completion only + * - 0b1 callback invoked at completion of each block + */ uint32_t complete_callback_en : 1; + /** + * Error callback enable + * + * - 0b0 error callback enabled + * - 0b1 error callback disabled + */ uint32_t error_callback_en : 1; + /** + * Source handshake, HW specific + * + * - 0b0 HW + * - 0b1 SW + */ uint32_t source_handshake : 1; + /** + * Destination handshake, HW specific + * + * - 0b0 HW + * - 0b1 SW + */ uint32_t dest_handshake : 1; + /** + * Channel priority for arbitration, HW specific + */ uint32_t channel_priority : 4; + /** Source chaining enable, HW specific */ uint32_t source_chaining_en : 1; + /** Destination chaining enable, HW specific */ uint32_t dest_chaining_en : 1; + /** Linked channel, HW specific */ uint32_t linked_channel : 7; + /** Cyclic transfer list, HW specific */ uint32_t cyclic : 1; - uint32_t reserved : 3; + + uint32_t _reserved : 3; + /** Width of source data (in bytes) */ uint32_t source_data_size : 16; + /** Width of destination data (in bytes) */ uint32_t dest_data_size : 16; + /** Source burst length in bytes */ uint32_t source_burst_length : 16; + /** Destination burst length in bytes */ uint32_t dest_burst_length : 16; + /** Number of blocks in transfer list */ uint32_t block_count; + /** Pointer to the first block in the transfer list */ struct dma_block_config *head_block; + /** Optional attached user data for callbacks */ void *user_data; + /** Optional callback for completion and error events */ dma_callback_t dma_callback; }; /** * DMA runtime status structure - * - * busy - is current DMA transfer busy or idle - * dir - DMA transfer direction - * pending_length - data length pending to be transferred in bytes - * or platform dependent. - * free - free buffer space - * write_position - write position in a circular dma buffer - * read_position - read position in a circular dma buffer - * */ struct dma_status { + /** Is the current DMA transfer busy or idle */ bool busy; + /** Direction fo the transfer */ enum dma_channel_direction dir; + /** Pending length to be transferred in bytes, HW specific */ uint32_t pending_length; + /** Available buffers space, HW specific */ uint32_t free; + /** Write position in circular DMA buffer, HW specific */ uint32_t write_position; + /** Read position in circular DMA buffer, HW specific */ uint32_t read_position; + /** Total copied, HW specific */ uint64_t total_copied; }; @@ -249,19 +291,17 @@ struct dma_status { * DMA context structure * Note: the dma_context shall be the first member * of DMA client driver Data, got by dev->data - * - * magic - magic code to identify the context - * dma_channels - dma channels - * atomic - driver atomic_t pointer - * */ struct dma_context { + /** magic code to identify the context */ int32_t magic; + /** number of dma channels */ int dma_channels; + /** atomic holding bit flags for each channel to mark as used/unused */ atomic_t *atomic; }; -/* magic code to identify context content */ +/** Magic code to identify context content */ #define DMA_MAGIC 0x47494749 /** @@ -386,6 +426,8 @@ static inline int dma_reload(const struct device *dev, uint32_t channel, * Start is allowed on channels that have already been started and must report * success. * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param channel Numeric identification of the channel where the transfer will * be processed @@ -412,6 +454,8 @@ static inline int z_impl_dma_start(const struct device *dev, uint32_t channel) * Stop is allowed on channels that have already been stopped and must report * success. * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param channel Numeric identification of the channel where the transfer was * being processed @@ -436,6 +480,8 @@ static inline int z_impl_dma_stop(const struct device *dev, uint32_t channel) * Implementations must check the validity of the channel state and ID passed * in and return -EINVAL if either are invalid. * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param channel Numeric identification of the channel to suspend * @@ -462,6 +508,8 @@ static inline int z_impl_dma_suspend(const struct device *dev, uint32_t channel) * Implementations must check the validity of the channel state and ID passed * in and return -EINVAL if either are invalid. * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param channel Numeric identification of the channel to resume * @@ -488,6 +536,8 @@ static inline int z_impl_dma_resume(const struct device *dev, uint32_t channel) * request DMA channel resources * return -EINVAL if there is no valid channel available. * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param filter_param filter function parameter * @@ -531,6 +581,8 @@ static inline int z_impl_dma_request_channel(const struct device *dev, * * release DMA channel resources * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param channel channel number * @@ -587,6 +639,8 @@ static inline int z_impl_dma_chan_filter(const struct device *dev, * Implementations must check the validity of the channel ID passed in and * return -EINVAL if it is invalid or -ENOSYS if not supported. * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param channel Numeric identification of the channel where the transfer was * being processed @@ -616,6 +670,8 @@ static inline int dma_get_status(const struct device *dev, uint32_t channel, * Implementations must check the validity of the type passed in and * return -EINVAL if it is invalid or -ENOSYS if not supported. * + * @funcprops \isr_ok + * * @param dev Pointer to the device structure for the driver instance. * @param type Numeric identification of the attribute * @param value A non-NULL pointer to the variable where the read value is to be placed @@ -637,7 +693,7 @@ static inline int dma_get_attribute(const struct device *dev, uint32_t type, uin /** * @brief Look-up generic width index to be used in registers * - * WARNING: This look-up works for most controllers, but *may* not work for + * @warning This look-up works for most controllers, but *may* not work for * yours. Ensure your controller expects the most common register * bit values before using this convenience function. If your * controller does not support these values, you will have to write @@ -666,7 +722,7 @@ static inline uint32_t dma_width_index(uint32_t size) /** * @brief Look-up generic burst index to be used in registers * - * WARNING: This look-up works for most controllers, but *may* not work for + * @warning This look-up works for most controllers, but *may* not work for * yours. Ensure your controller expects the most common register * bit values before using this convenience function. If your * controller does not support these values, you will have to write @@ -693,7 +749,7 @@ static inline uint32_t dma_burst_index(uint32_t burst) } /** - * Get the device tree property describing the buffer address alignment + * @brief Get the device tree property describing the buffer address alignment * * Useful when statically defining or allocating buffers for DMA usage where * memory alignment often matters. @@ -704,7 +760,7 @@ static inline uint32_t dma_burst_index(uint32_t burst) #define DMA_BUF_ADDR_ALIGNMENT(node) DT_PROP(node, dma_buf_addr_alignment) /** - * Get the device tree property describing the buffer size alignment + * @brief Get the device tree property describing the buffer size alignment * * Useful when statically defining or allocating buffers for DMA usage where * memory alignment often matters. @@ -715,7 +771,7 @@ static inline uint32_t dma_burst_index(uint32_t burst) #define DMA_BUF_SIZE_ALIGNMENT(node) DT_PROP(node, dma_buf_size_alignment) /** - * Get the device tree property describing the minimal chunk of data possible to be copied + * @brief Get the device tree property describing the minimal chunk of data possible to be copied * * @param node Node identifier, e.g. DT_NODELABEL(dma_0) * @return minimal Minimal chunk of data possible to be copied diff --git a/include/zephyr/drivers/dma/dma_intel_lpss.h b/include/zephyr/drivers/dma/dma_intel_lpss.h index c3cf3bef81e4fe4..8ef05b688f953c5 100644 --- a/include/zephyr/drivers/dma/dma_intel_lpss.h +++ b/include/zephyr/drivers/dma/dma_intel_lpss.h @@ -7,7 +7,6 @@ #ifndef ZEPHYR_INCLUDE_DRIVERS_DMA_INTEL_LPSS_H_ #define ZEPHYR_INCLUDE_DRIVERS_DMA_INTEL_LPSS_H_ -#define DMA_INTEL_LPSS_INIT_PRIORITY 80 #define DMA_INTEL_LPSS_OFFSET 0x800 #define DMA_INTEL_LPSS_REMAP_LOW 0x240 #define DMA_INTEL_LPSS_REMAP_HI 0x244 @@ -16,5 +15,7 @@ #define DMA_INTEL_LPSS_ADDR_RIGHT_SHIFT 32 void dma_intel_lpss_isr(const struct device *dev); +int dma_intel_lpss_setup(const struct device *dev); +void dma_intel_lpss_set_base(const struct device *dev, uintptr_t base); #endif /* ZEPHYR_INCLUDE_DRIVERS_DMA_INTEL_LPSS_H_ */ diff --git a/include/zephyr/drivers/dma/dma_mcux_lpc.h b/include/zephyr/drivers/dma/dma_mcux_lpc.h new file mode 100644 index 000000000000000..5bae1f8f39e920c --- /dev/null +++ b/include/zephyr/drivers/dma/dma_mcux_lpc.h @@ -0,0 +1,56 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_DMA_DMA_MCUX_LPC_H_ +#define ZEPHYR_INCLUDE_DRIVERS_DMA_DMA_MCUX_LPC_H_ + +/* + * LPC DMA engine channel hardware trigger attributes. + * These attributes can be set to the "dma_slot" field + * in a dma_config structure to configure a channel for + * hardware triggering. + */ + +/* Peripheral request enable. When set, the peripheral + * request line associated with this channel is used to pace DMA transfers. + */ +#define LPC_DMA_PERIPH_REQ_EN BIT(0) + +/* Hardware trigger enable. When set, the hardware trigger connected to this + * channel via INPUTMUX can be used to trigger a transfer + */ +#define LPC_DMA_HWTRIG_EN BIT(1) + +/* HW trigger polarity. When this bit is set, the trigger will be active + * high or rising edge triggered, based on TRIG_TYPE selection + */ +#define LPC_DMA_TRIGPOL_HIGH_RISING BIT(2) + +/* HW trigger type. When this bit is set, the trigger will be level triggered. + * When it is cleared, the hardware trigger will be edge triggered. + */ +#define LPC_DMA_TRIGTYPE_LEVEL BIT(3) + +/* HW trigger burst mode. When set, the hardware trigger will cause a burst + * transfer to occur, the length of which is determined by BURST_POWER. + * When cleared, a single transfer (of the width selected by XFERCFG register) + * will occur. + */ +#define LPC_DMA_TRIGBURST BIT(4) + +/* HW trigger burst power. Note that due to the size limit of the dma_slot + * field, the maximum transfer burst possible is 128. The hardware supports + * up to 1024 transfers in BURSTPOWER. The value set here will result in + * 2^BURSTPOWER transfers occurring. So for BURSTPOWER=3, 8 transfers would + * occur. + */ +#define LPC_DMA_BURSTPOWER(pwr) (((pwr) & 0x7) << 5) + + +/* Used by driver to extract burstpower setting */ +#define LPC_DMA_GET_BURSTPOWER(slot) (((slot) & 0xE0) >> 5) + +#endif /* ZEPHYR_INCLUDE_DRIVERS_DMA_DMA_MCUX_LPC_H_ */ diff --git a/include/zephyr/drivers/dma/dma_smartbond.h b/include/zephyr/drivers/dma/dma_smartbond.h new file mode 100644 index 000000000000000..c154488039d87f9 --- /dev/null +++ b/include/zephyr/drivers/dma/dma_smartbond.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef DMA_SMARTBOND_H_ +#define DMA_SMARTBOND_H_ + +/** + * @brief Vendror-specific DMA peripheral triggering sources. + * + * A valid triggering source should be provided when DMA + * is configured for peripheral to peripheral or memory to peripheral + * transactions. + */ +enum dma_smartbond_trig_mux { + DMA_SMARTBOND_TRIG_MUX_SPI = 0x0, + DMA_SMARTBOND_TRIG_MUX_SPI2 = 0x1, + DMA_SMARTBOND_TRIG_MUX_UART = 0x2, + DMA_SMARTBOND_TRIG_MUX_UART2 = 0x3, + DMA_SMARTBOND_TRIG_MUX_I2C = 0x4, + DMA_SMARTBOND_TRIG_MUX_I2C2 = 0x5, + DMA_SMARTBOND_TRIG_MUX_USB = 0x6, + DMA_SMARTBOND_TRIG_MUX_UART3 = 0x7, + DMA_SMARTBOND_TRIG_MUX_PCM = 0x8, + DMA_SMARTBOND_TRIG_MUX_SRC = 0x9, + DMA_SMARTBOND_TRIG_MUX_GPADC = 0xC, + DMA_SMARTBOND_TRIG_MUX_SDADC = 0xD, + DMA_SMARTBOND_TRIG_MUX_NONE = 0xF +}; + +#endif /* DMA_SMARTBOND_H_ */ diff --git a/include/zephyr/drivers/dma/dma_stm32.h b/include/zephyr/drivers/dma/dma_stm32.h index 3ccfeb9be10550f..c4c593457cb516d 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/edac.h b/include/zephyr/drivers/edac.h index 34dcb730dc3668d..bbdd304bb8e2b3c 100644 --- a/include/zephyr/drivers/edac.h +++ b/include/zephyr/drivers/edac.h @@ -16,8 +16,6 @@ #include -typedef void (*edac_notify_callback_f)(const struct device *dev, void *data); - /** * @defgroup edac EDAC API * @ingroup io_interfaces @@ -34,6 +32,14 @@ enum edac_error_type { EDAC_ERROR_TYPE_DRAM_UC = BIT(1) }; +/** + * @cond INTERNAL_HIDDEN + * + * For internal use only, skip these in public documentation. + */ + +typedef void (*edac_notify_callback_f)(const struct device *dev, void *data); + /** * @brief EDAC driver API * @@ -64,7 +70,16 @@ __subsystem struct edac_driver_api { edac_notify_callback_f cb); }; -/* Optional interfaces */ +/** + * INTERNAL_HIDDEN @endcond + */ + +/** + * @name Optional interfaces + * @{ + * + * EDAC Optional Interfaces + */ /** * @brief Set injection parameter param1 @@ -231,7 +246,14 @@ static inline int edac_inject_error_trigger(const struct device *dev) return api->inject_error_trigger(dev); } -/* Mandatory interfaces */ +/** @} */ /* End of EDAC Optional Interfaces */ + +/** + * @name Mandatory interfaces + * @{ + * + * EDAC Mandatory Interfaces + */ /** * @brief Get ECC Error Log @@ -388,8 +410,9 @@ static inline int edac_notify_callback_set(const struct device *dev, return api->notify_cb_set(dev, cb); } -/** - * @} - */ + +/** @} */ /* End of EDAC Mandatory Interfaces */ + +/** @} */ /* End of EDAC API */ #endif /* ZEPHYR_INCLUDE_DRIVERS_EDAC_H_ */ diff --git a/include/zephyr/drivers/eeprom.h b/include/zephyr/drivers/eeprom.h index 2494d3e67549f1a..7da3d2a079d7466 100644 --- a/include/zephyr/drivers/eeprom.h +++ b/include/zephyr/drivers/eeprom.h @@ -32,11 +32,31 @@ extern "C" { #endif +/** + * @cond INTERNAL_HIDDEN + * + * For internal driver use only, skip these in public documentation. + */ + +/** + * @brief Callback API upon reading from the EEPROM. + * See @a eeprom_read() for argument description + */ typedef int (*eeprom_api_read)(const struct device *dev, off_t offset, void *data, size_t len); + +/** + * @brief Callback API upon writing to the EEPROM. + * See @a eeprom_write() for argument description + */ typedef int (*eeprom_api_write)(const struct device *dev, off_t offset, const void *data, size_t len); + +/** + * @brief Callback API upon getting the EEPROM size. + * See @a eeprom_get_size() for argument description + */ typedef size_t (*eeprom_api_size)(const struct device *dev); __subsystem struct eeprom_driver_api { @@ -45,6 +65,8 @@ __subsystem struct eeprom_driver_api { eeprom_api_size size; }; +/** @endcond */ + /** * @brief Read data from EEPROM * diff --git a/include/zephyr/drivers/emul.h b/include/zephyr/drivers/emul.h index 9ef6fb9ada5c818..01297666dac48ff 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 * @@ -191,11 +213,9 @@ const struct emul *emul_get_binding(const char *name); * @} */ -#if defined(CONFIG_HAS_DTS) || defined(__DOXYGEN__) #define Z_MAYBE_EMUL_DECLARE_INTERNAL(node_id) extern const struct emul EMUL_DT_NAME_GET(node_id); DT_FOREACH_STATUS_OKAY_NODE(Z_MAYBE_EMUL_DECLARE_INTERNAL); -#endif /* CONFIG_HAS_DTS || __DOXYGEN__ */ #ifdef __cplusplus } diff --git a/include/zephyr/drivers/emul_bbram.h b/include/zephyr/drivers/emul_bbram.h new file mode 100644 index 000000000000000..441f101c934a963 --- /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 44a497ee4019b57..30345cc6a0bc227 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/entropy.h b/include/zephyr/drivers/entropy.h index 9bf4f37c3a83ee5..1e1573d29a817e9 100644 --- a/include/zephyr/drivers/entropy.h +++ b/include/zephyr/drivers/entropy.h @@ -29,6 +29,9 @@ extern "C" { #endif +/** @brief Driver is allowed to busy-wait for random data to be ready */ +#define ENTROPY_BUSYWAIT BIT(0) + /** * @typedef entropy_get_entropy_t * @brief Callback API to get entropy. @@ -51,6 +54,12 @@ typedef int (*entropy_get_entropy_isr_t)(const struct device *dev, uint8_t *buffer, uint16_t length, uint32_t flags); + +/** + * @brief Entropy driver API structure. + * + * This is the mandatory API any Entropy driver needs to expose. + */ __subsystem struct entropy_driver_api { entropy_get_entropy_t get_entropy; entropy_get_entropy_isr_t get_entropy_isr; @@ -82,9 +91,6 @@ static inline int z_impl_entropy_get_entropy(const struct device *dev, return api->get_entropy(dev, buffer, length); } -/* Busy-wait for random data to be ready */ -#define ENTROPY_BUSYWAIT BIT(0) - /** * @brief Fills a buffer with entropy in a non-blocking or busy-wait manner. * Callable from ISRs. diff --git a/include/zephyr/drivers/espi_saf.h b/include/zephyr/drivers/espi_saf.h index 9c6f47d1590254f..31fc23c0808ee5e 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 000000000000000..767acbea09e2750 --- /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/include/zephyr/drivers/flash.h b/include/zephyr/drivers/flash.h index de5e7c2116e0379..ae24ac96a7503cf 100644 --- a/include/zephyr/drivers/flash.h +++ b/include/zephyr/drivers/flash.h @@ -471,6 +471,16 @@ __syscall int flash_ex_op(const struct device *dev, uint16_t code, #define FLASH_EX_OP_VENDOR_BASE 0x8000 #define FLASH_EX_OP_IS_VENDOR(c) ((c) & FLASH_EX_OP_VENDOR_BASE) +/** + * @brief Enumeration for extra flash operations + */ +enum flash_ex_op_types { + /* + * Reset flash device. + */ + FLASH_EX_OP_RESET = 0, +}; + static inline int z_impl_flash_ex_op(const struct device *dev, uint16_t code, const uintptr_t in, void *out) { diff --git a/include/zephyr/drivers/gnss.h b/include/zephyr/drivers/gnss.h new file mode 100644 index 000000000000000..4c25bd84a435dfb --- /dev/null +++ b/include/zephyr/drivers/gnss.h @@ -0,0 +1,496 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file gnss.h + * @brief Public GNSS API. + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_GNSS_H_ +#define ZEPHYR_INCLUDE_DRIVERS_GNSS_H_ + +/** + * @brief GNSS Interface + * @defgroup gnss_interface GNSS Interface + * @ingroup io_interfaces + * @{ + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** GNSS PPS modes */ +enum gnss_pps_mode { + /** PPS output disabled */ + GNSS_PPS_MODE_DISABLED = 0, + /** PPS output always enabled */ + GNSS_PPS_MODE_ENABLED = 1, + /** PPS output enabled from first lock */ + GNSS_PPS_MODE_ENABLED_AFTER_LOCK = 2, + /** PPS output enabled while locked */ + GNSS_PPS_MODE_ENABLED_WHILE_LOCKED = 3 +}; + +/** API for setting fix rate */ +typedef int (*gnss_set_fix_rate_t)(const struct device *dev, uint32_t fix_interval_ms); + +/** API for getting fix rate */ +typedef int (*gnss_get_fix_rate_t)(const struct device *dev, uint32_t *fix_interval_ms); + +/** + * @brief GNSS periodic tracking configuration + * + * @note Setting either active_time or inactive_time to 0 will disable periodic + * function. + */ +struct gnss_periodic_config { + /** The time the GNSS will spend in the active state in ms */ + uint32_t active_time_ms; + /** The time the GNSS will spend in the inactive state in ms */ + uint32_t inactive_time_ms; +}; + +/** API for setting periodic tracking configuration */ +typedef int (*gnss_set_periodic_config_t)(const struct device *dev, + const struct gnss_periodic_config *periodic_config); + +/** API for setting periodic tracking configuration */ +typedef int (*gnss_get_periodic_config_t)(const struct device *dev, + struct gnss_periodic_config *periodic_config); + +/** GNSS navigation modes */ +enum gnss_navigation_mode { + /** Dynamics have no impact on tracking */ + GNSS_NAVIGATION_MODE_ZERO_DYNAMICS = 0, + /** Low dynamics have higher impact on tracking */ + GNSS_NAVIGATION_MODE_LOW_DYNAMICS = 1, + /** Low and high dynamics have equal impact on tracking */ + GNSS_NAVIGATION_MODE_BALANCED_DYNAMICS = 2, + /** High dynamics have higher impact on tracking */ + GNSS_NAVIGATION_MODE_HIGH_DYNAMICS = 3 +}; + +/** API for setting navigation mode */ +typedef int (*gnss_set_navigation_mode_t)(const struct device *dev, + enum gnss_navigation_mode mode); + +/** API for getting navigation mode */ +typedef int (*gnss_get_navigation_mode_t)(const struct device *dev, + enum gnss_navigation_mode *mode); + +/** Systems contained in gnss_systems_t */ +enum gnss_system { + /** Global Positioning System (GPS) */ + GNSS_SYSTEM_GPS = BIT(0), + /** GLObal NAvigation Satellite System (GLONASS) */ + GNSS_SYSTEM_GLONASS = BIT(1), + /** Galileo */ + GNSS_SYSTEM_GALILEO = BIT(2), + /** BeiDou Navigation Satellite System */ + GNSS_SYSTEM_BEIDOU = BIT(3), + /** Quasi-Zenith Satellite System (QZSS) */ + GNSS_SYSTEM_QZSS = BIT(4), + /** Indian Regional Navigation Satellite System (IRNSS) */ + GNSS_SYSTEM_IRNSS = BIT(5), + /** Satellite-Based Augmentation System (SBAS) */ + GNSS_SYSTEM_SBAS = BIT(6), + /** Indoor Messaging System (IMES) */ + GNSS_SYSTEM_IMES = BIT(7), +}; + +/** Type storing bitmask of GNSS systems */ +typedef uint32_t gnss_systems_t; + +/** API for enabling systems */ +typedef int (*gnss_set_enabled_systems_t)(const struct device *dev, gnss_systems_t systems); + +/** API for getting enabled systems */ +typedef int (*gnss_get_enabled_systems_t)(const struct device *dev, gnss_systems_t *systems); + +/** API for getting enabled systems */ +typedef int (*gnss_get_supported_systems_t)(const struct device *dev, gnss_systems_t *systems); + +/** GNSS fix status */ +enum gnss_fix_status { + /** No GNSS fix aqcuired */ + GNSS_FIX_STATUS_NO_FIX = 0, + /** GNSS fix aqcuired */ + GNSS_FIX_STATUS_GNSS_FIX = 1, + /** Differential GNSS fix acquired */ + GNSS_FIX_STATUS_DGNSS_FIX = 2, + /** Estimated fix acquired */ + GNSS_FIX_STATUS_ESTIMATED_FIX = 3, +}; + +/** GNSS fix quality */ +enum gnss_fix_quality { + /** Invalid fix */ + GNSS_FIX_QUALITY_INVALID = 0, + /** Standard positioning service */ + GNSS_FIX_QUALITY_GNSS_SPS = 1, + /** Differential GNSS */ + GNSS_FIX_QUALITY_DGNSS = 2, + /** Precise positioning service */ + GNSS_FIX_QUALITY_GNSS_PPS = 3, + /** Real-time kinematic */ + GNSS_FIX_QUALITY_RTK = 4, + /** Floating real-time kinematic */ + GNSS_FIX_QUALITY_FLOAT_RTK = 5, + /** Estimated fix */ + GNSS_FIX_QUALITY_ESTIMATED = 6, +}; + +/** GNSS info data structure */ +struct gnss_info { + /** Number of satellites being tracked */ + uint16_t satellites_cnt; + /** Horizontal dilution of precision in 1/1000 */ + uint16_t hdop; + /** The fix status */ + enum gnss_fix_status fix_status; + /** The fix quality */ + enum gnss_fix_quality fix_quality; +}; + +/** GNSS time data structure */ +struct gnss_time { + /** Hour [0, 23] */ + uint8_t hour; + /** Minute [0, 59] */ + uint8_t minute; + /** Millisecond [0, 59999] */ + uint16_t millisecond; + /** Day of month [1, 31] */ + uint8_t month_day; + /** Month [1, 12] */ + uint8_t month; + /** Year [0, 99] */ + uint8_t century_year; +}; + +/** GNSS API structure */ +__subsystem struct gnss_driver_api { + gnss_set_fix_rate_t set_fix_rate; + gnss_get_fix_rate_t get_fix_rate; + gnss_set_periodic_config_t set_periodic_config; + gnss_get_periodic_config_t get_periodic_config; + gnss_set_navigation_mode_t set_navigation_mode; + gnss_get_navigation_mode_t get_navigation_mode; + gnss_set_enabled_systems_t set_enabled_systems; + gnss_get_enabled_systems_t get_enabled_systems; + gnss_get_supported_systems_t get_supported_systems; +}; + +/** GNSS data structure */ +struct gnss_data { + /** Navigation data acquired */ + struct navigation_data nav_data; + /** GNSS info when navigation data was acquired */ + struct gnss_info info; + /** UTC time when data was acquired */ + struct gnss_time utc; +}; + +/** Template for GNSS data callback */ +typedef void (*gnss_data_callback_t)(const struct device *dev, const struct gnss_data *data); + +/** GNSS callback structure */ +struct gnss_data_callback { + /** Filter callback to GNSS data from this device if not NULL */ + const struct device *dev; + /** Callback called when GNSS data is published */ + gnss_data_callback_t callback; +}; + +/** GNSS satellite structure */ +struct gnss_satellite { + /** Pseudo-random noise sequence */ + uint8_t prn; + /** Signal-to-noise ratio in dB */ + uint8_t snr; + /** Elevation in degrees [0, 90] */ + uint8_t elevation; + /** Azimuth relative to True North in degrees [0, 359] */ + uint16_t azimuth; + /** System of satellite */ + enum gnss_system system; + /** True if satellite is being tracked */ + uint8_t is_tracked : 1; +}; + +/** Template for GNSS satellites callback */ +typedef void (*gnss_satellites_callback_t)(const struct device *dev, + const struct gnss_satellite *satellites, + uint16_t size); + +/** GNSS callback structure */ +struct gnss_satellites_callback { + /** Filter callback to GNSS data from this device if not NULL */ + const struct device *dev; + /** Callback called when GNSS satellites is published */ + gnss_satellites_callback_t callback; +}; + +/** + * @brief Set the GNSS fix rate + * + * @param dev Device instance + * @param fix_interval_ms Fix interval to set in milliseconds + * + * @return 0 if successful + * @return -errno negative errno code on failure + */ +__syscall int gnss_set_fix_rate(const struct device *dev, uint32_t fix_interval_ms); + +static inline int z_impl_gnss_set_fix_rate(const struct device *dev, uint32_t fix_interval_ms) +{ + const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api; + + if (api->set_fix_rate == NULL) { + return -ENOSYS; + } + + return api->set_fix_rate(dev, fix_interval_ms); +} + +/** + * @brief Get the GNSS fix rate + * + * @param dev Device instance + * @param fix_interval_ms Destination for fix interval in milliseconds + * + * @return 0 if successful + * @return -errno negative errno code on failure + */ +__syscall int gnss_get_fix_rate(const struct device *dev, uint32_t *fix_interval_ms); + +static inline int z_impl_gnss_get_fix_rate(const struct device *dev, uint32_t *fix_interval_ms) +{ + const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api; + + if (api->get_fix_rate == NULL) { + return -ENOSYS; + } + + return api->get_fix_rate(dev, fix_interval_ms); +} + +/** + * @brief Set the GNSS periodic tracking configuration + * + * @param dev Device instance + * @param config Periodic tracking configuration to set + * + * @return 0 if successful + * @return -errno negative errno code on failure + */ +__syscall int gnss_set_periodic_config(const struct device *dev, + const struct gnss_periodic_config *config); + +static inline int z_impl_gnss_set_periodic_config(const struct device *dev, + const struct gnss_periodic_config *config) +{ + const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api; + + if (api->set_periodic_config == NULL) { + return -ENOSYS; + } + + return api->set_periodic_config(dev, config); +} + +/** + * @brief Get the GNSS periodic tracking configuration + * + * @param dev Device instance + * @param config Destination for periodic tracking configuration + * + * @return 0 if successful + * @return -errno negative errno code on failure + */ +__syscall int gnss_get_periodic_config(const struct device *dev, + struct gnss_periodic_config *config); + +static inline int z_impl_gnss_get_periodic_config(const struct device *dev, + struct gnss_periodic_config *config) +{ + const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api; + + if (api->get_periodic_config == NULL) { + return -ENOSYS; + } + + return api->get_periodic_config(dev, config); +} + +/** + * @brief Set the GNSS navigation mode + * + * @param dev Device instance + * @param mode Navigation mode to set + * + * @return 0 if successful + * @return -errno negative errno code on failure + */ +__syscall int gnss_set_navigation_mode(const struct device *dev, + enum gnss_navigation_mode mode); + +static inline int z_impl_gnss_set_navigation_mode(const struct device *dev, + enum gnss_navigation_mode mode) +{ + const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api; + + if (api->set_navigation_mode == NULL) { + return -ENOSYS; + } + + return api->set_navigation_mode(dev, mode); +} + +/** + * @brief Get the GNSS navigation mode + * + * @param dev Device instance + * @param mode Destination for navigation mode + * + * @return 0 if successful + * @return -errno negative errno code on failure + */ +__syscall int gnss_get_navigation_mode(const struct device *dev, + enum gnss_navigation_mode *mode); + +static inline int z_impl_gnss_get_navigation_mode(const struct device *dev, + enum gnss_navigation_mode *mode) +{ + const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api; + + if (api->get_navigation_mode == NULL) { + return -ENOSYS; + } + + return api->get_navigation_mode(dev, mode); +} + +/** + * @brief Set enabled GNSS systems + * + * @param dev Device instance + * @param systems Systems to enable + * + * @return 0 if successful + * @return -errno negative errno code on failure + */ +__syscall int gnss_set_enabled_systems(const struct device *dev, gnss_systems_t systems); + +static inline int z_impl_gnss_set_enabled_systems(const struct device *dev, + gnss_systems_t systems) +{ + const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api; + + if (api->set_enabled_systems == NULL) { + return -ENOSYS; + } + + return api->set_enabled_systems(dev, systems); +} + +/** + * @brief Get enabled GNSS systems + * + * @param dev Device instance + * @param systems Destination for enabled systems + * + * @return 0 if successful + * @return -errno negative errno code on failure + */ +__syscall int gnss_get_enabled_systems(const struct device *dev, gnss_systems_t *systems); + +static inline int z_impl_gnss_get_enabled_systems(const struct device *dev, + gnss_systems_t *systems) +{ + const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api; + + if (api->get_enabled_systems == NULL) { + return -ENOSYS; + } + + return api->get_enabled_systems(dev, systems); +} + +/** + * @brief Get supported GNSS systems + * + * @param dev Device instance + * @param systems Destination for supported systems + * + * @return 0 if successful + * @return -errno negative errno code on failure + */ +__syscall int gnss_get_supported_systems(const struct device *dev, gnss_systems_t *systems); + +static inline int z_impl_gnss_get_supported_systems(const struct device *dev, + gnss_systems_t *systems) +{ + const struct gnss_driver_api *api = (const struct gnss_driver_api *)dev->api; + + if (api->get_supported_systems == NULL) { + return -ENOSYS; + } + + return api->get_supported_systems(dev, systems); +} + +/** + * @brief Register a callback structure for GNSS data published + * + * @param _dev Device pointer + * @param _callback The callback function + */ +#if CONFIG_GNSS +#define GNSS_DATA_CALLBACK_DEFINE(_dev, _callback) \ + static const STRUCT_SECTION_ITERABLE(gnss_data_callback, \ + _gnss_data_callback__##_callback) = { \ + .dev = _dev, \ + .callback = _callback, \ + } +#else +#define GNSS_DATA_CALLBACK_DEFINE(_dev, _callback) +#endif + +/** + * @brief Register a callback structure for GNSS satellites published + * + * @param _dev Device pointer + * @param _callback The callback function + */ +#if CONFIG_GNSS_SATELLITES +#define GNSS_SATELLITES_CALLBACK_DEFINE(_dev, _callback) \ + static const STRUCT_SECTION_ITERABLE(gnss_satellites_callback, \ + _gnss_satellites_callback__##_callback) = { \ + .dev = _dev, \ + .callback = _callback, \ + } +#else +#define GNSS_SATELLITES_CALLBACK_DEFINE(_dev, _callback) +#endif + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#include + +#endif /* ZEPHYR_INCLUDE_DRIVERS_GNSS_H_ */ diff --git a/include/zephyr/drivers/gnss/gnss_publish.h b/include/zephyr/drivers/gnss/gnss_publish.h new file mode 100644 index 000000000000000..b686c7eaed112da --- /dev/null +++ b/include/zephyr/drivers/gnss/gnss_publish.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_GNSS_GNSS_H_ +#define ZEPHYR_DRIVERS_GNSS_GNSS_H_ + +#include + +/** Internal function used by GNSS drivers to publish GNSS data */ +void gnss_publish_data(const struct device *dev, const struct gnss_data *data); + +/** Internal function used by GNSS drivers to publish GNSS satellites */ +void gnss_publish_satellites(const struct device *dev, const struct gnss_satellite *satellites, + uint16_t size); + +#endif /* ZEPHYR_DRIVERS_GNSS_GNSS_H_ */ diff --git a/include/zephyr/drivers/i2c.h b/include/zephyr/drivers/i2c.h index f0268322ecb1961..70cc0840db7734c 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 000000000000000..ac943d74664bf85 --- /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 dcbdd1c549617bb..4c0b86b18f54d32 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 36a93fc01de955c..a814b7d436b05c2 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/addresses.h b/include/zephyr/drivers/i3c/addresses.h index 191e7f881da9c88..c85255d8a691221 100644 --- a/include/zephyr/drivers/i3c/addresses.h +++ b/include/zephyr/drivers/i3c/addresses.h @@ -113,10 +113,11 @@ bool i3c_addr_slots_is_free(struct i3c_addr_slots *slots, * assigned to a new device. * * @param slots Pointer to the address slots structure. + * @param start_addr Where to start searching * * @return The next free address, or 0 if none found. */ -uint8_t i3c_addr_slots_next_free_find(struct i3c_addr_slots *slots); +uint8_t i3c_addr_slots_next_free_find(struct i3c_addr_slots *slots, uint8_t start_addr); /** * @brief Mark the address as free (not used) in device list. diff --git a/include/zephyr/drivers/i3c/ccc.h b/include/zephyr/drivers/i3c/ccc.h index 606d44f79aecaca..116750bcac59bcd 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 2bd41415983cab7..0bd808f921c6263 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 6c489723d7e2b59..c1e86068ad3ddf4 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 new file mode 100644 index 000000000000000..d347d81cad85ac4 --- /dev/null +++ b/include/zephyr/drivers/interrupt_controller/intc_ra_icu.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#ifndef ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_INTC_RA_ICU_H_ +#define ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_INTC_RA_ICU_H_ + +#define RA_ICU_FLAG_EVENT_OFFSET 8 +#define RA_ICU_FLAG_EVENT_MASK (BIT_MASK(8) << RA_ICU_FLAG_EVENT_OFFSET) +#define RA_ICU_FLAG_INTCFG_OFFSET 16 +#define RA_ICU_FLAG_INTCFG_MASK (BIT_MASK(8) << RA_ICU_FLAG_INTCFG_OFFSET) + +enum icu_irq_mode { + ICU_FALLING, + ICU_RISING, + ICU_BOTH_EDGE, + ICU_LOW_LEVEL, +}; + +typedef void (*ra_isr_handler)(const void *); + +extern void ra_icu_clear_int_flag(unsigned int irqn); + +extern int ra_icu_query_available_irq(uint32_t event); +extern int ra_icu_query_exists_irq(uint32_t event); + +extern void ra_icu_query_irq_config(unsigned int irq, uint32_t *intcfg, ra_isr_handler *pisr, + const void **cbarg); + +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/interrupt_controller/riscv_plic.h b/include/zephyr/drivers/interrupt_controller/riscv_plic.h index 1cec5cc810997cd..22c57a4b69673aa 100644 --- a/include/zephyr/drivers/interrupt_controller/riscv_plic.h +++ b/include/zephyr/drivers/interrupt_controller/riscv_plic.h @@ -12,24 +12,26 @@ #ifndef ZEPHYR_INCLUDE_DRIVERS_RISCV_PLIC_H_ #define ZEPHYR_INCLUDE_DRIVERS_RISCV_PLIC_H_ +#include + /** * @brief Enable interrupt * - * @param irq interrupt ID + * @param irq Multi-level encoded interrupt ID */ void riscv_plic_irq_enable(uint32_t irq); /** * @brief Disable interrupt * - * @param irq interrupt ID + * @param irq Multi-level encoded interrupt ID */ void riscv_plic_irq_disable(uint32_t irq); /** * @brief Check if an interrupt is enabled * - * @param irq interrupt ID + * @param irq Multi-level encoded interrupt ID * @return Returns true if interrupt is enabled, false otherwise */ int riscv_plic_irq_is_enabled(uint32_t irq); @@ -37,7 +39,7 @@ int riscv_plic_irq_is_enabled(uint32_t irq); /** * @brief Set interrupt priority * - * @param irq interrupt ID + * @param irq Multi-level encoded interrupt ID * @param prio interrupt priority */ void riscv_plic_set_priority(uint32_t irq, uint32_t prio); @@ -47,6 +49,13 @@ void riscv_plic_set_priority(uint32_t irq, uint32_t prio); * * @return Returns the ID of an active interrupt */ -int riscv_plic_get_irq(void); +unsigned int riscv_plic_get_irq(void); + +/** + * @brief Get active interrupt controller device + * + * @return Returns device pointer of the active interrupt device + */ +const struct device *riscv_plic_get_dev(void); #endif /* ZEPHYR_INCLUDE_DRIVERS_RISCV_PLIC_H_ */ diff --git a/include/zephyr/drivers/led.h b/include/zephyr/drivers/led.h index b9dd8cc2775d7ba..cb178a9442dd517 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 1d030c0f586f18d..9ee8deebd41d852 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/mfd/ad5592.h b/include/zephyr/drivers/mfd/ad5592.h new file mode 100644 index 000000000000000..014ccdd02baf86b --- /dev/null +++ b/include/zephyr/drivers/mfd/ad5592.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_MFD_AD5592_H_ +#define ZEPHYR_INCLUDE_DRIVERS_MFD_AD5592_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define AD5592_REG_SEQ_ADC 0x02U +#define AD5592_REG_ADC_CONFIG 0x04U +#define AD5592_REG_LDAC_EN 0x05U +#define AD5592_REG_GPIO_PULLDOWN 0x06U +#define AD5592_REG_READ_AND_LDAC 0x07U +#define AD5592_REG_GPIO_OUTPUT_EN 0x08U +#define AD5592_REG_GPIO_SET 0x09U +#define AD5592_REG_GPIO_INPUT_EN 0x0AU +#define AD5592_REG_PD_REF_CTRL 0x0BU + +#define AD5592_EN_REF BIT(9) + +#define AD5592_PIN_MAX 8U + +/** + * @defgroup mdf_interface_ad5592 MFD AD5592 interface + * @ingroup mfd_interfaces + * @{ + */ + +/** + * @brief Read raw data from the chip + * + * @param[in] dev Pointer to MFD device + * @param[in] val Pointer to data buffer + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad5592_read_raw(const struct device *dev, uint16_t *val); + +/** + * @brief Write raw data to chip + * + * @param[in] dev Pointer to MFD device + * @param[in] val Data to be written + * + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad5592_write_raw(const struct device *dev, uint16_t val); + +/** + * @brief Read data from provided register + * + * @param[in] dev Pointer to MFD device + * @param[in] reg Register to be read + * @param[in] reg_data Additional data passed to selected register + * @param[in] val Pointer to data buffer + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad5592_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, uint16_t *val); + +/** + * @brief Write data to provided register + * + * @param[in] dev Pointer to MFD device + * @param[in] reg Register to be written + * @param[in] val Data to be written + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad5592_write_reg(const struct device *dev, uint8_t reg, uint16_t val); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_MFD_AD5952_H_ */ diff --git a/include/zephyr/drivers/mfd/npm1300.h b/include/zephyr/drivers/mfd/npm1300.h index 13f6ee843651c14..b86f2f31c8fdb69 100644 --- a/include/zephyr/drivers/mfd/npm1300.h +++ b/include/zephyr/drivers/mfd/npm1300.h @@ -28,6 +28,7 @@ enum mfd_npm1300_event_t { NPM1300_EVENT_BATTERY_DETECTED, NPM1300_EVENT_BATTERY_REMOVED, NPM1300_EVENT_SHIPHOLD_PRESS, + NPM1300_EVENT_SHIPHOLD_RELEASE, NPM1300_EVENT_WATCHDOG_WARN, NPM1300_EVENT_VBUS_DETECTED, NPM1300_EVENT_VBUS_REMOVED, diff --git a/include/zephyr/drivers/mipi_dsi.h b/include/zephyr/drivers/mipi_dsi.h index 6373c1010f09a1b..e6ac1e0a787bc63 100644 --- a/include/zephyr/drivers/mipi_dsi.h +++ b/include/zephyr/drivers/mipi_dsi.h @@ -18,6 +18,7 @@ * @ingroup io_interfaces * @{ */ +#include #include #include #include @@ -217,6 +218,12 @@ struct mipi_dsi_device { uint32_t mode_flags; }; +/* + * Per message flag to indicate the message must be sent + * using Low Power Mode instead of controller default. + */ +#define MIPI_DSI_MSG_USE_LPM BIT(0x0) + /** MIPI-DSI read/write message. */ struct mipi_dsi_msg { /** Payload data type. */ @@ -241,6 +248,8 @@ __subsystem struct mipi_dsi_driver_api { const struct mipi_dsi_device *mdev); ssize_t (*transfer)(const struct device *dev, uint8_t channel, struct mipi_dsi_msg *msg); + int (*detach)(const struct device *dev, uint8_t channel, + const struct mipi_dsi_device *mdev); }; /** @@ -336,6 +345,29 @@ ssize_t mipi_dsi_dcs_read(const struct device *dev, uint8_t channel, ssize_t mipi_dsi_dcs_write(const struct device *dev, uint8_t channel, uint8_t cmd, const void *buf, size_t len); + +/** + * @brief Detach a device from the MIPI-DSI bus + * + * @param dev MIPI-DSI host device. + * @param channel Device channel (VID). + * @param mdev MIPI-DSI device description. + * + * @return 0 on success, negative on error + */ +static inline int mipi_dsi_detach(const struct device *dev, + uint8_t channel, + const struct mipi_dsi_device *mdev) +{ + const struct mipi_dsi_driver_api *api = (const struct mipi_dsi_driver_api *)dev->api; + + if (api->detach == NULL) { + return -ENOSYS; + } + + return api->detach(dev, channel, mdev); +} + #ifdef __cplusplus } #endif diff --git a/include/zephyr/drivers/misc/devmux/devmux.h b/include/zephyr/drivers/misc/devmux/devmux.h new file mode 100644 index 000000000000000..1772d719d96d652 --- /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/misc/timeaware_gpio/timeaware_gpio.h b/include/zephyr/drivers/misc/timeaware_gpio/timeaware_gpio.h index 68c305f9e1840e7..b65b697f54f3978 100644 --- a/include/zephyr/drivers/misc/timeaware_gpio/timeaware_gpio.h +++ b/include/zephyr/drivers/misc/timeaware_gpio/timeaware_gpio.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #ifdef __cplusplus extern "C" { diff --git a/include/zephyr/drivers/mm/mm_drv_bank.h b/include/zephyr/drivers/mm/mm_drv_bank.h index 9e1a51ebcbf17db..75fb57467ce9ae7 100644 --- a/include/zephyr/drivers/mm/mm_drv_bank.h +++ b/include/zephyr/drivers/mm/mm_drv_bank.h @@ -9,9 +9,10 @@ * @brief Memory Banks Driver APIs * * This contains generic APIs to be used by a system-wide memory management - * driver to track page usage within memory banks. It is incumbent upon the - * caller to ensure that proper locking is used to protect the data when - * using these APIs. + * driver to track page usage within memory banks. + * + * @note The caller of these functions needs to ensure proper locking + * to protect the data when using these APIs. */ #ifndef ZEPHYR_INCLUDE_DRIVERS_MM_DRV_BANK_H @@ -21,11 +22,31 @@ #include #include -#define SRAM_BANK_PAGE_NUM (SRAM_BANK_SIZE / CONFIG_MM_DRV_PAGE_SIZE) +/** + * @brief Memory Banks Driver APIs + * @defgroup mm_drv_bank_apis Memory Banks Driver APIs + * + * This contains APIs for a system-wide memory management driver to + * track page usage within memory banks. + * + * @note The caller of these functions needs to ensure proper locking + * to protect the data when using these APIs. + * + * @ingroup memory_management + * @{ + */ -struct mem_drv_bank { +/** + * @brief Information about memory banks. + */ +struct sys_mm_drv_bank { + /** Number of unmapped pages. */ uint32_t unmapped_pages; + + /** Number of mapped pages. */ uint32_t mapped_pages; + + /** Maximum number of mapped pages since last counter reset. */ uint32_t max_mapped_pages; }; @@ -38,10 +59,10 @@ struct mem_drv_bank { * it will start with all pages mapped. In next phase of driver initialization * unused pages will be unmapped. * - * @param bank Pointer to the memory bank structure used for tracking - * @param bank_pages Number of pages in the memory bank + * @param[in,out] bank Pointer to the memory bank structure used for tracking + * @param[in] bank_pages Number of pages in the memory bank */ -void sys_mm_drv_bank_init(struct mem_drv_bank *bank, uint32_t bank_pages); +void sys_mm_drv_bank_init(struct sys_mm_drv_bank *bank, uint32_t bank_pages); /** * @brief Track the mapping of a page in the specified memory bank @@ -49,11 +70,11 @@ void sys_mm_drv_bank_init(struct mem_drv_bank *bank, uint32_t bank_pages); * This function is used to update the number of mapped pages within the * specified memory bank. * - * @param bank Pointer to the memory bank's data structure + * @param[in,out] bank Pointer to the memory bank's data structure * * @return The number of pages mapped within the memory bank */ -uint32_t sys_mm_drv_bank_page_mapped(struct mem_drv_bank *bank); +uint32_t sys_mm_drv_bank_page_mapped(struct sys_mm_drv_bank *bank); /** * @brief Track the unmapping of a page in the specified memory bank @@ -61,11 +82,11 @@ uint32_t sys_mm_drv_bank_page_mapped(struct mem_drv_bank *bank); * This function is used to update the number of unmapped pages within the * specified memory bank. * - * @param bank Pointer to the memory bank's data structure + * @param[in,out] bank Pointer to the memory bank's data structure * * @return The number of unmapped pages within the memory bank */ -uint32_t sys_mm_drv_bank_page_unmapped(struct mem_drv_bank *bank); +uint32_t sys_mm_drv_bank_page_unmapped(struct sys_mm_drv_bank *bank); /** * @brief Reset the max number of pages mapped in the bank @@ -74,19 +95,23 @@ uint32_t sys_mm_drv_bank_page_unmapped(struct mem_drv_bank *bank); * the specified memory bank to the current number of pages mapped in * that memory bank. * - * @param bank Pointer to the memory bank's data structure + * @param[in,out] bank Pointer to the memory bank's data structure */ -void sys_mm_drv_bank_stats_reset_max(struct mem_drv_bank *bank); +void sys_mm_drv_bank_stats_reset_max(struct sys_mm_drv_bank *bank); /** * @brief Retrieve the memory usage stats for the specified memory bank * * This routine extracts the system memory stats from the memory bank. * - * @param bank Pointer to the memory bank's data structure - * @param stats Pointer to memory into which to copy the system memory stats + * @param[in] bank Pointer to the memory bank's data structure + * @param[in,out] stats Pointer to memory into which to copy the system memory stats */ -void sys_mm_drv_bank_stats_get(struct mem_drv_bank *bank, +void sys_mm_drv_bank_stats_get(struct sys_mm_drv_bank *bank, struct sys_memory_stats *stats); +/** + * @} + */ + #endif /* ZEPHYR_INCLUDE_DRIVERS_MM_DRV_BANK_H */ diff --git a/include/zephyr/drivers/mm/system_mm.h b/include/zephyr/drivers/mm/system_mm.h index c76f1097f656696..d523b706723f49f 100644 --- a/include/zephyr/drivers/mm/system_mm.h +++ b/include/zephyr/drivers/mm/system_mm.h @@ -26,12 +26,20 @@ extern "C" { /** * @brief Memory Management Driver APIs * @defgroup mm_drv_apis Memory Management Driver APIs + * + * This contains APIs for a system-wide memory management + * driver. Only one instance is permitted on the system. + * * @ingroup memory_management * @{ */ -/* - * Caching mode definitions. These are mutually exclusive. +/** + * @name Caching mode definitions. + * + * These are mutually exclusive. + * + * @{ */ /** No caching */ @@ -46,9 +54,16 @@ extern "C" { /** Reserved bits for cache modes */ #define SYS_MM_MEM_CACHE_MASK (BIT(3) - 1) -/* - * Region permission attributes. +/** + * @} + */ + +/** + * @name Region permission attributes. + * * Default should be read-only, no user, no exec. + * + * @{ */ /** Region will have read/write access (and not read-only) */ @@ -60,6 +75,18 @@ extern "C" { /** Region will be accessible to user mode (normally supervisor-only) */ #define SYS_MM_MEM_PERM_USER BIT(5) +/** + * @} + */ + +/** + * @name Memory Mapping and Unmapping + * + * On mapping and unmapping of memory. + * + * @{ + */ + /** * @brief Map one physical page into the virtual address space * @@ -177,25 +204,6 @@ int sys_mm_drv_unmap_page(void *virt); */ int sys_mm_drv_unmap_region(void *virt, size_t size); -/** - * @brief Get the mapped physical memory address from virtual address. - * - * The function queries the translation tables to find the physical - * memory address of a mapped virtual address. - * - * Behavior when providing unaligned address is undefined, this - * is assumed to be page aligned. - * - * @param virt Page-aligned virtual address - * @param[out] phys Mapped physical address (can be NULL if only checking - * if virtual address is mapped) - * - * @retval 0 if mapping is found and valid - * @retval -EINVAL if invalid arguments are provided - * @retval -EFAULT if virtual address is not mapped - */ -int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys); - /** * @brief Remap virtual pages into new address * @@ -225,6 +233,18 @@ int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys); */ int sys_mm_drv_remap_region(void *virt_old, size_t size, void *virt_new); +/** + * @} + */ + +/** + * @name Memory Moving + * + * On moving already mapped memory. + * + * @{ + */ + /** * @brief Physically move memory, with copy * @@ -294,6 +314,17 @@ int sys_mm_drv_move_region(void *virt_old, size_t size, void *virt_new, int sys_mm_drv_move_array(void *virt_old, size_t size, void *virt_new, uintptr_t *phys_new, size_t phys_cnt); +/** + * @} + */ + +/** + * @name Memory Mapping Attributes + * + * On manipulating attributes of already mapped memory. + * + * @{ + */ /** * @brief Update memory page flags @@ -340,6 +371,37 @@ 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); +/** + * @} + */ + +/** + * @name Memory Mappings Query + * + * On querying information on memory mappings. + * + * @{ + */ + +/** + * @brief Get the mapped physical memory address from virtual address. + * + * The function queries the translation tables to find the physical + * memory address of a mapped virtual address. + * + * Behavior when providing unaligned address is undefined, this + * is assumed to be page aligned. + * + * @param virt Page-aligned virtual address + * @param[out] phys Mapped physical address (can be NULL if only checking + * if virtual address is mapped) + * + * @retval 0 if mapping is found and valid + * @retval -EINVAL if invalid arguments are provided + * @retval -EFAULT if virtual address is not mapped + */ +int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys); + /** * @brief Represents an available memory region. * @@ -387,6 +449,10 @@ const struct sys_mm_drv_region *sys_mm_drv_query_memory_regions(void); */ void sys_mm_drv_query_memory_regions_free(const struct sys_mm_drv_region *regions); +/** + * @} + */ + /** * @} */ diff --git a/include/zephyr/drivers/pinctrl.h b/include/zephyr/drivers/pinctrl.h index bdff118462a3f26..93cc95901e40a2b 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/power/atmel_sam_supc.h b/include/zephyr/drivers/power/atmel_sam_supc.h new file mode 100644 index 000000000000000..e31e3d7565f09b6 --- /dev/null +++ b/include/zephyr/drivers/power/atmel_sam_supc.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Bjarki Arge Andreasen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_POWER_ATMEL_SAM_SUPC_H_ +#define ZEPHYR_INCLUDE_DRIVERS_POWER_ATMEL_SAM_SUPC_H_ + +#define SAM_DT_SUPC_CONTROLLER DEVICE_DT_GET(DT_NODELABEL(supc)) + +#define SAM_DT_SUPC_WAKEUP_SOURCE_ID(node_id) \ + DT_PROP_BY_IDX(node_id, wakeup_source_id wakeup_source_id) + +#define SAM_DT_INST_SUPC_WAKEUP_SOURCE_ID(inst) \ + SAM_DT_SUPC_WAKEUP_SOURCE_ID(DT_DRV_INST(inst)) + +#endif /* ZEPHYR_INCLUDE_DRIVERS_POWER_ATMEL_SAM_SUPC_H_ */ diff --git a/include/zephyr/drivers/regulator.h b/include/zephyr/drivers/regulator.h index a2e28440591591a..77e441d0daefdcb 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 */ @@ -76,6 +77,9 @@ typedef int (*regulator_set_voltage_t)(const struct device *dev, int32_t min_uv, int32_t max_uv); typedef int (*regulator_get_voltage_t)(const struct device *dev, int32_t *volt_uv); +typedef unsigned int (*regulator_count_current_limits_t)(const struct device *dev); +typedef int (*regulator_list_current_limit_t)(const struct device *dev, + unsigned int idx, int32_t *current_ua); typedef int (*regulator_set_current_limit_t)(const struct device *dev, int32_t min_ua, int32_t max_ua); typedef int (*regulator_get_current_limit_t)(const struct device *dev, @@ -84,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); @@ -95,10 +103,14 @@ __subsystem struct regulator_driver_api { regulator_list_voltage_t list_voltage; regulator_set_voltage_t set_voltage; regulator_get_voltage_t get_voltage; + regulator_count_current_limits_t count_current_limits; + regulator_list_current_limit_t list_current_limit; regulator_set_current_limit_t set_current_limit; 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; }; @@ -108,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) /** @} */ @@ -135,6 +163,12 @@ 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. */ + uint32_t off_on_delay_us; /** Allowed modes */ const regulator_mode_t *allowed_modes; /** Number of allowed modes */ @@ -162,6 +196,10 @@ 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 []) \ DT_PROP_OR(node_id, regulator_allowed_modes, {}), \ .allowed_modes_cnt = \ @@ -171,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)))), \ } /** @@ -485,6 +526,57 @@ static inline int regulator_get_voltage(const struct device *dev, return api->get_voltage(dev, volt_uv); } +/** + * @brief Obtain the number of supported current limit levels. + * + * Each current limit level supported by a regulator gets an index, starting from + * zero. The total number of supported current limit levels can be used together with + * regulator_list_current_limit() to list all supported current limit levels. + * + * @param dev Regulator device instance. + * + * @return Number of supported current limits. + */ +static inline unsigned int regulator_count_current_limits(const struct device *dev) +{ + const struct regulator_driver_api *api = + (const struct regulator_driver_api *)dev->api; + + if (api->count_current_limits == NULL) { + return 0U; + } + + return api->count_current_limits(dev); +} + +/** + * @brief Obtain the value of a current limit given an index. + * + * Each current limit level supported by a regulator gets an index, starting from + * zero. Together with regulator_count_current_limits(), this function can be used + * to iterate over all supported current limits. + * + * @param dev Regulator device instance. + * @param idx Current index. + * @param[out] current_ua Where current for the given @p index will be stored, in + * microamps. + * + * @retval 0 If @p index corresponds to a supported current limit. + * @retval -EINVAL If @p index does not correspond to a supported current limit. + */ +static inline int regulator_list_current_limit(const struct device *dev, + unsigned int idx, int32_t *current_ua) +{ + const struct regulator_driver_api *api = + (const struct regulator_driver_api *)dev->api; + + if (api->list_current_limit == NULL) { + return -EINVAL; + } + + return api->list_current_limit(dev, idx, current_ua); +} + /** * @brief Set output current limit. * @@ -569,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 1bfffe6381b35c4..d91161dbc7a8820 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 6e9a4a1cb394f55..2e8b9fe60ec0ea8 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/sdhc.h b/include/zephyr/drivers/sdhc.h index 78529af2f4b05c8..092fca8a9ef2d1d 100644 --- a/include/zephyr/drivers/sdhc.h +++ b/include/zephyr/drivers/sdhc.h @@ -231,17 +231,44 @@ struct sdhc_host_props { bool is_spi; /*!< Is the host using SPI mode */ }; +/** + * @brief SD host controller interrupt sources + * + * Interrupt sources for SD host controller. + */ +enum sdhc_interrupt_source { + SDHC_INT_SDIO = BIT(0), /*!< Card interrupt, used by SDIO cards */ + SDHC_INT_INSERTED = BIT(1), /*!< Card was inserted into slot */ + SDHC_INT_REMOVED = BIT(2), /*!< Card was removed from slot */ +}; + +/** + * @typedef sdhc_interrupt_cb_t + * @brief SDHC card interrupt callback prototype + * + * Function prototype for SDHC card interrupt callback. + * @param dev: SDHC device that produced interrupt + * @param reason: one of @ref sdhc_interrupt_source values. + * @param user_data: User data, set via @ref sdhc_enable_interrupt + */ +typedef void (*sdhc_interrupt_cb_t)(const struct device *dev, int reason, + const void *user_data); + __subsystem struct sdhc_driver_api { int (*reset)(const struct device *dev); int (*request)(const struct device *dev, - struct sdhc_command *cmd, - struct sdhc_data *data); + struct sdhc_command *cmd, + struct sdhc_data *data); int (*set_io)(const struct device *dev, struct sdhc_io *ios); int (*get_card_present)(const struct device *dev); int (*execute_tuning)(const struct device *dev); int (*card_busy)(const struct device *dev); int (*get_host_props)(const struct device *dev, - struct sdhc_host_props *props); + struct sdhc_host_props *props); + int (*enable_interrupt)(const struct device *dev, + sdhc_interrupt_cb_t callback, + int sources, void *user_data); + int (*disable_interrupt)(const struct device *dev, int sources); }; /** @@ -260,8 +287,7 @@ __syscall int sdhc_hw_reset(const struct device *dev); static inline int z_impl_sdhc_hw_reset(const struct device *dev) { - const struct sdhc_driver_api *api = - (const struct sdhc_driver_api *)dev->api; + const struct sdhc_driver_api *api = (const struct sdhc_driver_api *)dev->api; if (!api->reset) { return -ENOSYS; @@ -285,13 +311,13 @@ static inline int z_impl_sdhc_hw_reset(const struct device *dev) * @retval -EIO: I/O error */ __syscall int sdhc_request(const struct device *dev, struct sdhc_command *cmd, - struct sdhc_data *data); + struct sdhc_data *data); static inline int z_impl_sdhc_request(const struct device *dev, - struct sdhc_command *cmd, struct sdhc_data *data) + struct sdhc_command *cmd, + struct sdhc_data *data) { - const struct sdhc_driver_api *api = - (const struct sdhc_driver_api *)dev->api; + const struct sdhc_driver_api *api = (const struct sdhc_driver_api *)dev->api; if (!api->request) { return -ENOSYS; @@ -315,10 +341,9 @@ static inline int z_impl_sdhc_request(const struct device *dev, __syscall int sdhc_set_io(const struct device *dev, struct sdhc_io *io); static inline int z_impl_sdhc_set_io(const struct device *dev, - struct sdhc_io *io) + struct sdhc_io *io) { - const struct sdhc_driver_api *api = - (const struct sdhc_driver_api *)dev->api; + const struct sdhc_driver_api *api = (const struct sdhc_driver_api *)dev->api; if (!api->set_io) { return -ENOSYS; @@ -342,8 +367,7 @@ __syscall int sdhc_card_present(const struct device *dev); static inline int z_impl_sdhc_card_present(const struct device *dev) { - const struct sdhc_driver_api *api = - (const struct sdhc_driver_api *)dev->api; + const struct sdhc_driver_api *api = (const struct sdhc_driver_api *)dev->api; if (!api->get_card_present) { return -ENOSYS; @@ -368,8 +392,7 @@ __syscall int sdhc_execute_tuning(const struct device *dev); static inline int z_impl_sdhc_execute_tuning(const struct device *dev) { - const struct sdhc_driver_api *api = - (const struct sdhc_driver_api *)dev->api; + const struct sdhc_driver_api *api = (const struct sdhc_driver_api *)dev->api; if (!api->execute_tuning) { return -ENOSYS; @@ -393,8 +416,7 @@ __syscall int sdhc_card_busy(const struct device *dev); static inline int z_impl_sdhc_card_busy(const struct device *dev) { - const struct sdhc_driver_api *api = - (const struct sdhc_driver_api *)dev->api; + const struct sdhc_driver_api *api = (const struct sdhc_driver_api *)dev->api; if (!api->card_busy) { return -ENOSYS; @@ -415,13 +437,12 @@ static inline int z_impl_sdhc_card_busy(const struct device *dev) * @retval -ENOTSUP host controller does not support this call */ __syscall int sdhc_get_host_props(const struct device *dev, - struct sdhc_host_props *props); + struct sdhc_host_props *props); static inline int z_impl_sdhc_get_host_props(const struct device *dev, - struct sdhc_host_props *props) + struct sdhc_host_props *props) { - const struct sdhc_driver_api *api = - (const struct sdhc_driver_api *)dev->api; + const struct sdhc_driver_api *api = (const struct sdhc_driver_api *)dev->api; if (!api->get_host_props) { return -ENOSYS; @@ -430,6 +451,64 @@ static inline int z_impl_sdhc_get_host_props(const struct device *dev, return api->get_host_props(dev, props); } +/** + * @brief Enable SDHC interrupt sources. + * + * Enables SDHC interrupt sources. Each subsequent call of this function + * should replace the previous callback set, and leave only the interrupts + * specified in the "sources" argument enabled. + * @param dev: SDHC device + * @param callback: Callback called when interrupt occurs + * @param sources: bitmask of @ref sdhc_interrupt_source values + * indicating which interrupts should produce a callback + * @param user_data: parameter that will be passed to callback function + * @retval 0 interrupts were enabled, and callback was installed + * @retval -ENOTSUP: controller does not support this function + * @retval -EIO: I/O error + */ +__syscall int sdhc_enable_interrupt(const struct device *dev, + sdhc_interrupt_cb_t callback, + int sources, void *user_data); + +static inline int z_impl_sdhc_enable_interrupt(const struct device *dev, + sdhc_interrupt_cb_t callback, + int sources, void *user_data) +{ + const struct sdhc_driver_api *api = (const struct sdhc_driver_api *)dev->api; + + if (!api->enable_interrupt) { + return -ENOSYS; + } + + return api->enable_interrupt(dev, callback, sources, user_data); +} + +/** + * @brief Disable SDHC interrupt sources + * + * Disables SDHC interrupt sources. If multiple sources are enabled, only + * the ones specified in "sources" will be masked. + * @param dev: SDHC device + * @param sources: bitmask of @ref sdhc_interrupt_source values + * indicating which interrupts should be disabled. + * @retval 0 interrupts were disabled + * @retval -ENOTSUP: controller does not support this function + * @retval -EIO: I/O error + */ +__syscall int sdhc_disable_interrupt(const struct device *dev, int sources); + +static inline int z_impl_sdhc_disable_interrupt(const struct device *dev, + int sources) +{ + const struct sdhc_driver_api *api = (const struct sdhc_driver_api *)dev->api; + + if (!api->disable_interrupt) { + return -ENOSYS; + } + + return api->disable_interrupt(dev, sources); +} + /** * @} */ diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index 903acb6f03ac466..53d55e1f1a3786f 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -251,6 +251,12 @@ enum sensor_trigger_type { /** Trigger fires when no motion has been detected for a while. */ SENSOR_TRIG_STATIONARY, + + /** Trigger fires when the FIFO watermark has been reached. */ + SENSOR_TRIG_FIFO_WATERMARK, + + /** Trigger fires when the FIFO becomes full. */ + SENSOR_TRIG_FIFO_FULL, /** * Number of all common sensor triggers. */ @@ -328,6 +334,10 @@ enum sensor_attribute { * to the new sampling frequency. */ SENSOR_ATTR_FF_DUR, + + /** Hardware batch duration in ticks */ + SENSOR_ATTR_BATCH_DURATION, + /** * Number of all common sensor attributes. */ @@ -408,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 { /** @@ -466,6 +476,15 @@ struct sensor_decoder_api { */ int (*decode)(const uint8_t *buffer, enum sensor_channel channel, size_t channel_idx, uint32_t *fit, uint16_t max_count, void *data_out); + + /** + * @brief Check if the given trigger type is present + * + * @param[in] buffer The buffer provided on the @ref rtio context + * @param[in] trigger The trigger type in question + * @return Whether the trigger is present in the buffer + */ + bool (*has_trigger)(const uint8_t *buffer, enum sensor_trigger_type trigger); }; /** @@ -538,13 +557,38 @@ int sensor_natively_supported_channel_size_info(enum sensor_channel channel, siz typedef int (*sensor_get_decoder_t)(const struct device *dev, const struct sensor_decoder_api **api); +/** + * @brief Options for what to do with the associated data when a trigger is consumed + */ +enum sensor_stream_data_opt { + /** @brief Include whatever data is associated with the trigger */ + SENSOR_STREAM_DATA_INCLUDE = 0, + /** @brief Do nothing with the associated trigger data, it may be consumed later */ + SENSOR_STREAM_DATA_NOP = 1, + /** @brief Flush/clear whatever data is associated with the trigger */ + SENSOR_STREAM_DATA_DROP = 2, +}; + +struct sensor_stream_trigger { + enum sensor_trigger_type trigger; + enum sensor_stream_data_opt opt; +}; + +#define SENSOR_STREAM_TRIGGER_PREP(_trigger, _opt) \ + { \ + .trigger = (_trigger), .opt = (_opt), \ + } /* * Internal data structure used to store information about the IODevice for async reading and * streaming sensor data. */ struct sensor_read_config { const struct device *sensor; - enum sensor_channel *const channels; + const bool is_streaming; + union { + enum sensor_channel *const channels; + struct sensor_stream_trigger *const triggers; + }; size_t count; const size_t max; }; @@ -564,14 +608,45 @@ struct sensor_read_config { * @endcode */ #define SENSOR_DT_READ_IODEV(name, dt_node, ...) \ - static enum sensor_channel __channel_array_##name[] = {__VA_ARGS__}; \ - static struct sensor_read_config __sensor_read_config_##name = { \ + static enum sensor_channel _CONCAT(__channel_array_, name)[] = {__VA_ARGS__}; \ + static struct sensor_read_config _CONCAT(__sensor_read_config_, name) = { \ .sensor = DEVICE_DT_GET(dt_node), \ - .channels = __channel_array_##name, \ - .count = ARRAY_SIZE(__channel_array_##name), \ - .max = ARRAY_SIZE(__channel_array_##name), \ + .is_streaming = false, \ + .channels = _CONCAT(__channel_array_, name), \ + .count = ARRAY_SIZE(_CONCAT(__channel_array_, name)), \ + .max = ARRAY_SIZE(_CONCAT(__channel_array_, name)), \ }; \ - RTIO_IODEV_DEFINE(name, &__sensor_iodev_api, &__sensor_read_config_##name) + RTIO_IODEV_DEFINE(name, &__sensor_iodev_api, _CONCAT(&__sensor_read_config_, name)) + +/** + * @brief Define a stream instance of a sensor + * + * Use this macro to generate a @ref rtio_iodev for starting a stream that's triggered by specific + * interrupts. Example: + * + * @code(.c) + * SENSOR_DT_STREAM_IODEV(imu_stream, DT_ALIAS(imu), + * {SENSOR_TRIG_FIFO_WATERMARK, SENSOR_STREAM_DATA_INCLUDE}, + * {SENSOR_TRIG_FIFO_FULL, SENSOR_STREAM_DATA_NOP}); + * + * int main(void) { + * struct rtio_sqe *handle; + * sensor_stream(&imu_stream, &rtio, NULL, &handle); + * k_msleep(1000); + * rtio_sqe_cancel(handle); + * } + * @endcode + */ +#define SENSOR_DT_STREAM_IODEV(name, dt_node, ...) \ + static struct sensor_stream_trigger _CONCAT(__trigger_array_, name)[] = {__VA_ARGS__}; \ + static struct sensor_read_config _CONCAT(__sensor_read_config_, name) = { \ + .sensor = DEVICE_DT_GET(dt_node), \ + .is_streaming = true, \ + .triggers = _CONCAT(__trigger_array_, name), \ + .count = ARRAY_SIZE(_CONCAT(__trigger_array_, name)), \ + .max = ARRAY_SIZE(_CONCAT(__trigger_array_, name)), \ + }; \ + RTIO_IODEV_DEFINE(name, &__sensor_iodev_api, &_CONCAT(__sensor_read_config_, name)) /* Used to submit an RTIO sqe to the sensor's iodev */ typedef int (*sensor_submit_t)(const struct device *sensor, struct rtio_iodev_sqe *sqe); @@ -880,7 +955,7 @@ static inline int z_impl_sensor_reconfigure_read_iodev(struct rtio_iodev *iodev, { struct sensor_read_config *cfg = (struct sensor_read_config *)iodev->data; - if (cfg->max < num_channels) { + if (cfg->max < num_channels || cfg->is_streaming) { return -ENOMEM; } @@ -888,6 +963,28 @@ static inline int z_impl_sensor_reconfigure_read_iodev(struct rtio_iodev *iodev, memcpy(cfg->channels, channels, num_channels * sizeof(enum sensor_channel)); cfg->count = num_channels; return 0; +} + +static inline int sensor_stream(struct rtio_iodev *iodev, struct rtio *ctx, void *userdata, + struct rtio_sqe **handle) +{ + if (IS_ENABLED(CONFIG_USERSPACE)) { + struct rtio_sqe sqe; + + rtio_sqe_prep_read_multishot(&sqe, iodev, RTIO_PRIO_NORM, userdata); + rtio_sqe_copy_in_get_handles(ctx, &sqe, handle, 1); + } else { + struct rtio_sqe *sqe = rtio_sqe_acquire(ctx); + + if (sqe == NULL) { + return -ENOMEM; + } + if (handle != NULL) { + *handle = sqe; + } + rtio_sqe_prep_read_multishot(sqe, iodev, RTIO_PRIO_NORM, userdata); + } + rtio_submit(ctx, 0); return 0; } @@ -1257,10 +1354,48 @@ static inline int64_t sensor_value_to_micro(const struct sensor_value *val) } /** - * @} + * @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; -#if defined(CONFIG_HAS_DTS) || defined(__DOXYGEN__) + 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; +} + +/** + * @} + */ /** * @brief Get the decoder name for the current driver @@ -1309,7 +1444,6 @@ static inline int64_t sensor_value_to_micro(const struct sensor_value *val) ()) DT_FOREACH_STATUS_OKAY_NODE(Z_MAYBE_SENSOR_DECODER_DECLARE_INTERNAL) -#endif /* defined(CONFIG_HAS_DTS) || defined(__DOXYGEN__) */ #ifdef __cplusplus } diff --git a/include/zephyr/drivers/sensor/adc_cmp_npcx.h b/include/zephyr/drivers/sensor/adc_cmp_npcx.h index 5e986dd1be73344..0fa7f14ca1ff149 100644 --- a/include/zephyr/drivers/sensor/adc_cmp_npcx.h +++ b/include/zephyr/drivers/sensor/adc_cmp_npcx.h @@ -17,11 +17,9 @@ enum npcx_adc_cmp_thrctl { ADC_CMP_NPCX_THRCTL1, ADC_CMP_NPCX_THRCTL2, ADC_CMP_NPCX_THRCTL3, -#if !defined(CONFIG_SOC_SERIES_NPCX7) ADC_CMP_NPCX_THRCTL4, ADC_CMP_NPCX_THRCTL5, ADC_CMP_NPCX_THRCTL6, -#endif ADC_CMP_NPCX_THRCTL_COUNT, }; diff --git a/include/zephyr/drivers/sensor/bmp581_user.h b/include/zephyr/drivers/sensor/bmp581_user.h new file mode 100644 index 000000000000000..e0fd000c8c067a8 --- /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/explorir_m.h b/include/zephyr/drivers/sensor/explorir_m.h new file mode 100644 index 000000000000000..efef562447cead0 --- /dev/null +++ b/include/zephyr/drivers/sensor/explorir_m.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023, Vitrolife A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_EXPLORIR_M_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_EXPLORIR_M_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +enum sensor_attribute_explorir_m { + /* Sensor integrated low-pass filter. Values 16, 32, 64, and 128 is allowed */ + SENSOR_ATTR_EXPLORIR_M_FILTER = SENSOR_ATTR_PRIV_START, +}; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_EXPLORIR_M_H_ */ diff --git a/include/zephyr/drivers/sensor/max31865.h b/include/zephyr/drivers/sensor/max31865.h new file mode 100644 index 000000000000000..901637379bfe660 --- /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_attribute_types.h b/include/zephyr/drivers/sensor_attribute_types.h new file mode 100644 index 000000000000000..8ccb9dba1109e27 --- /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_rx.h b/include/zephyr/drivers/serial/uart_async_rx.h new file mode 100644 index 000000000000000..646a2befc946580 --- /dev/null +++ b/include/zephyr/drivers/serial/uart_async_rx.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Helper module for receiving using UART Asynchronous API. + */ + +#ifndef ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_RX_H_ +#define ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_RX_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* @brief RX buffer structure which holds the buffer and its state. */ +struct uart_async_rx_buf { + /* Write index which is incremented whenever new data is reported to be + * received to that buffer. + */ + uint8_t wr_idx; + + /* Read index which is incremented whenever data is consumed from the buffer. + * Read index cannot be higher than the write index. + */ + uint8_t rd_idx; + + /* Set to one if buffer is released by the driver. */ + uint8_t completed; + + /* Location which is passed to the UART driver. */ + uint8_t buffer[]; +}; + +/** @brief UART asynchronous RX helper structure. */ +struct uart_async_rx { + /* Pointer to the configuration structure. Structure must be persistent. */ + const struct uart_async_rx_config *config; + + /* Total amount of pending bytes. Bytes may be spread across multiple RX buffers. */ + atomic_t pending_bytes; + + /* Number of buffers which are free. */ + atomic_t free_buf_cnt; + + /* Single buffer size. */ + uint8_t buf_len; + + /* Index of the next buffer to be provided to the driver. */ + uint8_t drv_buf_idx; + + /* Current buffer to which data is written. */ + uint8_t wr_buf_idx; + + /* Current buffer from which data is being consumed. */ + uint8_t rd_buf_idx; +}; + +/** @brief UART asynchronous RX helper configuration structure. */ +struct uart_async_rx_config { + /* Pointer to the buffer. */ + uint8_t *buffer; + + /* Buffer length. */ + size_t length; + + /* Number of buffers into provided space shall be split. */ + uint8_t buf_cnt; +}; + +/** @brief Get RX buffer length. + * + * @param async_rx Pointer to the helper instance. + * + * @return Buffer length. + */ +static inline uint8_t uart_async_rx_get_buf_len(struct uart_async_rx *async_rx) +{ + return async_rx->buf_len; +} + +/** @brief Get amount of space dedicated for managing each buffer state. + * + * User buffer provided during the initialization is split into chunks and each + * chunk has overhead. This overhead can be used to calculate actual space used + * for UART data. + * + * @return Overhead space in bytes. + */ +#define UART_ASYNC_RX_BUF_OVERHEAD offsetof(struct uart_async_rx_buf, buffer) + +/** @brief Initialize the helper instance. + * + * @param async_rx Pointer to the helper instance. + * @param config Configuration. Must be persistent. + * + * @retval 0 on successful initialization. + */ +int uart_async_rx_init(struct uart_async_rx *async_rx, + const struct uart_async_rx_config *config); + +/** @brief Reset state of the helper instance. + * + * Helper can be reset after RX abort to discard all received data and bring + * the helper to its initial state. + * + * @param async_rx Pointer to the helper instance. + */ +void uart_async_rx_reset(struct uart_async_rx *async_rx); + +/** @brief Indicate received data. + * + * Function shall be called from @ref UART_RX_RDY context. + * + * @param async_rx Pointer to the helper instance. + * @param buffer Buffer received in the UART driver event. + * @param length Length received in the UART driver event. + */ +void uart_async_rx_on_rdy(struct uart_async_rx *async_rx, uint8_t *buffer, size_t length); + +/** @brief Get next RX buffer. + * + * Returned pointer shall be provided to @ref uart_rx_buf_rsp or @ref uart_rx_enable. + * If null is returned that indicates that there are no available buffers since all + * buffers are used by the driver or contain not consumed data. + * + * @param async_rx Pointer to the helper instance. + * + * @return Pointer to the next RX buffer or null if no buffer available. + */ +uint8_t *uart_async_rx_buf_req(struct uart_async_rx *async_rx); + +/** @brief Indicate that buffer is no longer used by the UART driver. + * + * Function shall be called on @ref UART_RX_BUF_RELEASED event. + * + * @param async_rx Pointer to the helper instance. + * @param buf Buffer pointer received in the UART driver event. + */ +void uart_async_rx_on_buf_rel(struct uart_async_rx *async_rx, uint8_t *buf); + +/** @brief Claim received data for processing. + * + * Helper module works in the zero copy mode. It provides a pointer to the buffer + * that was directly used by the UART driver. Since received data is spread across + * multiple buffers there is no possibility to read all data at once. It can only be + * consumed in chunks. After data is processed, @ref uart_async_rx_data_consume is + * used to indicate that data is consumed. + * + * @param async_rx Pointer to the helper instance. + * @param data Location where address to the buffer is written. Untouched if no data to claim. + * @param length Amount of requested data. + * + * @return Amount valid of data in the @p data buffer. 0 is returned when there is no data. + */ +size_t uart_async_rx_data_claim(struct uart_async_rx *async_rx, uint8_t **data, size_t length); + +/** @brief Consume claimed data. + * + * It pairs with @ref uart_async_rx_data_claim. + * + * @param async_rx Pointer to the helper instance. + * @param length Amount of data to consume. It must be less or equal than amount of claimed data. + */ +void uart_async_rx_data_consume(struct uart_async_rx *async_rx, size_t length); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_RX_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 000000000000000..d5116dee2c0edef --- /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/serial/uart_emul.h b/include/zephyr/drivers/serial/uart_emul.h index 68a289841df2fca..08e6be05b1aeb7e 100644 --- a/include/zephyr/drivers/serial/uart_emul.h +++ b/include/zephyr/drivers/serial/uart_emul.h @@ -83,6 +83,14 @@ uint32_t uart_emul_flush_rx_data(const struct device *dev); */ uint32_t uart_emul_flush_tx_data(const struct device *dev); +/** + * @brief Sets one or more driver errors + * + * @param dev The emulated UART device instance + * @param errors The @ref uart_rx_stop_reason errors to set + */ +void uart_emul_set_errors(const struct device *dev, int errors); + #ifdef __cplusplus } #endif diff --git a/include/zephyr/drivers/serial/uart_intel_lw.h b/include/zephyr/drivers/serial/uart_intel_lw.h new file mode 100644 index 000000000000000..8ad8c26aab8352a --- /dev/null +++ b/include/zephyr/drivers/serial/uart_intel_lw.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Header file for the INTEL LW UART + */ + +#ifndef ZEPHYR_DRIVERS_SERIAL_UART_INTEL_LW_H_ +#define ZEPHYR_DRIVERS_SERIAL_UART_INTEL_LW_H_ + +/* End of packet feature. + * Driver will trigger interrupt upon receiving end of package character. + * Please enable CONFIG_UART_INTEL_LW_EOP to use this feature. + * Use the api: uart_drv_cmd with CMD_ENABLE_EOP to enable the feature. + * This cmd will write the ip register and also set a flag to the driver. + * The flag will modify uart_irq_callback_user_data_set + * to set call back function for eop interrupt. + * Flag is cleared after uart_irq_callback_user_data_set is called. + */ +#define CMD_ENABLE_EOP 0x01 +#define CMD_DISABLE_EOP 0x02 + +/* Transmit break feature. + * Use uart_drv_cmd with CMD_TRBK_EN to break ongoing transmit. + * After this cmd, uart is unable to transmit any data. + * Please use CMD_TRBK_DIS to resume normal operation. + * Please also call uart_intel_lw_err_check, to clear the error caused + * by transmit break. + */ +#define CMD_TRBK_EN 0x03 +#define CMD_TRBK_DIS 0x04 + +/* This driver supports interrupt driven api. + * Polling for data under normal operation, might cause unexpected behaviour. + * If users wish to poll for data, please use the api: + * uart_drv_cmd with CMD_POLL_ASSERT_RTS before polling out/in. + * Then use CMD_POLL_DEASSERT_RTS to resume normal operation after polling. + */ +#define CMD_POLL_ASSERT_RTS 0x05 +#define CMD_POLL_DEASSERT_RTS 0x06 + +#endif /* ZEPHYR_DRIVERS_SERIAL_UART_INTEL_LW_H_ */ diff --git a/include/zephyr/drivers/smbus.h b/include/zephyr/drivers/smbus.h index b624462f4259704..c0348c367f141ff 100644 --- a/include/zephyr/drivers/smbus.h +++ b/include/zephyr/drivers/smbus.h @@ -4,6 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @file + * @brief Public SMBus Driver APIs + */ + #ifndef ZEPHYR_INCLUDE_DRIVERS_SMBUS_H_ #define ZEPHYR_INCLUDE_DRIVERS_SMBUS_H_ @@ -14,6 +19,8 @@ * @{ */ +#include +#include #include #include @@ -606,11 +613,8 @@ static inline int z_impl_smbus_get_config(const struct device *dev, * @retval -ENOSYS If function smbus_smbalert_set_cb() is not implemented * by the driver. */ -__syscall int smbus_smbalert_set_cb(const struct device *dev, - struct smbus_callback *cb); - -static inline int z_impl_smbus_smbalert_set_cb(const struct device *dev, - struct smbus_callback *cb) +static inline int smbus_smbalert_set_cb(const struct device *dev, + struct smbus_callback *cb) { const struct smbus_driver_api *api = (const struct smbus_driver_api *)dev->api; @@ -660,11 +664,8 @@ static inline int z_impl_smbus_smbalert_remove_cb(const struct device *dev, * @retval -ENOSYS If function smbus_host_notify_set_cb() is not implemented * by the driver. */ -__syscall int smbus_host_notify_set_cb(const struct device *dev, - struct smbus_callback *cb); - -static inline int z_impl_smbus_host_notify_set_cb(const struct device *dev, - struct smbus_callback *cb) +static inline int smbus_host_notify_set_cb(const struct device *dev, + struct smbus_callback *cb) { const struct smbus_driver_api *api = (const struct smbus_driver_api *)dev->api; diff --git a/include/zephyr/drivers/spi.h b/include/zephyr/drivers/spi.h index 671040de6a3ebad..44863f49acd1539 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 @@ -332,7 +347,10 @@ struct spi_config { .frequency = DT_PROP(node_id, spi_max_frequency), \ .operation = (operation_) | \ DT_PROP(node_id, duplex) | \ - DT_PROP(node_id, frame_format), \ + DT_PROP(node_id, frame_format) | \ + COND_CODE_1(DT_PROP(node_id, spi_cpol), SPI_MODE_CPOL, (0)) | \ + COND_CODE_1(DT_PROP(node_id, spi_cpha), SPI_MODE_CPHA, (0)) | \ + COND_CODE_1(DT_PROP(node_id, spi_hold_cs), SPI_HOLD_ON_CS, (0)), \ .slave = DT_REG_ADDR(node_id), \ .cs = SPI_CS_CONTROL_INIT(node_id, delay_), \ } @@ -353,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; }; @@ -402,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; }; diff --git a/include/zephyr/drivers/spi_emul.h b/include/zephyr/drivers/spi_emul.h index fe189efb82b7d62..9f7eb9580895e5e 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 000000000000000..172a904fdef950a --- /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 0f01d877e541ca7..7e13d565a736a9b 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 000000000000000..c8f76c9227f75f9 --- /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/usb_c/usbc_tcpc.h b/include/zephyr/drivers/usb_c/usbc_tcpc.h index 2788aea2e402fb4..1b62a39db682bcc 100644 --- a/include/zephyr/drivers/usb_c/usbc_tcpc.h +++ b/include/zephyr/drivers/usb_c/usbc_tcpc.h @@ -136,8 +136,7 @@ __subsystem struct tcpc_driver_api { int (*set_vconn)(const struct device *dev, bool enable); int (*set_roles)(const struct device *dev, enum tc_power_role power_role, enum tc_data_role data_role); - int (*receive_data)(const struct device *dev, struct pd_msg *msg); - bool (*is_rx_pending_msg)(const struct device *dev, enum pd_packet_type *type); + int (*get_rx_pending_msg)(const struct device *dev, struct pd_msg *msg); int (*set_rx_enable)(const struct device *dev, bool enable); int (*set_cc_polarity)(const struct device *dev, enum tc_cc_polarity polarity); int (*transmit_data)(const struct device *dev, struct pd_msg *msg); @@ -152,8 +151,8 @@ __subsystem struct tcpc_driver_api { int (*set_debug_accessory)(const struct device *dev, bool enable); int (*set_debug_detach)(const struct device *dev); int (*set_drp_toggle)(const struct device *dev, bool enable); - bool (*get_snk_ctrl)(const struct device *dev); - bool (*get_src_ctrl)(const struct device *dev); + int (*get_snk_ctrl)(const struct device *dev); + int (*get_src_ctrl)(const struct device *dev); int (*get_chip_info)(const struct device *dev, struct tcpc_chip_info *chip_info); int (*set_low_power_mode)(const struct device *dev, bool enable); int (*sop_prime_enable)(const struct device *dev, bool enable); @@ -232,6 +231,7 @@ static inline int tcpc_is_cc_only_one_rd(enum tc_cc_voltage_state cc1, * * @retval 0 on success * @retval -EIO on failure + * @retval -EAGAIN if initialization should be postponed */ static inline int tcpc_init(const struct device *dev) { @@ -455,50 +455,25 @@ static inline int tcpc_set_roles(const struct device *dev, } /** - * @brief Tests if a received Power Delivery message is pending + * @brief Retrieves the Power Delivery message from the TCPC. + * If buf is NULL, then only the status is returned, where 0 means there is a message pending and + * -ENODATA means there is no pending message. * - * @param dev Runtime device structure - * @param type pointer to where message type is written. Can be NULL - * - * @retval true if message is pending, else false - * @retval -EIO on failure - * @retval -ENOSYS if not implemented - */ -static inline bool tcpc_is_rx_pending_msg(const struct device *dev, - enum pd_packet_type *type) -{ - const struct tcpc_driver_api *api = - (const struct tcpc_driver_api *)dev->api; - - if (api->is_rx_pending_msg == NULL) { - return -ENOSYS; - } - - return api->is_rx_pending_msg(dev, type); -} - -/** - * @brief Retrieves the Power Delivery message from the TCPC - * - * @param dev Runtime device structure - * @param buf pointer where the pd_buf pointer is written + * @param dev Runtime device structure + * @param buf pointer where the pd_buf pointer is written, NULL if only checking the status * - * @retval Greater or equal to 0 is the number of bytes received + * @retval Greater or equal to 0 is the number of bytes received if buf parameter is provided + * @retval 0 if there is a message pending and buf parameter is NULL * @retval -EIO on failure - * @retval -EFAULT on buf being NULL - * @retval -ENOSYS if not implemented + * @retval -ENODATA if no message is pending */ -static inline int tcpc_receive_data(const struct device *dev, - struct pd_msg *buf) +static inline int tcpc_get_rx_pending_msg(const struct device *dev, struct pd_msg *buf) { - const struct tcpc_driver_api *api = - (const struct tcpc_driver_api *)dev->api; + const struct tcpc_driver_api *api = (const struct tcpc_driver_api *)dev->api; - if (api->receive_data == NULL) { - return -ENOSYS; - } + __ASSERT(api->get_rx_pending_msg != NULL, "Callback pointer should not be NULL"); - return api->receive_data(dev, buf); + return api->get_rx_pending_msg(dev, buf); } /** @@ -767,7 +742,7 @@ static inline int tcpc_set_drp_toggle(const struct device *dev, bool enable) * @retval false if not sinking power * @retval -ENOSYS if not implemented */ -static inline bool tcpc_get_snk_ctrl(const struct device *dev) +static inline int tcpc_get_snk_ctrl(const struct device *dev) { const struct tcpc_driver_api *api = (const struct tcpc_driver_api *)dev->api; @@ -788,7 +763,7 @@ static inline bool tcpc_get_snk_ctrl(const struct device *dev) * @retval false if not sourcing power * @retval -ENOSYS if not implemented */ -static inline bool tcpc_get_src_ctrl(const struct device *dev) +static inline int tcpc_get_src_ctrl(const struct device *dev) { const struct tcpc_driver_api *api = (const struct tcpc_driver_api *)dev->api; diff --git a/include/zephyr/drivers/virtualization/ivshmem.h b/include/zephyr/drivers/virtualization/ivshmem.h index 0507eb6ae1af547..20bd1e42336eb17 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 93c3b0b3b157d3b..3535c06935eea0d 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm.h @@ -55,4 +55,7 @@ #define IMX_CCM_QTMR_CLK 0x0D00UL +#define IMX_CCM_ENET_CLK 0x0E00UL +#define IMX_CCM_ENET_PLL 0x0E01UL + #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 fb105454377575a..fe011525846400d 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,9 @@ #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 + #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 6c06928ec805deb..8395a05b48366cd 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 581c5b57e08f709..e273288a37ed41f 100644 --- a/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h +++ b/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h @@ -51,4 +51,8 @@ #define MCUX_SCTIMER_CLK 34 +#define MCUX_DMIC_CLK 35 + +#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 000000000000000..f3a11104e741f5b --- /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/nxp_s32z2_clock.h b/include/zephyr/dt-bindings/clock/nxp_s32z2_clock.h index 47eb060c5455972..6471a2c54069f19 100644 --- a/include/zephyr/dt-bindings/clock/nxp_s32z2_clock.h +++ b/include/zephyr/dt-bindings/clock/nxp_s32z2_clock.h @@ -39,7 +39,7 @@ #define NXP_S32_LFAST0_PLL_PH0_CLK 30U #define NXP_S32_LFAST1_PLL_PH0_CLK 31U #define NXP_S32_ETH_RGMII_REF_CLK 32U -#define NXP_S32_ETH_EXT_TS_CLK 33U +#define NXP_S32_TMR_1588_CLK 33U #define NXP_S32_ETH0_EXT_RX_CLK 34U #define NXP_S32_ETH0_EXT_TX_CLK 35U #define NXP_S32_ETH1_EXT_RX_CLK 36U @@ -188,110 +188,113 @@ #define NXP_S32_ETH0_RX_MII_CLK 180U #define NXP_S32_ETH0_RX_RGMII_CLK 181U #define NXP_S32_ETH0_TX_RGMII_CLK 182U -#define NXP_S32_ETH0_TX_RGMII_LPBK_CLK 183U +#define NXP_S32_ETH0_PS_TX_CLK 183U #define NXP_S32_ETH1_REF_RMII_CLK 184U #define NXP_S32_ETH1_RX_MII_CLK 185U #define NXP_S32_ETH1_RX_RGMII_CLK 186U #define NXP_S32_ETH1_TX_MII_CLK 187U #define NXP_S32_ETH1_TX_RGMII_CLK 188U -#define NXP_S32_ETH1_TX_RGMII_LPBK_CLK 189U +#define NXP_S32_ETH1_PS_TX_CLK 189U #define NXP_S32_P1_LFAST0_REF_CLK 190U #define NXP_S32_P1_LFAST1_REF_CLK 191U -#define NXP_S32_P1_LFAST_DFT_CLK 192U -#define NXP_S32_P1_NETC_AXI_CLK 193U -#define NXP_S32_P1_LIN_CLK 194U -#define NXP_S32_P1_REG_INTF_CLK 195U -#define NXP_S32_P2_DBG_ATB_CLK 196U -#define NXP_S32_P2_REG_INTF_CLK 197U -#define NXP_S32_P3_AES_CLK 198U -#define NXP_S32_P3_CLKOUT_SRC_CLK 199U -#define NXP_S32_P3_DBG_TS_CLK 200U -#define NXP_S32_P3_REG_INTF_CLK 201U -#define NXP_S32_P3_SYS_MON1_CLK 202U -#define NXP_S32_P3_SYS_MON2_CLK 203U -#define NXP_S32_P3_SYS_MON3_CLK 204U -#define NXP_S32_P4_CLKOUT_SRC_CLK 205U -#define NXP_S32_P4_DSPI60_CLK 206U -#define NXP_S32_P4_EMIOS_LCU_CLK 207U -#define NXP_S32_P4_LIN_CLK 208U -#define NXP_S32_P4_PSI5_125K_CLK 209U -#define NXP_S32_P4_PSI5_189K_CLK 210U -#define NXP_S32_P4_PSI5_S_BAUD_CLK 211U -#define NXP_S32_P4_PSI5_S_CORE_CLK 212U -#define NXP_S32_P4_PSI5_S_TRIG0_CLK 213U -#define NXP_S32_P4_PSI5_S_TRIG1_CLK 214U -#define NXP_S32_P4_PSI5_S_TRIG2_CLK 215U -#define NXP_S32_P4_PSI5_S_TRIG3_CLK 216U -#define NXP_S32_P4_PSI5_S_UART_CLK 217U -#define NXP_S32_P4_PSI5_S_WDOG0_CLK 218U -#define NXP_S32_P4_PSI5_S_WDOG1_CLK 219U -#define NXP_S32_P4_PSI5_S_WDOG2_CLK 220U -#define NXP_S32_P4_PSI5_S_WDOG3_CLK 221U -#define NXP_S32_P4_QSPI0_2X_CLK 222U -#define NXP_S32_P4_QSPI0_1X_CLK 223U -#define NXP_S32_P4_QSPI1_2X_CLK 224U -#define NXP_S32_P4_QSPI1_1X_CLK 225U -#define NXP_S32_P4_REG_INTF_2X_CLK 226U -#define NXP_S32_P4_REG_INTF_CLK 227U -#define NXP_S32_P4_SDHC_IP_CLK 228U -#define NXP_S32_P4_SDHC_IP_DIV2_CLK 229U -#define NXP_S32_P5_DIPORT_CLK 230U -#define NXP_S32_P5_AE_CLK 231U -#define NXP_S32_P5_CANXL_PE_CLK 232U -#define NXP_S32_P5_CANXL_CHI_CLK 233U -#define NXP_S32_P5_CLKOUT_SRC_CLK 234U -#define NXP_S32_P5_LIN_CLK 235U -#define NXP_S32_P5_REG_INTF_CLK 236U -#define NXP_S32_P6_REG_INTF_CLK 237U -#define NXP_S32_PIT0_CLK 238U -#define NXP_S32_PIT1_CLK 239U -#define NXP_S32_PIT4_CLK 240U -#define NXP_S32_PIT5_CLK 241U -#define NXP_S32_P0_PSI5_1US_CLK 242U -#define NXP_S32_PSI5_0_CLK 243U -#define NXP_S32_P4_PSI5_1US_CLK 244U -#define NXP_S32_PSI5_1_CLK 245U -#define NXP_S32_PSI5S_0_CLK 246U -#define NXP_S32_PSI5S_1_CLK 247U -#define NXP_S32_QSPI0_CLK 248U -#define NXP_S32_QSPI1_CLK 249U -#define NXP_S32_RTU0_CORE_MON1_CLK 250U -#define NXP_S32_RTU0_CORE_MON2_CLK 251U -#define NXP_S32_RTU0_CORE_DIV2_MON1_CLK 252U -#define NXP_S32_RTU0_CORE_DIV2_MON2_CLK 253U -#define NXP_S32_RTU0_CORE_DIV2_MON3_CLK 254U -#define NXP_S32_RTU0_REG_INTF_CLK 255U -#define NXP_S32_RTU1_CORE_MON1_CLK 256U -#define NXP_S32_RTU1_CORE_MON2_CLK 257U -#define NXP_S32_RTU1_CORE_DIV2_MON1_CLK 258U -#define NXP_S32_RTU1_CORE_DIV2_MON2_CLK 259U -#define NXP_S32_RTU1_CORE_DIV2_MON3_CLK 260U -#define NXP_S32_RTU1_REG_INTF_CLK 261U -#define NXP_S32_P4_SDHC_CLK 262U -#define NXP_S32_RXLUT_CLK 263U -#define NXP_S32_SDHC0_CLK 264U -#define NXP_S32_SINC_CLK 265U -#define NXP_S32_SIPI0_CLK 266U -#define NXP_S32_SIPI1_CLK 267U -#define NXP_S32_SIUL2_0_CLK 268U -#define NXP_S32_SIUL2_1_CLK 269U -#define NXP_S32_SIUL2_4_CLK 270U -#define NXP_S32_SIUL2_5_CLK 271U -#define NXP_S32_P0_DSPI_CLK 272U -#define NXP_S32_SPI0_CLK 273U -#define NXP_S32_SPI1_CLK 274U -#define NXP_S32_P1_DSPI_CLK 275U -#define NXP_S32_SPI2_CLK 276U -#define NXP_S32_SPI3_CLK 277U -#define NXP_S32_SPI4_CLK 278U -#define NXP_S32_P4_DSPI_CLK 279U -#define NXP_S32_SPI5_CLK 280U -#define NXP_S32_SPI6_CLK 281U -#define NXP_S32_SPI7_CLK 282U -#define NXP_S32_P5_DSPI_CLK 283U -#define NXP_S32_SPI8_CLK 284U -#define NXP_S32_SPI9_CLK 285U -#define NXP_S32_SRX0_CLK 286U -#define NXP_S32_SRX1_CLK 287U +#define NXP_S32_P1_NETC_AXI_CLK 192U +#define NXP_S32_P1_LIN_CLK 193U +#define NXP_S32_P1_REG_INTF_CLK 194U +#define NXP_S32_P2_DBG_ATB_CLK 195U +#define NXP_S32_P2_REG_INTF_CLK 196U +#define NXP_S32_P3_AES_CLK 197U +#define NXP_S32_P3_CLKOUT_SRC_CLK 198U +#define NXP_S32_P3_DBG_TS_CLK 199U +#define NXP_S32_P3_REG_INTF_CLK 200U +#define NXP_S32_P3_SYS_MON1_CLK 201U +#define NXP_S32_P3_SYS_MON2_CLK 202U +#define NXP_S32_P3_SYS_MON3_CLK 203U +#define NXP_S32_P4_CLKOUT_SRC_CLK 204U +#define NXP_S32_P4_DSPI60_CLK 205U +#define NXP_S32_P4_EMIOS_LCU_CLK 206U +#define NXP_S32_P4_LIN_CLK 207U +#define NXP_S32_P4_PSI5_125K_CLK 208U +#define NXP_S32_P4_PSI5_189K_CLK 209U +#define NXP_S32_P4_PSI5_S_BAUD_CLK 210U +#define NXP_S32_P4_PSI5_S_CORE_CLK 211U +#define NXP_S32_P4_PSI5_S_TRIG0_CLK 212U +#define NXP_S32_P4_PSI5_S_TRIG1_CLK 213U +#define NXP_S32_P4_PSI5_S_TRIG2_CLK 214U +#define NXP_S32_P4_PSI5_S_TRIG3_CLK 215U +#define NXP_S32_P4_PSI5_S_UART_CLK 216U +#define NXP_S32_P4_PSI5_S_WDOG0_CLK 217U +#define NXP_S32_P4_PSI5_S_WDOG1_CLK 218U +#define NXP_S32_P4_PSI5_S_WDOG2_CLK 219U +#define NXP_S32_P4_PSI5_S_WDOG3_CLK 220U +#define NXP_S32_P4_QSPI0_2X_CLK 221U +#define NXP_S32_P4_QSPI0_1X_CLK 222U +#define NXP_S32_P4_QSPI1_2X_CLK 223U +#define NXP_S32_P4_QSPI1_1X_CLK 224U +#define NXP_S32_P4_REG_INTF_2X_CLK 225U +#define NXP_S32_P4_REG_INTF_CLK 226U +#define NXP_S32_P4_SDHC_IP_CLK 227U +#define NXP_S32_P4_SDHC_IP_DIV2_CLK 228U +#define NXP_S32_P5_DIPORT_CLK 229U +#define NXP_S32_P5_AE_CLK 230U +#define NXP_S32_P5_CANXL_PE_CLK 231U +#define NXP_S32_P5_CANXL_CHI_CLK 232U +#define NXP_S32_P5_CLKOUT_SRC_CLK 233U +#define NXP_S32_P5_LIN_CLK 234U +#define NXP_S32_P5_REG_INTF_CLK 235U +#define NXP_S32_P6_REG_INTF_CLK 236U +#define NXP_S32_PIT0_CLK 237U +#define NXP_S32_PIT1_CLK 238U +#define NXP_S32_PIT4_CLK 239U +#define NXP_S32_PIT5_CLK 240U +#define NXP_S32_P0_PSI5_1US_CLK 241U +#define NXP_S32_PSI5_0_CLK 242U +#define NXP_S32_P4_PSI5_1US_CLK 243U +#define NXP_S32_PSI5_1_CLK 244U +#define NXP_S32_PSI5S_0_CLK 245U +#define NXP_S32_PSI5S_1_CLK 246U +#define NXP_S32_QSPI0_CLK 247U +#define NXP_S32_QSPI1_CLK 248U +#define NXP_S32_RTU0_CORE_MON1_CLK 249U +#define NXP_S32_RTU0_CORE_MON2_CLK 250U +#define NXP_S32_RTU0_CORE_DIV2_MON1_CLK 251U +#define NXP_S32_RTU0_CORE_DIV2_MON2_CLK 252U +#define NXP_S32_RTU0_CORE_DIV2_MON3_CLK 253U +#define NXP_S32_RTU0_REG_INTF_CLK 254U +#define NXP_S32_RTU1_CORE_MON1_CLK 255U +#define NXP_S32_RTU1_CORE_MON2_CLK 256U +#define NXP_S32_RTU1_CORE_DIV2_MON1_CLK 257U +#define NXP_S32_RTU1_CORE_DIV2_MON2_CLK 258U +#define NXP_S32_RTU1_CORE_DIV2_MON3_CLK 259U +#define NXP_S32_RTU1_REG_INTF_CLK 260U +#define NXP_S32_P4_SDHC_CLK 261U +#define NXP_S32_RXLUT_CLK 262U +#define NXP_S32_SDHC0_CLK 263U +#define NXP_S32_SINC_CLK 264U +#define NXP_S32_SIPI0_CLK 265U +#define NXP_S32_SIPI1_CLK 266U +#define NXP_S32_SIUL2_0_CLK 267U +#define NXP_S32_SIUL2_1_CLK 268U +#define NXP_S32_SIUL2_4_CLK 269U +#define NXP_S32_SIUL2_5_CLK 270U +#define NXP_S32_P0_DSPI_CLK 271U +#define NXP_S32_SPI0_CLK 272U +#define NXP_S32_SPI1_CLK 273U +#define NXP_S32_P1_DSPI_CLK 274U +#define NXP_S32_SPI2_CLK 275U +#define NXP_S32_SPI3_CLK 276U +#define NXP_S32_SPI4_CLK 277U +#define NXP_S32_P4_DSPI_CLK 278U +#define NXP_S32_SPI5_CLK 279U +#define NXP_S32_SPI6_CLK 280U +#define NXP_S32_SPI7_CLK 281U +#define NXP_S32_P5_DSPI_CLK 282U +#define NXP_S32_SPI8_CLK 283U +#define NXP_S32_SPI9_CLK 284U +#define NXP_S32_SRX0_CLK 285U +#define NXP_S32_SRX1_CLK 286U +#define NXP_S32_CORE_PLL_REFCLKOUT 287U +#define NXP_S32_CORE_PLL_FBCLKOUT 288U +#define NXP_S32_PERIPH_PLL_REFCLKOUT 289U +#define NXP_S32_PERIPH_PLL_FBCLKOUT 290U #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NXP_S32Z2_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/r7fa4m1xxxxxx-clock.h b/include/zephyr/dt-bindings/clock/r7fa4m1xxxxxx-clock.h new file mode 100644 index 000000000000000..355c4982a3d3c28 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/r7fa4m1xxxxxx-clock.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DT_BINDINGS_CLOCK_R7FA4M1XXXXXX_CLOCK_H_ +#define ZEPHYR_DT_BINDINGS_CLOCK_R7FA4M1XXXXXX_CLOCK_H_ + +#include + +#endif /* ZEPHYR_DT_BINDINGS_CLOCK_R7FA4M1XXXXXX_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 000000000000000..d0f01809795c9a5 --- /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/renesas-ra-cgc.h b/include/zephyr/dt-bindings/clock/renesas-ra-cgc.h new file mode 100644 index 000000000000000..31bb65ecc4593a4 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/renesas-ra-cgc.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DT_BINDINGS_CLOCK_RENESAS_RA_CGC_H_ +#define ZEPHYR_DT_BINDINGS_CLOCK_RENESAS_RA_CGC_H_ + +#define RA_CLOCK(grp, func, ch) ((grp << 28) | (func << 20) | ch) + +#define RA_CLOCK_GROUP(mod) (((mod >> 28) & 0xF) * 4) +#define RA_CLOCK_BIT(mod) BIT(((mod >> 20) & 0xFF) - ((mod >> 0) & 0xF)) + +#define RA_CLOCK_DMAC(channel) RA_CLOCK(0, 22, channel) +#define RA_CLOCK_DTC(channel) RA_CLOCK(0, 22, channel) +#define RA_CLOCK_CAN(channel) RA_CLOCK(1, 2, channel) +#define RA_CLOCK_CEC(channel) RA_CLOCK(1, 3U, channel) +#define RA_CLOCK_I3C(channel) RA_CLOCK(1, 4U, channel) +#define RA_CLOCK_IRDA(channel) RA_CLOCK(1, 5U, channel) +#define RA_CLOCK_QSPI(channel) RA_CLOCK(1, 6U, channel) +#define RA_CLOCK_IIC(channel) RA_CLOCK(1, 9U, channel) +#define RA_CLOCK_USBFS(channel) RA_CLOCK(1, 11U, channel) +#define RA_CLOCK_USBHS(channel) RA_CLOCK(1, 12U, channel) +#define RA_CLOCK_EPTPC(channel) RA_CLOCK(1, 13U, channel) +#define RA_CLOCK_ETHER(channel) RA_CLOCK(1, 15U, channel) +#define RA_CLOCK_OSPI(channel) RA_CLOCK(1, 16U, channel) +#define RA_CLOCK_SPI(channel) RA_CLOCK(1, 19U, channel) +#define RA_CLOCK_SCI(channel) RA_CLOCK(1, 31U, channel) +#define RA_CLOCK_CAC(channel) RA_CLOCK(2, 0U, channel) +#define RA_CLOCK_CRC(channel) RA_CLOCK(2, 1U, channel) +#define RA_CLOCK_PDC(channel) RA_CLOCK(2, 2U, channel) +#define RA_CLOCK_CTSU(channel) RA_CLOCK(2, 3U, channel) +#define RA_CLOCK_SLCDC(channel) RA_CLOCK(2, 4U, channel) +#define RA_CLOCK_GLCDC(channel) RA_CLOCK(2, 4U, channel) +#define RA_CLOCK_JPEG(channel) RA_CLOCK(2, 5U, channel) +#define RA_CLOCK_DRW(channel) RA_CLOCK(2, 6U, channel) +#define RA_CLOCK_SSI(channel) RA_CLOCK(2, 8U, channel) +#define RA_CLOCK_SRC(channel) RA_CLOCK(2, 9U, channel) +#define RA_CLOCK_SDHIMMC(channel) RA_CLOCK(2, 12U, channel) +#define RA_CLOCK_DOC(channel) RA_CLOCK(2, 13U, channel) +#define RA_CLOCK_ELC(channel) RA_CLOCK(2, 14U, channel) +#define RA_CLOCK_CEU(channel) RA_CLOCK(2, 16U, channel) +#define RA_CLOCK_TFU(channel) RA_CLOCK(2, 20U, channel) +#define RA_CLOCK_IIRFA(channel) RA_CLOCK(2, 21U, channel) +#define RA_CLOCK_CANFD(channel) RA_CLOCK(2, 27U, channel) +#define RA_CLOCK_TRNG(channel) RA_CLOCK(2, 28U, channel) +#define RA_CLOCK_SCE(channel) RA_CLOCK(2, 31U, channel) +#define RA_CLOCK_AES(channel) RA_CLOCK(2, 31U, channel) +#define RA_CLOCK_POEG(channel) RA_CLOCK(3, 14U, channel) +#define RA_CLOCK_ADC(channel) RA_CLOCK(3, 16U, channel) +#define RA_CLOCK_SDADC(channel) RA_CLOCK(3, 17U, channel) +#define RA_CLOCK_DAC8(channel) RA_CLOCK(3, 19U, channel) +#define RA_CLOCK_DAC(channel) RA_CLOCK(3, 20U, channel) +#define RA_CLOCK_TSN(channel) RA_CLOCK(3, 22U, channel) +#define RA_CLOCK_ACMPHS(channel) RA_CLOCK(3, 28U, channel) +#define RA_CLOCK_ACMPLP(channel) RA_CLOCK(3, 29U, channel) +#define RA_CLOCK_OPAMP(channel) RA_CLOCK(3, 31U, channel) +#define RA_CLOCK_AGT(channel) RA_CLOCK(4, 3U, channel) +#define RA_CLOCK_KEY(channel) RA_CLOCK(4, 4U, channel) +#define RA_CLOCK_ULPT(channel) RA_CLOCK(4, 9U, channel) +#define RA_CLOCK_GPT(channel) RA_CLOCK(5, 31U, channel) + +#endif /* ZEPHYR_DT_BINDINGS_CLOCK_RENESAS_RA_CGC_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 000000000000000..07522be66329c89 --- /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 000000000000000..030ec2d939bbe85 --- /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 b48aa7d2ef1a200..224bd1517d5e7e0 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 309c31877e3f07c..116457358305c82 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 e65be1c72e363de..571014dd2f09722 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 90614f385b987a5..377eb4fdaad73cb 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 e0edf742d79758f..93355865fdd0660 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 fd404f1001ca9df..92d3b7e12211a1f 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 3752a06b9a01e09..86d93e83d1479ec 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 d2720fa0b7f1110..0cc0b1be2dc8df5 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 c5172c4e6b645c9..070f3b3aad469f8 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 d3507bc2fdb11a9..02ed14f2a7bc40a 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 a6e5565a2b5efd6..5c4d80a2b34ec8a 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 ae580af85b4565e..1dd1fbb90c29380 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 3a042bc34e9414a..8249a1bf17155e9 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 900f77620f8508a..6f240fb37b30b42 100644 --- a/include/zephyr/dt-bindings/clock/stm32u5_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32u5_clock.h @@ -1,37 +1,38 @@ /* * Copyright (c) 2022 Linaro Limited + * Copyright (c) 2023 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ #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 @@ -87,8 +88,8 @@ #define USART1_SEL(val) STM32_CLOCK(val, 3, 0, CCIPR1_REG) #define USART2_SEL(val) STM32_CLOCK(val, 3, 2, CCIPR1_REG) #define USART3_SEL(val) STM32_CLOCK(val, 3, 4, CCIPR1_REG) -#define USART4_SEL(val) STM32_CLOCK(val, 3, 6, CCIPR1_REG) -#define USART5_SEL(val) STM32_CLOCK(val, 3, 8, CCIPR1_REG) +#define UART4_SEL(val) STM32_CLOCK(val, 3, 6, CCIPR1_REG) +#define UART5_SEL(val) STM32_CLOCK(val, 3, 8, CCIPR1_REG) #define I2C1_SEL(val) STM32_CLOCK(val, 3, 10, CCIPR1_REG) #define I2C2_SEL(val) STM32_CLOCK(val, 3, 12, CCIPR1_REG) #define I2C4_SEL(val) STM32_CLOCK(val, 3, 14, CCIPR1_REG) @@ -106,7 +107,14 @@ #define SAE_SEL(val) STM32_CLOCK(val, 1, 11, CCIPR2_REG) #define RNG_SEL(val) STM32_CLOCK(val, 3, 12, CCIPR2_REG) #define SDMMC_SEL(val) STM32_CLOCK(val, 1, 14, CCIPR2_REG) +#define DSIHOST_SEL(val) STM32_CLOCK(val, 1, 15, CCIPR2_REG) +#define USART6_SEL(val) STM32_CLOCK(val, 1, 16, CCIPR2_REG) +#define LTDC_SEL(val) STM32_CLOCK(val, 1, 18, CCIPR2_REG) #define OCTOSPI_SEL(val) STM32_CLOCK(val, 3, 20, CCIPR2_REG) +#define HSPI_SEL(val) STM32_CLOCK(val, 3, 22, CCIPR2_REG) +#define I2C5_SEL(val) STM32_CLOCK(val, 3, 24, CCIPR2_REG) +#define I2C6_SEL(val) STM32_CLOCK(val, 3, 26, CCIPR2_REG) +#define USBPHYC_SEL(val) STM32_CLOCK(val, 3, 30, CCIPR2_REG) /** CCIPR3 devices */ #define LPUART1_SEL(val) STM32_CLOCK(val, 7, 0, CCIPR3_REG) #define SPI3_SEL(val) STM32_CLOCK(val, 3, 3, CCIPR3_REG) diff --git a/include/zephyr/dt-bindings/clock/stm32wb_clock.h b/include/zephyr/dt-bindings/clock/stm32wb_clock.h index f339f2ac19fe58f..d90b640d2dc01c3 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 757cb8a05524075..4dc686e8943afbf 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 @@ -72,6 +72,8 @@ #define CCIPR1_REG 0xE0 #define CCIPR2_REG 0xE4 #define CCIPR3_REG 0xE8 +/** @brief RCC_BCDR1 register offset (RM0493.pdf) */ +#define BCDR1_REG 0xF0 /** @brief Device clk sources selection helpers */ /** CCIPR1 devices */ @@ -90,5 +92,7 @@ #define I2C3_SEL(val) STM32_CLOCK(val, 3, 6, CCIPR3_REG) #define LPTIM1_SEL(val) STM32_CLOCK(val, 3, 10, CCIPR3_REG) #define ADC_SEL(val) STM32_CLOCK(val, 7, 12, CCIPR3_REG) +/** BCDR1 devices */ +#define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BCDR1_REG) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WBA_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32wl_clock.h b/include/zephyr/dt-bindings/clock/stm32wl_clock.h index 7bff72937c17bc4..081490d37e15ae6 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 000000000000000..e084825da4c7547 --- /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/gpio/renesas-rzt2m-gpio.h b/include/zephyr/dt-bindings/gpio/renesas-rzt2m-gpio.h new file mode 100644 index 000000000000000..8bd26d46434d205 --- /dev/null +++ b/include/zephyr/dt-bindings/gpio/renesas-rzt2m-gpio.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_RENESAS_RZT2M_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_RENESAS_RZT2M_H_ +#include + +#define RZT2M_GPIO_DRIVE_OFFSET 8 +#define RZT2M_GPIO_DRIVE_MASK GENMASK(RZT2M_GPIO_DRIVE_OFFSET + 2, RZT2M_GPIO_DRIVE_OFFSET) + +/** + * @brief Select GPIO pin drive strength + */ +#define RZT2M_GPIO_DRIVE_LOW (0U << RZT2M_GPIO_DRIVE_OFFSET) +#define RZT2M_GPIO_DRIVE_MIDDLE (1U << RZT2M_GPIO_DRIVE_OFFSET) +#define RZT2M_GPIO_DRIVE_HIGH (2U << RZT2M_GPIO_DRIVE_OFFSET) +#define RZT2M_GPIO_DRIVE_ULTRA_HIGH (3U << RZT2M_GPIO_DRIVE_OFFSET) + +#define RZT2M_GPIO_SCHMITT_TRIGGER_OFFSET 10 +#define RZT2M_GPIO_SCHMITT_TRIGGER_MASK BIT(RZT2M_GPIO_SCHMITT_TRIGGER_OFFSET) + +/** + * @brief Enable GPIO pin schmitt trigger + */ +#define RZT2M_GPIO_SCHMITT_TRIGGER BIT(RZT2M_GPIO_SCHMITT_TRIGGER_OFFSET) + +#define RZT2M_GPIO_SLEW_RATE_OFFSET 11 +#define RZT2M_GPIO_SLEW_RATE_MASK BIT(RZT2M_GPIO_SLEW_RATE_OFFSET) + +/** + * @brief Select GPIO pin slew rate + */ +#define RZT2M_GPIO_SLEW_RATE_SLOW 0U +#define RZT2M_GPIO_SLEW_RATE_FAST BIT(RZT2M_GPIO_SLEW_RATE_OFFSET) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_RENESAS_RZT2M_H_ */ diff --git a/include/zephyr/dt-bindings/i2c/it8xxx2-i2c.h b/include/zephyr/dt-bindings/i2c/it8xxx2-i2c.h index a42879d1331354f..199e813308ec5a2 100644 --- a/include/zephyr/dt-bindings/i2c/it8xxx2-i2c.h +++ b/include/zephyr/dt-bindings/i2c/it8xxx2-i2c.h @@ -20,4 +20,12 @@ #define CGC_OFFSET_SMBB ((IT8XXX2_ECPM_CGCTRL4R_OFF << 8) | 0x08) #define CGC_OFFSET_SMBA ((IT8XXX2_ECPM_CGCTRL4R_OFF << 8) | 0x04) +/* I2C channel switch selection */ +#define I2C_CHA_LOCATE 0 +#define I2C_CHB_LOCATE 1 +#define I2C_CHC_LOCATE 2 +#define I2C_CHD_LOCATE 3 +#define I2C_CHE_LOCATE 4 +#define I2C_CHF_LOCATE 5 + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_I2C_IT8XXX2_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 000000000000000..83a8035551f2f04 --- /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 73d5f49b9bb3d69..34dd00f85140e8e 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 000000000000000..65d4b108b03abf2 --- /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 new file mode 100644 index 000000000000000..4df6bfeae52efd5 --- /dev/null +++ b/include/zephyr/dt-bindings/interrupt-controller/renesas-ra-icu.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DT_BINDINGS_INTERRUPT_CONTROLLER_RENESAS_RA_ICU_H_ +#define ZEPHYR_DT_BINDINGS_INTERRUPT_CONTROLLER_RENESAS_RA_ICU_H_ + +#define RA_ICU_IRQ_UNSPECIFIED (-1) + +#define RA_ICU_PORT_IRQ0 (1 << 8) +#define RA_ICU_PORT_IRQ1 (2 << 8) +#define RA_ICU_PORT_IRQ2 (3 << 8) +#define RA_ICU_PORT_IRQ3 (4 << 8) +#define RA_ICU_PORT_IRQ4 (5 << 8) +#define RA_ICU_PORT_IRQ5 (6 << 8) +#define RA_ICU_PORT_IRQ6 (7 << 8) +#define RA_ICU_PORT_IRQ7 (8 << 8) +#define RA_ICU_PORT_IRQ8 (9 << 8) +#define RA_ICU_PORT_IRQ9 (10 << 8) +#define RA_ICU_PORT_IRQ10 (11 << 8) +#define RA_ICU_PORT_IRQ11 (12 << 8) +#define RA_ICU_PORT_IRQ12 (13 << 8) +#define RA_ICU_PORT_IRQ14 (15 << 8) +#define RA_ICU_PORT_IRQ15 (16 << 8) +#define RA_ICU_DMAC0_INT (17 << 8) +#define RA_ICU_DMAC1_INT (18 << 8) +#define RA_ICU_DMAC2_INT (19 << 8) +#define RA_ICU_DMAC3_INT (20 << 8) +#define RA_ICU_DTC_COMPLETE (21 << 8) +#define RA_ICU_ICU_SNZCANCEL (23 << 8) +#define RA_ICU_FCU_FRDYI (24 << 8) +#define RA_ICU_LVD_LVD1 (25 << 8) +#define RA_ICU_LVD_LVD2 (26 << 8) +#define RA_ICU_VBATT_LVD (27 << 8) +#define RA_ICU_MOSC_STOP (28 << 8) +#define RA_ICU_SYSTEM_SNZREQ (29 << 8) +#define RA_ICU_AGT0_AGTI (30 << 8) +#define RA_ICU_AGT0_AGTCMAI (31 << 8) +#define RA_ICU_AGT0_AGTCMBI (32 << 8) +#define RA_ICU_AGT1_AGTI (33 << 8) +#define RA_ICU_AGT1_AGTCMAI (34 << 8) +#define RA_ICU_AGT1_AGTCMBI (35 << 8) +#define RA_ICU_IWDT_NMIUNDF (36 << 8) +#define RA_ICU_WDT_NMIUNDF (37 << 8) +#define RA_ICU_RTC_ALM (38 << 8) +#define RA_ICU_RTC_PRD (39 << 8) +#define RA_ICU_RTC_CUP (40 << 8) +#define RA_ICU_ADC140_ADI (41 << 8) +#define RA_ICU_ADC140_GBADI (42 << 8) +#define RA_ICU_ADC140_CMPAI (43 << 8) +#define RA_ICU_ADC140_CMPBI (44 << 8) +#define RA_ICU_ADC140_WCMPM (45 << 8) +#define RA_ICU_ADC140_WCMPUM (46 << 8) +#define RA_ICU_ACMP_LP0 (47 << 8) +#define RA_ICU_ACMP_LP1 (48 << 8) +#define RA_ICU_USBFS_D0FIFO (49 << 8) +#define RA_ICU_USBFS_D1FIFO (50 << 8) +#define RA_ICU_USBFS_USBI (51 << 8) +#define RA_ICU_USBFS_USBR (52 << 8) +#define RA_ICU_IIC0_RXI (53 << 8) +#define RA_ICU_IIC0_TXI (54 << 8) +#define RA_ICU_IIC0_TEI (55 << 8) +#define RA_ICU_IIC0_EEI (56 << 8) +#define RA_ICU_IIC0_WUI (57 << 8) +#define RA_ICU_IIC1_RXI (58 << 8) +#define RA_ICU_IIC1_TXI (59 << 8) +#define RA_ICU_IIC1_TEI (60 << 8) +#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 (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 000000000000000..e723227a02210e4 --- /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 000000000000000..09ad0ae361bfe24 --- /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 000000000000000..ccd47addf11130d --- /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/memory-controller/nxp,flexram.h b/include/zephyr/dt-bindings/memory-controller/nxp,flexram.h new file mode 100644 index 000000000000000..2c35e655fc995de --- /dev/null +++ b/include/zephyr/dt-bindings/memory-controller/nxp,flexram.h @@ -0,0 +1,15 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MEMORY_CONTROLLER_NXP_FLEXRAM_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_MEMORY_CONTROLLER_NXP_FLEXRAM_H_ + +#define FLEXRAM_NONE 0 +#define FLEXRAM_OCRAM 1 +#define FLEXRAM_DTCM 2 +#define FLEXRAM_ITCM 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MEMORY_CONTROLLER_NXP_FLEXRAM_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 000000000000000..b961c27facf3336 --- /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 000000000000000..2eda20f9cb36045 --- /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 000000000000000..5d97a79b176f38e --- /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 000000000000000..f8713bec265902e --- /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/imx8qm-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/imx8qm-pinctrl.h new file mode 100644 index 000000000000000..9748a2ce4aa8081 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/imx8qm-pinctrl.h @@ -0,0 +1,18 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_IMX8QM_PINCTRL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_IMX8QM_PINCTRL_H_ + +/* values for pad field */ +#define SC_P_UART0_RTS_B 23 +#define SC_P_UART0_CTS_B 24 + +/* mux values */ +#define IMX8QM_DMA_LPUART2_RX_UART0_RTS_B 2 /* UART0_RTS_B ---> DMA_LPUART2_RX */ +#define IMX8QM_DMA_LPUART2_TX_UART0_CTS_B 2 /* DMA_LPUART2_TX ---> UART0_CTS_B */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_IMX8QM_PINCTRL_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/imx8qxp-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/imx8qxp-pinctrl.h new file mode 100644 index 000000000000000..0143540f6bf6c22 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/imx8qxp-pinctrl.h @@ -0,0 +1,18 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_IMX8QXP_PINCTRL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_IMX8QXP_PINCTRL_H_ + +/* values for pad field */ +#define SC_P_UART2_TX 113 +#define SC_P_UART2_RX 114 + +/* mux values */ +#define IMX8QXP_DMA_LPUART2_RX_UART2_RX 0 /* UART2_RX ---> DMA_LPUART2_RX */ +#define IMX8QXP_DMA_LPUART2_TX_UART2_TX 0 /* DMA_LPUART2_TX ---> UART2_TX */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_IMX8QXP_PINCTRL_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h index b2dcd7ae6c98fbe..9d7f8c2312fe139 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 000000000000000..3fb83a3a7a4b0fb --- /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-rzt2m-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/renesas-rzt2m-pinctrl.h new file mode 100644 index 000000000000000..ed1cbf7ee96b95c --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/renesas-rzt2m-pinctrl.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __RENESAS_RZT2M_PINCTRL_H__ +#define __RENESAS_RZT2M_PINCTRL_H__ + +#define RZT2M_PINMUX(port, pin, func) ((port << 16) | (pin << 8) | func) + +#define UART0TX_P16_5 RZT2M_PINMUX(16, 5, 1) +#define UART0RX_P16_6 RZT2M_PINMUX(16, 6, 2) + +#define UART3TX_P18_0 RZT2M_PINMUX(18, 0, 4) +#define UART3RX_P17_7 RZT2M_PINMUX(17, 7, 4) + +#endif /* __RENESAS_RZT2M_PINCTRL_H__ */ diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r7fa4m1xxxxxx.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r7fa4m1xxxxxx.h new file mode 100644 index 000000000000000..e54667576533d8d --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r7fa4m1xxxxxx.h @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_R7FA4M1XXXXXX_H_ +#define ZEPHYR_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_R7FA4M1XXXXXX_H_ + +#include + +#define P000_AMP0P RA_PINCFG__40(0, 0, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P000_AN000 RA_PINCFG__40(0, 0, 0x01, RA_PINCFG_ANALOG) +#define P000_TS21 RA_PINCFG__40(0, 0, 0x0C, RA_PINCFG_FUNC) +#define P001_AMP0M RA_PINCFG__40(0, 1, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P001_AN001 RA_PINCFG__40(0, 1, 0x01, RA_PINCFG_ANALOG) +#define P001_TS22 RA_PINCFG__40(0, 1, 0x0C, RA_PINCFG_FUNC) +#define P002_AMP0O RA_PINCFG__48(0, 2, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P002_AN002 RA_PINCFG__48(0, 2, 0x01, RA_PINCFG_ANALOG) +#define P003_AMP1O RA_PINCFG__64(0, 3, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P003_AN003 RA_PINCFG__64(0, 3, 0x01, RA_PINCFG_ANALOG) +#define P004_AMP2O RA_PINCFG__64(0, 4, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P004_AN004 RA_PINCFG__64(0, 4, 0x01, RA_PINCFG_ANALOG) +#define P005_AMP3P RA_PINCFG_100(0, 5, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P005_AN011 RA_PINCFG_100(0, 5, 0x01, RA_PINCFG_ANALOG) +#define P006_AMP3M RA_PINCFG_100(0, 6, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P006_AN012 RA_PINCFG_100(0, 6, 0x01, RA_PINCFG_ANALOG) +#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, 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) +#define P100_GTETRGA RA_PINCFG__40(1, 0, 0x02, RA_PINCFG_FUNC) +#define P100_GTIOC5B RA_PINCFG__40(1, 0, 0x03, RA_PINCFG_FUNC) +#define P100_KR00 RA_PINCFG__40(1, 0, 0x08, RA_PINCFG_FUNC) +#define P100_MISO0 RA_PINCFG__40(1, 0, 0x04, RA_PINCFG_FUNC) +#define P100_MISOA RA_PINCFG__40(1, 0, 0x06, RA_PINCFG_FUNC) +#define P100_RXD0 RA_PINCFG__40(1, 0, 0x04, RA_PINCFG_FUNC) +#define P100_SCK1 RA_PINCFG__40(1, 0, 0x05, RA_PINCFG_FUNC) +#define P100_SCL0 RA_PINCFG__40(1, 0, 0x04, RA_PINCFG_FUNC) +#define P100_SCL1 RA_PINCFG__40(1, 0, 0x07, RA_PINCFG_FUNC) +#define P100_VL1 RA_PINCFG__40(1, 0, 0x0D, RA_PINCFG_FUNC) +#define P101_AGTEE0 RA_PINCFG__40(1, 1, 0x01, RA_PINCFG_FUNC) +#define P101_AN021 RA_PINCFG__40(1, 1, 0x01, RA_PINCFG_ANALOG) +#define P101_CMPREF0 RA_PINCFG__40(1, 1, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P101_CTS1_RTS1 RA_PINCFG__40(1, 1, 0x05, RA_PINCFG_FUNC) +#define P101_GTETRGB RA_PINCFG__40(1, 1, 0x02, RA_PINCFG_FUNC) +#define P101_GTIOC5A RA_PINCFG__40(1, 1, 0x03, RA_PINCFG_FUNC) +#define P101_KR01 RA_PINCFG__40(1, 1, 0x08, RA_PINCFG_FUNC) +#define P101_MOSI0 RA_PINCFG__40(1, 1, 0x04, RA_PINCFG_FUNC) +#define P101_MOSIA RA_PINCFG__40(1, 1, 0x06, RA_PINCFG_FUNC) +#define P101_SDA0 RA_PINCFG__40(1, 1, 0x04, RA_PINCFG_FUNC) +#define P101_SDA1 RA_PINCFG__40(1, 1, 0x07, RA_PINCFG_FUNC) +#define P101_SS1 RA_PINCFG__40(1, 1, 0x05, RA_PINCFG_FUNC) +#define P101_TXD0 RA_PINCFG__40(1, 1, 0x04, RA_PINCFG_FUNC) +#define P101_VL2 RA_PINCFG__40(1, 1, 0x0D, RA_PINCFG_FUNC) +#define P102_ADTRG0 RA_PINCFG__40(1, 2, 0x0A, RA_PINCFG_FUNC) +#define P102_AGTO0 RA_PINCFG__40(1, 2, 0x01, RA_PINCFG_FUNC) +#define P102_AN020 RA_PINCFG__40(1, 2, 0x01, RA_PINCFG_ANALOG) +#define P102_CMPIN1 RA_PINCFG__40(1, 2, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P102_CRX0 RA_PINCFG__40(1, 2, 0x10, RA_PINCFG_FUNC) +#define P102_GTIOC2B RA_PINCFG__40(1, 2, 0x03, RA_PINCFG_FUNC) +#define P102_GTOWLO RA_PINCFG__40(1, 2, 0x02, RA_PINCFG_FUNC) +#define P102_KR02 RA_PINCFG__40(1, 2, 0x08, RA_PINCFG_FUNC) +#define P102_MOSI2 RA_PINCFG__40(1, 2, 0x05, RA_PINCFG_FUNC) +#define P102_RSPCKA RA_PINCFG__40(1, 2, 0x06, RA_PINCFG_FUNC) +#define P102_SCK0 RA_PINCFG__40(1, 2, 0x04, RA_PINCFG_FUNC) +#define P102_SDA2 RA_PINCFG__40(1, 2, 0x05, RA_PINCFG_FUNC) +#define P102_TXD2 RA_PINCFG__40(1, 2, 0x05, RA_PINCFG_FUNC) +#define P102_VL3 RA_PINCFG__40(1, 2, 0x0D, RA_PINCFG_FUNC) +#define P103_AN019 RA_PINCFG__48(1, 3, 0x01, RA_PINCFG_ANALOG) +#define P103_CMPREF1 RA_PINCFG__48(1, 3, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P103_CTS0_RTS0 RA_PINCFG__48(1, 3, 0x04, RA_PINCFG_FUNC) +#define P103_CTX0 RA_PINCFG__48(1, 3, 0x10, RA_PINCFG_FUNC) +#define P103_GTIOC2A RA_PINCFG__48(1, 3, 0x03, RA_PINCFG_FUNC) +#define P103_GTOWUP RA_PINCFG__48(1, 3, 0x02, RA_PINCFG_FUNC) +#define P103_KR03 RA_PINCFG__48(1, 3, 0x08, RA_PINCFG_FUNC) +#define P103_SS0 RA_PINCFG__48(1, 3, 0x04, RA_PINCFG_FUNC) +#define P103_SSLA0 RA_PINCFG__48(1, 3, 0x06, RA_PINCFG_FUNC) +#define P103_VL4 RA_PINCFG__48(1, 3, 0x0D, RA_PINCFG_FUNC) +#define P104_COM0 RA_PINCFG__48(1, 4, 0x0D, RA_PINCFG_FUNC) +#define P104_GTETRGB RA_PINCFG__48(1, 4, 0x02, RA_PINCFG_FUNC) +#define P104_GTIOC1B RA_PINCFG__48(1, 4, 0x03, RA_PINCFG_FUNC) +#define P104_KR04 RA_PINCFG__48(1, 4, 0x08, RA_PINCFG_FUNC) +#define P104_MISO0 RA_PINCFG__48(1, 4, 0x04, RA_PINCFG_FUNC) +#define P104_RXD0 RA_PINCFG__48(1, 4, 0x04, RA_PINCFG_FUNC) +#define P104_SCL0 RA_PINCFG__48(1, 4, 0x04, RA_PINCFG_FUNC) +#define P104_SSLA1 RA_PINCFG__48(1, 4, 0x06, RA_PINCFG_FUNC) +#define P104_TS13 RA_PINCFG__48(1, 4, 0x0C, RA_PINCFG_FUNC) +#define P105_COM1 RA_PINCFG__64(1, 5, 0x0D, RA_PINCFG_FUNC) +#define P105_GTETRGA RA_PINCFG__64(1, 5, 0x02, RA_PINCFG_FUNC) +#define P105_GTIOC1A RA_PINCFG__64(1, 5, 0x03, RA_PINCFG_FUNC) +#define P105_KR05 RA_PINCFG__64(1, 5, 0x08, RA_PINCFG_FUNC) +#define P105_SSLA2 RA_PINCFG__64(1, 5, 0x06, RA_PINCFG_FUNC) +#define P105_TS34 RA_PINCFG__64(1, 5, 0x0C, RA_PINCFG_FUNC) +#define P106_COM2 RA_PINCFG__64(1, 6, 0x0D, RA_PINCFG_FUNC) +#define P106_GTIOC0B RA_PINCFG__64(1, 6, 0x03, RA_PINCFG_FUNC) +#define P106_KR06 RA_PINCFG__64(1, 6, 0x08, RA_PINCFG_FUNC) +#define P106_SSLA3 RA_PINCFG__64(1, 6, 0x06, RA_PINCFG_FUNC) +#define P107_COM3 RA_PINCFG__64(1, 7, 0x0D, RA_PINCFG_FUNC) +#define P107_GTIOC0A RA_PINCFG__64(1, 7, 0x03, RA_PINCFG_FUNC) +#define P107_KR07 RA_PINCFG__64(1, 7, 0x08, RA_PINCFG_FUNC) +#define P108_CTS9_RTS9 RA_PINCFG__40(1, 8, 0x05, RA_PINCFG_FUNC) +#define P108_GTIOC0B RA_PINCFG__40(1, 8, 0x03, RA_PINCFG_FUNC) +#define P108_GTOULO RA_PINCFG__40(1, 8, 0x02, RA_PINCFG_FUNC) +#define P108_SS9 RA_PINCFG__40(1, 8, 0x05, RA_PINCFG_FUNC) +#define P108_SSLB0 RA_PINCFG__40(1, 8, 0x06, RA_PINCFG_FUNC) +#define P109_CLKOUT RA_PINCFG__40(1, 9, 0x09, RA_PINCFG_FUNC) +#define P109_CTX0 RA_PINCFG__40(1, 9, 0x10, RA_PINCFG_FUNC) +#define P109_GTIOC1A RA_PINCFG__40(1, 9, 0x03, RA_PINCFG_FUNC) +#define P109_GTOVUP RA_PINCFG__40(1, 9, 0x02, RA_PINCFG_FUNC) +#define P109_MOSI9 RA_PINCFG__40(1, 9, 0x05, RA_PINCFG_FUNC) +#define P109_MOSIB RA_PINCFG__40(1, 9, 0x06, RA_PINCFG_FUNC) +#define P109_SCK1 RA_PINCFG__40(1, 9, 0x04, RA_PINCFG_FUNC) +#define P109_SDA9 RA_PINCFG__40(1, 9, 0x05, RA_PINCFG_FUNC) +#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, 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) +#define P202_RXD9 RA_PINCFG_100(2, 2, 0x05, RA_PINCFG_FUNC) +#define P202_SCK2 RA_PINCFG_100(2, 2, 0x04, RA_PINCFG_FUNC) +#define P202_SCL9 RA_PINCFG_100(2, 2, 0x05, RA_PINCFG_FUNC) +#define P202_SEG16 RA_PINCFG_100(2, 2, 0x0D, RA_PINCFG_FUNC) +#define P203_CTS2_RTS2 RA_PINCFG_100(2, 3, 0x04, RA_PINCFG_FUNC) +#define P203_GTIOC5A RA_PINCFG_100(2, 3, 0x03, RA_PINCFG_FUNC) +#define P203_MOSI9 RA_PINCFG_100(2, 3, 0x05, RA_PINCFG_FUNC) +#define P203_MOSIB RA_PINCFG_100(2, 3, 0x06, RA_PINCFG_FUNC) +#define P203_SDA9 RA_PINCFG_100(2, 3, 0x05, RA_PINCFG_FUNC) +#define P203_SEG15 RA_PINCFG_100(2, 3, 0x0D, RA_PINCFG_FUNC) +#define P203_SS2 RA_PINCFG_100(2, 3, 0x04, RA_PINCFG_FUNC) +#define P203_TSCAP RA_PINCFG_100(2, 3, 0x0C, RA_PINCFG_FUNC) +#define P203_TXD9 RA_PINCFG_100(2, 3, 0x05, RA_PINCFG_FUNC) +#define P204_AGTIO1 RA_PINCFG__64(2, 4, 0x01, RA_PINCFG_FUNC) +#define P204_CACREF RA_PINCFG__64(2, 4, 0x0A, RA_PINCFG_FUNC) +#define P204_GTIOC4B RA_PINCFG__64(2, 4, 0x03, RA_PINCFG_FUNC) +#define P204_GTIW RA_PINCFG__64(2, 4, 0x02, RA_PINCFG_FUNC) +#define P204_RSPCKB RA_PINCFG__64(2, 4, 0x06, RA_PINCFG_FUNC) +#define P204_SCK0 RA_PINCFG__64(2, 4, 0x04, RA_PINCFG_FUNC) +#define P204_SCK9 RA_PINCFG__64(2, 4, 0x05, RA_PINCFG_FUNC) +#define P204_SCL0 RA_PINCFG__64(2, 4, 0x07, RA_PINCFG_FUNC) +#define P204_SEG14 RA_PINCFG__64(2, 4, 0x0D, RA_PINCFG_FUNC) +#define P204_TS00 RA_PINCFG__64(2, 4, 0x0C, RA_PINCFG_FUNC) +#define P204_USB_OVRCUR_B RA_PINCFG__64(2, 4, 0x13, RA_PINCFG_FUNC) +#define P205_AGTO1 RA_PINCFG__64(2, 5, 0x01, RA_PINCFG_FUNC) +#define P205_CLKOUT RA_PINCFG__64(2, 5, 0x09, RA_PINCFG_FUNC) +#define P205_CTS9_RTS9 RA_PINCFG__64(2, 5, 0x05, RA_PINCFG_FUNC) +#define P205_GTIOC4A RA_PINCFG__64(2, 5, 0x03, RA_PINCFG_FUNC) +#define P205_GTIV RA_PINCFG__64(2, 5, 0x02, RA_PINCFG_FUNC) +#define P205_MOSI0 RA_PINCFG__64(2, 5, 0x04, RA_PINCFG_FUNC) +#define P205_SCL1 RA_PINCFG__64(2, 5, 0x07, RA_PINCFG_FUNC) +#define P205_SDA0 RA_PINCFG__64(2, 5, 0x04, RA_PINCFG_FUNC) +#define P205_SEG13 RA_PINCFG__64(2, 5, 0x0D, RA_PINCFG_FUNC) +#define P205_SS9 RA_PINCFG__64(2, 5, 0x05, RA_PINCFG_FUNC) +#define P205_SSLB0 RA_PINCFG__64(2, 5, 0x06, RA_PINCFG_FUNC) +#define P205_TSCAP RA_PINCFG__64(2, 5, 0x0C, RA_PINCFG_FUNC) +#define P205_TXD0 RA_PINCFG__64(2, 5, 0x04, RA_PINCFG_FUNC) +#define P205_USB_OVRCUR_A RA_PINCFG__64(2, 5, 0x13, RA_PINCFG_FUNC) +#define P206_GTIU RA_PINCFG__48(2, 6, 0x02, RA_PINCFG_FUNC) +#define P206_MISO0 RA_PINCFG__48(2, 6, 0x04, RA_PINCFG_FUNC) +#define P206_RXD0 RA_PINCFG__48(2, 6, 0x04, RA_PINCFG_FUNC) +#define P206_SCL0 RA_PINCFG__48(2, 6, 0x04, RA_PINCFG_FUNC) +#define P206_SDA1 RA_PINCFG__48(2, 6, 0x07, RA_PINCFG_FUNC) +#define P206_SEG12 RA_PINCFG__48(2, 6, 0x0D, RA_PINCFG_FUNC) +#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, 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) +#define P301_AGTIO0 RA_PINCFG__40(3, 1, 0x01, RA_PINCFG_FUNC) +#define P301_COM5 RA_PINCFG__40(3, 1, 0x10, RA_PINCFG_FUNC) +#define P301_CTS9_RTS9 RA_PINCFG__40(3, 1, 0x05, RA_PINCFG_FUNC) +#define P301_GTIOC4B RA_PINCFG__40(3, 1, 0x03, RA_PINCFG_FUNC) +#define P301_GTOULO RA_PINCFG__40(3, 1, 0x02, RA_PINCFG_FUNC) +#define P301_MISO2 RA_PINCFG__40(3, 1, 0x04, RA_PINCFG_FUNC) +#define P301_RXD2 RA_PINCFG__40(3, 1, 0x04, RA_PINCFG_FUNC) +#define P301_SCL2 RA_PINCFG__40(3, 1, 0x04, RA_PINCFG_FUNC) +#define P301_SEG01 RA_PINCFG__40(3, 1, 0x0D, RA_PINCFG_FUNC) +#define P301_SS9 RA_PINCFG__40(3, 1, 0x05, RA_PINCFG_FUNC) +#define P301_SSLB2 RA_PINCFG__40(3, 1, 0x06, RA_PINCFG_FUNC) +#define P301_TS09 RA_PINCFG__40(3, 1, 0x0C, RA_PINCFG_FUNC) +#define P302_COM6 RA_PINCFG__48(3, 2, 0x10, RA_PINCFG_FUNC) +#define P302_GTIOC4A RA_PINCFG__48(3, 2, 0x03, RA_PINCFG_FUNC) +#define P302_GTOUUP RA_PINCFG__48(3, 2, 0x02, RA_PINCFG_FUNC) +#define P302_MOSI2 RA_PINCFG__48(3, 2, 0x04, RA_PINCFG_FUNC) +#define P302_SDA2 RA_PINCFG__48(3, 2, 0x04, RA_PINCFG_FUNC) +#define P302_SEG02 RA_PINCFG__48(3, 2, 0x0D, RA_PINCFG_FUNC) +#define P302_SSLB3 RA_PINCFG__48(3, 2, 0x06, RA_PINCFG_FUNC) +#define P302_TS08 RA_PINCFG__48(3, 2, 0x0C, RA_PINCFG_FUNC) +#define P302_TXD2 RA_PINCFG__48(3, 2, 0x04, RA_PINCFG_FUNC) +#define P303_COM7 RA_PINCFG__64(3, 3, 0x10, RA_PINCFG_FUNC) +#define P303_GTIOC7B RA_PINCFG__64(3, 3, 0x03, RA_PINCFG_FUNC) +#define P303_SEG03 RA_PINCFG__64(3, 3, 0x0D, RA_PINCFG_FUNC) +#define P303_TS02 RA_PINCFG__64(3, 3, 0x0C, RA_PINCFG_FUNC) +#define P304_GTIOC7A RA_PINCFG__64(3, 4, 0x03, RA_PINCFG_FUNC) +#define P304_SEG20 RA_PINCFG__64(3, 4, 0x0D, RA_PINCFG_FUNC) +#define P304_TS11 RA_PINCFG__64(3, 4, 0x0C, RA_PINCFG_FUNC) +#define P305_SEG19 RA_PINCFG_100(3, 5, 0x0D, RA_PINCFG_FUNC) +#define P306_SEG18 RA_PINCFG_100(3, 6, 0x0D, RA_PINCFG_FUNC) +#define P307_SEG17 RA_PINCFG_100(3, 7, 0x0D, RA_PINCFG_FUNC) +#define P400_AGTIO1 RA_PINCFG__48(4, 0, 0x01, RA_PINCFG_FUNC) +#define P400_AUDIO_CLK RA_PINCFG__48(4, 0, 0x12, RA_PINCFG_FUNC) +#define P400_CACREF RA_PINCFG__48(4, 0, 0x0A, RA_PINCFG_FUNC) +#define P400_GTIOC6A RA_PINCFG__48(4, 0, 0x04, RA_PINCFG_FUNC) +#define P400_SCK0 RA_PINCFG__48(4, 0, 0x04, RA_PINCFG_FUNC) +#define P400_SCK1 RA_PINCFG__48(4, 0, 0x05, RA_PINCFG_FUNC) +#define P400_SCL0 RA_PINCFG__48(4, 0, 0x07, RA_PINCFG_FUNC) +#define P400_SEG04 RA_PINCFG__48(4, 0, 0x0D, RA_PINCFG_FUNC) +#define P400_TS20 RA_PINCFG__48(4, 0, 0x0C, RA_PINCFG_FUNC) +#define P401_CTS0_RTS0 RA_PINCFG__64(4, 1, 0x04, RA_PINCFG_FUNC) +#define P401_CTX0 RA_PINCFG__64(4, 1, 0x10, RA_PINCFG_FUNC) +#define P401_GTETRGA RA_PINCFG__64(4, 1, 0x03, RA_PINCFG_FUNC) +#define P401_GTIOC6B RA_PINCFG__64(4, 1, 0x04, RA_PINCFG_FUNC) +#define P401_MOSI1 RA_PINCFG__64(4, 1, 0x05, RA_PINCFG_FUNC) +#define P401_SDA0 RA_PINCFG__64(4, 1, 0x07, RA_PINCFG_FUNC) +#define P401_SDA1 RA_PINCFG__64(4, 1, 0x05, RA_PINCFG_FUNC) +#define P401_SEG05 RA_PINCFG__64(4, 1, 0x0D, RA_PINCFG_FUNC) +#define P401_SS0 RA_PINCFG__64(4, 1, 0x04, RA_PINCFG_FUNC) +#define P401_TS19 RA_PINCFG__64(4, 1, 0x0C, RA_PINCFG_FUNC) +#define P401_TXD1 RA_PINCFG__64(4, 1, 0x05, RA_PINCFG_FUNC) +#define P402_AGTIO0 RA_PINCFG__64(4, 2, 0x01, RA_PINCFG_FUNC) +#define P402_AGTIO1 RA_PINCFG__64(4, 2, 0x02, RA_PINCFG_FUNC) +#define P402_CRX0 RA_PINCFG__64(4, 2, 0x10, RA_PINCFG_FUNC) +#define P402_MISO1 RA_PINCFG__64(4, 2, 0x05, RA_PINCFG_FUNC) +#define P402_RTCIC0 RA_PINCFG__64(4, 2, 0x00, RA_PINCFG_GPIO) +#define P402_RXD1 RA_PINCFG__64(4, 2, 0x05, RA_PINCFG_FUNC) +#define P402_SCL1 RA_PINCFG__64(4, 2, 0x05, RA_PINCFG_FUNC) +#define P402_SEG06 RA_PINCFG__64(4, 2, 0x0D, RA_PINCFG_FUNC) +#define P402_TS18 RA_PINCFG__64(4, 2, 0x0C, RA_PINCFG_FUNC) +#define P403_AGTIO0 RA_PINCFG_100(4, 3, 0x01, RA_PINCFG_FUNC) +#define P403_AGTIO1 RA_PINCFG_100(4, 3, 0x02, RA_PINCFG_FUNC) +#define P403_CTS1_RTS1 RA_PINCFG_100(4, 3, 0x05, RA_PINCFG_FUNC) +#define P403_GTIOC3A RA_PINCFG_100(4, 3, 0x04, RA_PINCFG_FUNC) +#define P403_RTCIC1 RA_PINCFG_100(4, 3, 0x00, RA_PINCFG_GPIO) +#define P403_SS1 RA_PINCFG_100(4, 3, 0x05, RA_PINCFG_FUNC) +#define P403_SSIBCK0 RA_PINCFG_100(4, 3, 0x12, RA_PINCFG_FUNC) +#define P403_TS17 RA_PINCFG_100(4, 3, 0x0C, RA_PINCFG_FUNC) +#define P404_GTIOC3B RA_PINCFG_100(4, 4, 0x04, RA_PINCFG_FUNC) +#define P404_RTCIC2 RA_PINCFG_100(4, 4, 0x00, RA_PINCFG_GPIO) +#define P404_SSIFS0 RA_PINCFG_100(4, 4, 0x12, RA_PINCFG_FUNC) +#define P404_SSILRCK0 RA_PINCFG_100(4, 4, 0x12, RA_PINCFG_FUNC) +#define P405_GTIOC1A RA_PINCFG_100(4, 5, 0x04, RA_PINCFG_FUNC) +#define P405_SSITXD0 RA_PINCFG_100(4, 5, 0x12, RA_PINCFG_FUNC) +#define P406_GTIOC1B RA_PINCFG_100(4, 6, 0x04, RA_PINCFG_FUNC) +#define P406_SSIRXD0 RA_PINCFG_100(4, 6, 0x12, RA_PINCFG_FUNC) +#define P407_ADTRG0 RA_PINCFG__40(4, 7, 0x0A, RA_PINCFG_FUNC) +#define P407_AGTIO0 RA_PINCFG__40(4, 7, 0x01, RA_PINCFG_FUNC) +#define P407_CTS0_RTS0 RA_PINCFG__40(4, 7, 0x04, RA_PINCFG_FUNC) +#define P407_RTCOUT RA_PINCFG__40(4, 7, 0x09, RA_PINCFG_FUNC) +#define P407_SDA0 RA_PINCFG__40(4, 7, 0x07, RA_PINCFG_FUNC) +#define P407_SEG11 RA_PINCFG__40(4, 7, 0x0D, RA_PINCFG_FUNC) +#define P407_SS0 RA_PINCFG__40(4, 7, 0x04, RA_PINCFG_FUNC) +#define P407_SSLB3 RA_PINCFG__40(4, 7, 0x06, RA_PINCFG_FUNC) +#define P407_TS03 RA_PINCFG__40(4, 7, 0x0C, RA_PINCFG_FUNC) +#define P407_USB_VBUS RA_PINCFG__40(4, 7, 0x13, RA_PINCFG_FUNC) +#define P408_CTS1_RTS1 RA_PINCFG__40(4, 8, 0x04, RA_PINCFG_FUNC) +#define P408_GTIOC5B RA_PINCFG__40(4, 8, 0x04, RA_PINCFG_FUNC) +#define P408_GTOWLO RA_PINCFG__40(4, 8, 0x03, RA_PINCFG_FUNC) +#define P408_MISO9 RA_PINCFG__40(4, 8, 0x05, RA_PINCFG_FUNC) +#define P408_RXD9 RA_PINCFG__40(4, 8, 0x05, RA_PINCFG_FUNC) +#define P408_SCL0 RA_PINCFG__40(4, 8, 0x07, RA_PINCFG_FUNC) +#define P408_SCL9 RA_PINCFG__40(4, 8, 0x05, RA_PINCFG_FUNC) +#define P408_SEG10 RA_PINCFG__40(4, 8, 0x0D, RA_PINCFG_FUNC) +#define P408_SS1 RA_PINCFG__40(4, 8, 0x04, RA_PINCFG_FUNC) +#define P408_TS04 RA_PINCFG__40(4, 8, 0x0C, RA_PINCFG_FUNC) +#define P408_USB_ID RA_PINCFG__40(4, 8, 0x13, RA_PINCFG_FUNC) +#define P409_GTIOC5A RA_PINCFG__48(4, 9, 0x04, RA_PINCFG_FUNC) +#define P409_GTOWUP RA_PINCFG__48(4, 9, 0x03, RA_PINCFG_FUNC) +#define P409_MOSI9 RA_PINCFG__48(4, 9, 0x05, RA_PINCFG_FUNC) +#define P409_SDA9 RA_PINCFG__48(4, 9, 0x05, RA_PINCFG_FUNC) +#define P409_SEG09 RA_PINCFG__48(4, 9, 0x0D, RA_PINCFG_FUNC) +#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, 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) +#define P500_GTIOC2A RA_PINCFG__48(5, 0, 0x04, RA_PINCFG_FUNC) +#define P500_GTIU RA_PINCFG__48(5, 0, 0x03, RA_PINCFG_FUNC) +#define P500_SEG34 RA_PINCFG__48(5, 0, 0x0D, RA_PINCFG_FUNC) +#define P500_USB_VBUSEN RA_PINCFG__48(5, 0, 0x13, RA_PINCFG_FUNC) +#define P501_AGTOB0 RA_PINCFG__64(5, 1, 0x01, RA_PINCFG_FUNC) +#define P501_AN017 RA_PINCFG__64(5, 1, 0x01, RA_PINCFG_ANALOG) +#define P501_CMPIN1 RA_PINCFG__64(5, 1, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P501_GTIOC2B RA_PINCFG__64(5, 1, 0x04, RA_PINCFG_FUNC) +#define P501_GTIV RA_PINCFG__64(5, 1, 0x03, RA_PINCFG_FUNC) +#define P501_MOSI1 RA_PINCFG__64(5, 1, 0x05, RA_PINCFG_FUNC) +#define P501_SDA1 RA_PINCFG__64(5, 1, 0x05, RA_PINCFG_FUNC) +#define P501_SEG35 RA_PINCFG__64(5, 1, 0x0D, RA_PINCFG_FUNC) +#define P501_TXD1 RA_PINCFG__64(5, 1, 0x05, RA_PINCFG_FUNC) +#define P501_USB_OVRCUR_A RA_PINCFG__64(5, 1, 0x13, RA_PINCFG_FUNC) +#define P502_AN018 RA_PINCFG__64(5, 2, 0x01, RA_PINCFG_ANALOG) +#define P502_CMPREF0 RA_PINCFG__64(5, 2, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P502_GTIOC3B RA_PINCFG__64(5, 2, 0x04, RA_PINCFG_FUNC) +#define P502_GTIW RA_PINCFG__64(5, 2, 0x03, RA_PINCFG_FUNC) +#define P502_MISO1 RA_PINCFG__64(5, 2, 0x05, RA_PINCFG_FUNC) +#define P502_RXD1 RA_PINCFG__64(5, 2, 0x05, RA_PINCFG_FUNC) +#define P502_SCL1 RA_PINCFG__64(5, 2, 0x05, RA_PINCFG_FUNC) +#define P502_SEG36 RA_PINCFG__64(5, 2, 0x0D, RA_PINCFG_FUNC) +#define P502_USB_OVRCUR_B RA_PINCFG__64(5, 2, 0x13, RA_PINCFG_FUNC) +#define P503_AN023 RA_PINCFG_100(5, 3, 0x01, RA_PINCFG_ANALOG) +#define P503_CMPIN0 RA_PINCFG_100(5, 3, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P503_SCK1 RA_PINCFG_100(5, 3, 0x05, RA_PINCFG_FUNC) +#define P503_SEG37 RA_PINCFG_100(5, 3, 0x0D, RA_PINCFG_FUNC) +#define P503_USB_EXICEN RA_PINCFG_100(5, 3, 0x13, RA_PINCFG_FUNC) +#define P504_AN024 RA_PINCFG_100(5, 4, 0x01, RA_PINCFG_ANALOG) +#define P504_CTS1_RTS1 RA_PINCFG_100(5, 4, 0x05, RA_PINCFG_FUNC) +#define P504_SS1 RA_PINCFG_100(5, 4, 0x05, RA_PINCFG_FUNC) +#define P504_USB_ID RA_PINCFG_100(5, 4, 0x13, RA_PINCFG_FUNC) +#define P505_AN025 RA_PINCFG_100(5, 5, 0x01, RA_PINCFG_ANALOG) +#define P600_GTIOC6B RA_PINCFG_100(6, 0, 0x01, RA_PINCFG_FUNC) +#define P600_SCK9 RA_PINCFG_100(6, 0, 0x05, RA_PINCFG_FUNC) +#define P600_SEG33 RA_PINCFG_100(6, 0, 0x0D, RA_PINCFG_FUNC) +#define P601_GTIOC6A RA_PINCFG_100(6, 1, 0x01, RA_PINCFG_FUNC) +#define P601_MISO9 RA_PINCFG_100(6, 1, 0x05, RA_PINCFG_FUNC) +#define P601_RXD9 RA_PINCFG_100(6, 1, 0x05, RA_PINCFG_FUNC) +#define P601_SCL9 RA_PINCFG_100(6, 1, 0x05, RA_PINCFG_FUNC) +#define P601_SEG32 RA_PINCFG_100(6, 1, 0x0D, RA_PINCFG_FUNC) +#define P602_GTIOC7B RA_PINCFG_100(6, 2, 0x01, RA_PINCFG_FUNC) +#define P602_MOSI9 RA_PINCFG_100(6, 2, 0x05, RA_PINCFG_FUNC) +#define P602_SDA9 RA_PINCFG_100(6, 2, 0x05, RA_PINCFG_FUNC) +#define P602_SEG31 RA_PINCFG_100(6, 2, 0x0D, RA_PINCFG_FUNC) +#define P602_TXD9 RA_PINCFG_100(6, 2, 0x05, RA_PINCFG_FUNC) +#define P603_CTS9_RTS9 RA_PINCFG_100(6, 3, 0x05, RA_PINCFG_FUNC) +#define P603_GTIOC7A RA_PINCFG_100(6, 3, 0x01, RA_PINCFG_FUNC) +#define P603_SEG30 RA_PINCFG_100(6, 3, 0x0D, RA_PINCFG_FUNC) +#define P603_SS9 RA_PINCFG_100(6, 3, 0x05, RA_PINCFG_FUNC) +#define P608_GTIOC4B RA_PINCFG_100(6, 8, 0x01, RA_PINCFG_FUNC) +#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, 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, 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 000000000000000..50e8a3580070fe2 --- /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 new file mode 100644 index 000000000000000..a7969523a93fd56 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra-common.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_RA_COMMON_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_RA_COMMON_H_ + +#define PORT4_POS 29 +#define PORT4_MASK 0x1 +#define PSEL_POS 24 +#define PSEL_MASK 0x5 +#define PORT_POS 21 +#define PORT_MASK 0x7 +#define PIN_POS 17 +#define PIN_MASK 0xF +#define OPT_POS 0 +#define OPT_MASK 0x1B000 + +#define RA_PINCFG_GPIO 0x00000 +#define RA_PINCFG_FUNC 0x10000 +#define RA_PINCFG_ANALOG 0x08000 + +#define RA_PINCFG(port, pin, psel, opt) \ + ((((psel)&PSEL_MASK) << PSEL_POS) | (((pin)&PIN_MASK) << PIN_POS) | \ + (((port)&PORT_MASK) << PORT_POS) | ((((port) >> 3) & PORT4_MASK) << PORT4_POS) | \ + (((opt)&OPT_MASK) << OPT_POS)) + +#if RA_SOC_PINS >= 40 +#define RA_PINCFG__40(port, pin, psel, opt) RA_PINCFG(port, pin, psel, opt) +#endif + +#if RA_SOC_PINS >= 48 +#define RA_PINCFG__48(port, pin, psel, opt) RA_PINCFG(port, pin, psel, opt) +#endif + +#if RA_SOC_PINS >= 64 +#define RA_PINCFG__64(port, pin, psel, opt) RA_PINCFG(port, pin, psel, opt) +#endif + +#if RA_SOC_PINS >= 100 +#define RA_PINCFG_100(port, pin, psel, opt) RA_PINCFG(port, pin, psel, opt) +#endif + +#endif 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 fc8d5090e84b280..30a2afe1db12f13 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 4249fd24a3a4e25..c7870a210827c0d 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/power/atmel_sam_supc.h b/include/zephyr/dt-bindings/power/atmel_sam_supc.h new file mode 100644 index 000000000000000..547a97ef704eb4b --- /dev/null +++ b/include/zephyr/dt-bindings/power/atmel_sam_supc.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Bjarki Arge Andreasen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_POWER_ATMEL_SAM_SUPC_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_POWER_ATMEL_SAM_SUPC_H_ + +#define SUPC_WAKEUP_SOURCE_FWUP 0 +#define SUPC_WAKEUP_SOURCE_SM 1 +#define SUPC_WAKEUP_SOURCE_RTT 2 +#define SUPC_WAKEUP_SOURCE_RTC 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_POWER_ATMEL_SAM_SUPC_H_ */ diff --git a/include/zephyr/dt-bindings/regulator/max20335.h b/include/zephyr/dt-bindings/regulator/max20335.h new file mode 100644 index 000000000000000..d7d23f03c965b65 --- /dev/null +++ b/include/zephyr/dt-bindings/regulator/max20335.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Grinn + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_MAX20335_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_MAX20335_H_ + +/** + * @defgroup regulator_max20335 MAX20335 Devicetree helpers. + * @ingroup regulator_interface + * @{ + */ + +/** + * @name MAX20335 Regulator modes + * @{ + */ +/** LDO mode */ +#define MAX20335_LDO_MODE 0 +/** Load switch mode */ +#define MAX20335_LOAD_SWITCH_MODE 1 +/** @} */ + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_MAX20335_H_*/ diff --git a/include/zephyr/dt-bindings/sensor/bq274xx.h b/include/zephyr/dt-bindings/sensor/bq274xx.h new file mode 100644 index 000000000000000..9e8c259068ec86b --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/bq274xx.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 The Zephyr Contributors. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Relevant documents: + * - BQ27421 + * Datasheet: https://www.ti.com/lit/gpn/bq27421-g1 + * Technical reference manual: https://www.ti.com/lit/pdf/sluuac5 + * - BQ27427 + * Datasheet: https://www.ti.com/lit/gpn/bq27427 + * Technical reference manual: https://www.ti.com/lit/pdf/sluucd5 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_BQ274XX_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_BQ274XX_H_ + +/* Chemistry IDs for BQ27427 */ +#define BQ27427_CHEM_ID_A 0x3230 +#define BQ27427_CHEM_ID_B 0x1202 +#define BQ27427_CHEM_ID_C 0x3142 + +/* Chemistry IDs for BQ27421 variants */ +#define BQ27421_G1A_CHEM_ID 0x0128 +#define BQ27421_G1B_CHEM_ID 0x0312 +#define BQ27421_G1D_CHEM_ID 0x3142 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_BQ274XX_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/iis2dlpc.h b/include/zephyr/dt-bindings/sensor/iis2dlpc.h new file mode 100644 index 000000000000000..abf6df1cc443606 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/iis2dlpc.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_IIS2DLPC_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_IIS2DLPC_H_ + +/* power-modes */ +#define IIS2DLPC_DT_LP_M1 0 +#define IIS2DLPC_DT_LP_M2 1 +#define IIS2DLPC_DT_LP_M3 2 +#define IIS2DLPC_DT_LP_M4 3 +#define IIS2DLPC_DT_HP_MODE 4 + +/* Filter bandwidth */ +#define IIS2DLPC_DT_FILTER_BW_ODR_DIV_2 0 +#define IIS2DLPC_DT_FILTER_BW_ODR_DIV_4 1 +#define IIS2DLPC_DT_FILTER_BW_ODR_DIV_10 2 +#define IIS2DLPC_DT_FILTER_BW_ODR_DIV_20 3 + +/* Tap mode */ +#define IIS2DLPC_DT_SINGLE_TAP 0 +#define IIS2DLPC_DT_SINGLE_DOUBLE_TAP 1 + +/* Free-Fall threshold */ +#define IIS2DLPC_DT_FF_THRESHOLD_156_mg 0 +#define IIS2DLPC_DT_FF_THRESHOLD_219_mg 1 +#define IIS2DLPC_DT_FF_THRESHOLD_250_mg 2 +#define IIS2DLPC_DT_FF_THRESHOLD_312_mg 3 +#define IIS2DLPC_DT_FF_THRESHOLD_344_mg 4 +#define IIS2DLPC_DT_FF_THRESHOLD_406_mg 5 +#define IIS2DLPC_DT_FF_THRESHOLD_469_mg 6 +#define IIS2DLPC_DT_FF_THRESHOLD_500_mg 7 + +/* wakeup duration */ +#define IIS2DLPC_DT_WAKEUP_1_ODR 0 +#define IIS2DLPC_DT_WAKEUP_2_ODR 1 +#define IIS2DLPC_DT_WAKEUP_3_ODR 2 +#define IIS2DLPC_DT_WAKEUP_4_ODR 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_IIS2DLPC_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/iis2iclx.h b/include/zephyr/dt-bindings/sensor/iis2iclx.h new file mode 100644 index 000000000000000..544486e0984dc3e --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/iis2iclx.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_IIS2ICLX_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_IIS2ICLX_H_ + +/* Accel range */ +#define IIS2ICLX_DT_FS_500mG 0 +#define IIS2ICLX_DT_FS_3G 1 +#define IIS2ICLX_DT_FS_1G 2 +#define IIS2ICLX_DT_FS_2G 3 + +/* Accel Data rates */ +#define IIS2ICLX_DT_ODR_OFF 0x0 +#define IIS2ICLX_DT_ODR_12Hz5 0x1 +#define IIS2ICLX_DT_ODR_26H 0x2 +#define IIS2ICLX_DT_ODR_52Hz 0x3 +#define IIS2ICLX_DT_ODR_104Hz 0x4 +#define IIS2ICLX_DT_ODR_208Hz 0x5 +#define IIS2ICLX_DT_ODR_416Hz 0x6 +#define IIS2ICLX_DT_ODR_833Hz 0x7 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_IIS2ICLX_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/ism330dhcx.h b/include/zephyr/dt-bindings/sensor/ism330dhcx.h new file mode 100644 index 000000000000000..7d857eb165a662b --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/ism330dhcx.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_ISM330DHCX_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_ISM330DHCX_H_ + +/* Accel and Gyro Data rates */ +#define ISM330DHCX_DT_ODR_OFF 0x0 +#define ISM330DHCX_DT_ODR_12Hz5 0x1 +#define ISM330DHCX_DT_ODR_26H 0x2 +#define ISM330DHCX_DT_ODR_52Hz 0x3 +#define ISM330DHCX_DT_ODR_104Hz 0x4 +#define ISM330DHCX_DT_ODR_208Hz 0x5 +#define ISM330DHCX_DT_ODR_416Hz 0x6 +#define ISM330DHCX_DT_ODR_833Hz 0x7 +#define ISM330DHCX_DT_ODR_1666Hz 0x8 +#define ISM330DHCX_DT_ODR_3332Hz 0x9 +#define ISM330DHCX_DT_ODR_6667Hz 0xa +#define ISM330DHCX_DT_ODR_1Hz6 0xb + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_ISM330DHCX_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/lis2dh.h b/include/zephyr/dt-bindings/sensor/lis2dh.h new file mode 100644 index 000000000000000..a697f34cc802465 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lis2dh.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DH_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DH_H_ + +/* GPIO interrupt configuration */ +#define LIS2DH_DT_GPIO_INT_EDGE 0 +#define LIS2DH_DT_GPIO_INT_EDGE_RISING 1 +#define LIS2DH_DT_GPIO_INT_EDGE_FALLING 2 +#define LIS2DH_DT_GPIO_INT_LEVEL_HIGH 3 +#define LIS2DH_DT_GPIO_INT_LEVEL_LOW 4 + +/* Any Motion mode */ +#define LIS2DH_DT_ANYM_OR_COMBINATION 0 +#define LIS2DH_DT_ANYM_6D_MOVEMENT 1 +#define LIS2DH_DT_ANYM_AND_COMBINATION 2 +#define LIS2DH_DT_ANYM_6D_POSITION 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DH_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/lis2ds12.h b/include/zephyr/dt-bindings/sensor/lis2ds12.h new file mode 100644 index 000000000000000..04d808bfa72d792 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lis2ds12.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DS12_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DS12_H_ + +/* power-modes */ +#define LIS2DS12_DT_POWER_DOWN 0 +#define LIS2DS12_DT_LOW_POWER 1 +#define LIS2DS12_DT_HIGH_RESOLUTION 2 +#define LIS2DS12_DT_HIGH_FREQUENCY 3 + +/* Data rate */ +#define LIS2DS12_DT_ODR_OFF 0 +#define LIS2DS12_DT_ODR_1Hz_LP 1 /* available in LP mode only */ +#define LIS2DS12_DT_ODR_12Hz5 2 /* available in LP and HR mode */ +#define LIS2DS12_DT_ODR_25Hz 3 /* available in LP and HR mode */ +#define LIS2DS12_DT_ODR_50Hz 4 /* available in LP and HR mode */ +#define LIS2DS12_DT_ODR_100Hz 5 /* available in LP and HR mode */ +#define LIS2DS12_DT_ODR_200Hz 6 /* available in LP and HR mode */ +#define LIS2DS12_DT_ODR_400Hz 7 /* available in LP and HR mode */ +#define LIS2DS12_DT_ODR_800Hz 8 /* available in LP and HR mode */ +#define LIS2DS12_DT_ODR_1600Hz 9 /* available in HF mode only */ +#define LIS2DS12_DT_ODR_3200Hz_HF 10 /* available in HF mode only */ +#define LIS2DS12_DT_ODR_6400Hz_HF 11 /* available in HF mode only */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DS12_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/lis2du12.h b/include/zephyr/dt-bindings/sensor/lis2du12.h new file mode 100644 index 000000000000000..99e4c520e3f5501 --- /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/lis2dw12.h b/include/zephyr/dt-bindings/sensor/lis2dw12.h new file mode 100644 index 000000000000000..9e5892ec0a52dd2 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lis2dw12.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DW12_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DW12_H_ + +/* power-modes */ +#define LIS2DW12_DT_LP_M1 0 +#define LIS2DW12_DT_LP_M2 1 +#define LIS2DW12_DT_LP_M3 2 +#define LIS2DW12_DT_LP_M4 3 +#define LIS2DW12_DT_HP_MODE 4 + +/* Filter bandwidth */ +#define LIS2DW12_DT_FILTER_BW_ODR_DIV_2 0 +#define LIS2DW12_DT_FILTER_BW_ODR_DIV_4 1 +#define LIS2DW12_DT_FILTER_BW_ODR_DIV_10 2 +#define LIS2DW12_DT_FILTER_BW_ODR_DIV_20 3 + +/* Tap mode */ +#define LIS2DW12_DT_SINGLE_TAP 0 +#define LIS2DW12_DT_SINGLE_DOUBLE_TAP 1 + +/* Free-Fall threshold */ +#define LIS2DW12_DT_FF_THRESHOLD_156_mg 0 +#define LIS2DW12_DT_FF_THRESHOLD_219_mg 1 +#define LIS2DW12_DT_FF_THRESHOLD_250_mg 2 +#define LIS2DW12_DT_FF_THRESHOLD_312_mg 3 +#define LIS2DW12_DT_FF_THRESHOLD_344_mg 4 +#define LIS2DW12_DT_FF_THRESHOLD_406_mg 5 +#define LIS2DW12_DT_FF_THRESHOLD_469_mg 6 +#define LIS2DW12_DT_FF_THRESHOLD_500_mg 7 + +/* wakeup duration */ +#define LIS2DW12_DT_WAKEUP_1_ODR 0 +#define LIS2DW12_DT_WAKEUP_2_ODR 1 +#define LIS2DW12_DT_WAKEUP_3_ODR 2 +#define LIS2DW12_DT_WAKEUP_4_ODR 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DW12_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/lps22hh.h b/include/zephyr/dt-bindings/sensor/lps22hh.h new file mode 100644 index 000000000000000..728f872bc37589c --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lps22hh.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22HH_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22HH_H_ + +/* Data rate */ +#define LPS22HH_DT_ODR_POWER_DOWN 0 +#define LPS22HH_DT_ODR_1HZ 1 +#define LPS22HH_DT_ODR_10HZ 2 +#define LPS22HH_DT_ODR_25HZ 3 +#define LPS22HH_DT_ODR_50HZ 4 +#define LPS22HH_DT_ODR_75HZ 5 +#define LPS22HH_DT_ODR_100HZ 6 +#define LPS22HH_DT_ODR_200HZ 7 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22HH_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/lps2xdf.h b/include/zephyr/dt-bindings/sensor/lps2xdf.h new file mode 100644 index 000000000000000..bcbb831bae57c66 --- /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/lsm6dso.h b/include/zephyr/dt-bindings/sensor/lsm6dso.h new file mode 100644 index 000000000000000..7d3775bae3d3e4f --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lsm6dso.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSO_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSO_H_ + +/* Accel power-modes */ +#define LSM6DSO_DT_XL_HP_MODE 0 +#define LSM6DSO_DT_XL_LP_NORMAL_MODE 1 +#define LSM6DSO_DT_XL_ULP_MODE 2 + +/* Gyro power-modes */ +#define LSM6DSO_DT_GY_HP_MODE 0 +#define LSM6DSO_DT_GY_NORMAL_MODE 1 + +/* Accel range */ +#define LSM6DSO_DT_FS_2G 0 +#define LSM6DSO_DT_FS_16G 1 +#define LSM6DSO_DT_FS_4G 2 +#define LSM6DSO_DT_FS_8G 3 + +/* Gyro range */ +#define LSM6DSO_DT_FS_250DPS 0 +#define LSM6DSO_DT_FS_125DPS 1 +#define LSM6DSO_DT_FS_500DPS 2 +#define LSM6DSO_DT_FS_1000DPS 4 +#define LSM6DSO_DT_FS_2000DPS 6 + +/* Accel and Gyro Data rates */ +#define LSM6DSO_DT_ODR_OFF 0x0 +#define LSM6DSO_DT_ODR_12Hz5 0x1 +#define LSM6DSO_DT_ODR_26H 0x2 +#define LSM6DSO_DT_ODR_52Hz 0x3 +#define LSM6DSO_DT_ODR_104Hz 0x4 +#define LSM6DSO_DT_ODR_208Hz 0x5 +#define LSM6DSO_DT_ODR_417Hz 0x6 +#define LSM6DSO_DT_ODR_833Hz 0x7 +#define LSM6DSO_DT_ODR_1667Hz 0x8 +#define LSM6DSO_DT_ODR_3333Hz 0x9 +#define LSM6DSO_DT_ODR_6667Hz 0xa +#define LSM6DSO_DT_ODR_1Hz6 0xb + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSO_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/lsm6dso16is.h b/include/zephyr/dt-bindings/sensor/lsm6dso16is.h new file mode 100644 index 000000000000000..385f41145cf12bf --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lsm6dso16is.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSO16IS_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSO16IS_H_ + +/* Accel range */ +#define LSM6DSO16IS_DT_FS_2G 0 +#define LSM6DSO16IS_DT_FS_16G 1 +#define LSM6DSO16IS_DT_FS_4G 2 +#define LSM6DSO16IS_DT_FS_8G 3 + +/* Gyro range */ +#define LSM6DSO16IS_DT_FS_250DPS 0x0 +#define LSM6DSO16IS_DT_FS_500DPS 0x1 +#define LSM6DSO16IS_DT_FS_1000DPS 0x2 +#define LSM6DSO16IS_DT_FS_2000DPS 0x3 +#define LSM6DSO16IS_DT_FS_125DPS 0x10 + +/* Accel and Gyro Data rates */ +#define LSM6DSO16IS_DT_ODR_OFF 0x0 +#define LSM6DSO16IS_DT_ODR_12Hz5_HP 0x1 +#define LSM6DSO16IS_DT_ODR_26H_HP 0x2 +#define LSM6DSO16IS_DT_ODR_52Hz_HP 0x3 +#define LSM6DSO16IS_DT_ODR_104Hz_HP 0x4 +#define LSM6DSO16IS_DT_ODR_208Hz_HP 0x5 +#define LSM6DSO16IS_DT_ODR_416Hz_HP 0x6 +#define LSM6DSO16IS_DT_ODR_833Hz_HP 0x7 +#define LSM6DSO16IS_DT_ODR_1667Hz_HP 0x8 +#define LSM6DSO16IS_DT_ODR_3333Hz_HP 0x9 +#define LSM6DSO16IS_DT_ODR_6667Hz_HP 0xa +#define LSM6DSO16IS_DT_ODR_12Hz5_LP 0x11 +#define LSM6DSO16IS_DT_ODR_26H_LP 0x12 +#define LSM6DSO16IS_DT_ODR_52Hz_LP 0x13 +#define LSM6DSO16IS_DT_ODR_104Hz_LP 0x14 +#define LSM6DSO16IS_DT_ODR_208Hz_LP 0x15 +#define LSM6DSO16IS_DT_ODR_416Hz_LP 0x16 +#define LSM6DSO16IS_DT_ODR_833Hz_LP 0x17 +#define LSM6DSO16IS_DT_ODR_1667Hz_LP 0x18 +#define LSM6DSO16IS_DT_ODR_3333Hz_LP 0x19 +#define LSM6DSO16IS_DT_ODR_6667Hz_LP 0x1a +#define LSM6DSO16IS_DT_ODR_1Hz6_LP 0x1b + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSO16IS_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/lsm6dsv16x.h b/include/zephyr/dt-bindings/sensor/lsm6dsv16x.h new file mode 100644 index 000000000000000..533dd5e3febb085 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lsm6dsv16x.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSV16X_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSV16X_H_ + +/* Accel range */ +#define LSM6DSV16X_DT_FS_2G 0 +#define LSM6DSV16X_DT_FS_4G 1 +#define LSM6DSV16X_DT_FS_8G 2 +#define LSM6DSV16X_DT_FS_16G 3 + +/* Gyro range */ +#define LSM6DSV16X_DT_FS_125DPS 0x0 +#define LSM6DSV16X_DT_FS_250DPS 0x1 +#define LSM6DSV16X_DT_FS_500DPS 0x2 +#define LSM6DSV16X_DT_FS_1000DPS 0x3 +#define LSM6DSV16X_DT_FS_2000DPS 0x4 +#define LSM6DSV16X_DT_FS_4000DPS 0xc + +/* Accel and Gyro Data rates */ +#define LSM6DSV16X_DT_ODR_OFF 0x0 +#define LSM6DSV16X_DT_ODR_AT_1Hz875 0x1 +#define LSM6DSV16X_DT_ODR_AT_7Hz5 0x2 +#define LSM6DSV16X_DT_ODR_AT_15Hz 0x3 +#define LSM6DSV16X_DT_ODR_AT_30Hz 0x4 +#define LSM6DSV16X_DT_ODR_AT_60Hz 0x5 +#define LSM6DSV16X_DT_ODR_AT_120Hz 0x6 +#define LSM6DSV16X_DT_ODR_AT_240Hz 0x7 +#define LSM6DSV16X_DT_ODR_AT_480Hz 0x8 +#define LSM6DSV16X_DT_ODR_AT_960Hz 0x9 +#define LSM6DSV16X_DT_ODR_AT_1920Hz 0xA +#define LSM6DSV16X_DT_ODR_AT_3840Hz 0xB +#define LSM6DSV16X_DT_ODR_AT_7680Hz 0xC +#define LSM6DSV16X_DT_ODR_HA01_AT_15Hz625 0x13 +#define LSM6DSV16X_DT_ODR_HA01_AT_31Hz25 0x14 +#define LSM6DSV16X_DT_ODR_HA01_AT_62Hz5 0x15 +#define LSM6DSV16X_DT_ODR_HA01_AT_125Hz 0x16 +#define LSM6DSV16X_DT_ODR_HA01_AT_250Hz 0x17 +#define LSM6DSV16X_DT_ODR_HA01_AT_500Hz 0x18 +#define LSM6DSV16X_DT_ODR_HA01_AT_1000Hz 0x19 +#define LSM6DSV16X_DT_ODR_HA01_AT_2000Hz 0x1A +#define LSM6DSV16X_DT_ODR_HA01_AT_4000Hz 0x1B +#define LSM6DSV16X_DT_ODR_HA01_AT_8000Hz 0x1C +#define LSM6DSV16X_DT_ODR_HA02_AT_12Hz5 0x23 +#define LSM6DSV16X_DT_ODR_HA02_AT_25Hz 0x24 +#define LSM6DSV16X_DT_ODR_HA02_AT_50Hz 0x25 +#define LSM6DSV16X_DT_ODR_HA02_AT_100Hz 0x26 +#define LSM6DSV16X_DT_ODR_HA02_AT_200Hz 0x27 +#define LSM6DSV16X_DT_ODR_HA02_AT_400Hz 0x28 +#define LSM6DSV16X_DT_ODR_HA02_AT_800Hz 0x29 +#define LSM6DSV16X_DT_ODR_HA02_AT_1600Hz 0x2A +#define LSM6DSV16X_DT_ODR_HA02_AT_3200Hz 0x2B +#define LSM6DSV16X_DT_ODR_HA02_AT_6400Hz 0x2C + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSV16X_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 000000000000000..c7df471d9294596 --- /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 000000000000000..e25db0a143147a4 --- /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 000000000000000..4bc8c591457afae --- /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/fs/fs_interface.h b/include/zephyr/fs/fs_interface.h index 2692ea168a7cd8e..5db637635b954c6 100644 --- a/include/zephyr/fs/fs_interface.h +++ b/include/zephyr/fs/fs_interface.h @@ -13,7 +13,7 @@ extern "C" { #endif -#if (CONFIG_FILE_SYSTEM_MAX_FILE_NAME - 0) > 0 +#if defined(CONFIG_FILE_SYSTEM_MAX_FILE_NAME) && (CONFIG_FILE_SYSTEM_MAX_FILE_NAME - 0) > 0 #define MAX_FILE_NAME CONFIG_FILE_SYSTEM_MAX_FILE_NAME #else /* CONFIG_FILE_SYSTEM_MAX_FILE_NAME */ diff --git a/include/zephyr/init.h b/include/zephyr/init.h index 9b0d2993d62081e..2788dc01afd7fef 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 000000000000000..14492156d9c75bd --- /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 000000000000000..da8ad0ddfa3ae5c --- /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 000000000000000..2a89dde0530e306 --- /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 new file mode 100644 index 000000000000000..7d3f4f37c437a6b --- /dev/null +++ b/include/zephyr/input/input_kbd_matrix.h @@ -0,0 +1,310 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_INPUT_KBD_MATRIX_H_ +#define ZEPHYR_INCLUDE_INPUT_KBD_MATRIX_H_ + +/** + * @brief Keyboard Matrix API + * @defgroup input_kbd_matrix Keyboard Matrix API + * @ingroup io_interfaces + * @{ + */ + +#include +#include +#include +#include +#include + +/** Special drive_column argument for not driving any column */ +#define INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE -1 + +/** Special drive_column argument for driving all the columns */ +#define INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL -2 + +/** 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. + */ +struct input_kbd_matrix_api { + /** + * @brief Request to drive a specific column. + * + * Request to drive a specific matrix column, or none, or all. + * + * @param dev Pointer to the keyboard matrix device. + * @param col The column to drive, or + * @ref INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE or + * @ref INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL. + */ + void (*drive_column)(const struct device *dev, int col); + /** + * @brief Read the matrix row. + * + * @param dev Pointer to the keyboard matrix device. + */ + kbd_row_t (*read_row)(const struct device *dev); + /** + * @brief Request to put the matrix in detection mode. + * + * Request to put the driver in detection mode, this is called after a + * request to drive all the column and typically involves reenabling + * interrupts row pin changes. + * + * @param dev Pointer to the keyboard matrix device. + * @param enable Whether detection mode has to be enabled or disabled. + */ + void (*set_detect_mode)(const struct device *dev, bool enabled); +}; + +/** + * @brief Common keyboard matrix config. + * + * This structure **must** be placed first in the driver's config structure. + */ +struct input_kbd_matrix_common_config { + const struct input_kbd_matrix_api *api; + uint8_t row_size; + uint8_t col_size; + uint32_t poll_period_us; + uint32_t poll_timeout_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 */ + 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; +}; + +#define INPUT_KBD_MATRIX_DATA_NAME(node_id, name) \ + _CONCAT(__input_kbd_matrix_, \ + _CONCAT(name, DEVICE_DT_NAME_GET(node_id))) + +/** + * @brief Defines the common keyboard matrix support data from devicetree, + * 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, INPUT_KBD_MATRIX_ROW_BITS), "invalid row-size"); \ + BUILD_ASSERT(IN_RANGE(_col_size, 1, UINT8_MAX), "invalid 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]; + +/** + * @brief Defines the common keyboard matrix support data from devicetree. + */ +#define INPUT_KBD_MATRIX_DT_DEFINE(node_id) \ + INPUT_KBD_MATRIX_DT_DEFINE_ROW_COL( \ + node_id, DT_PROP(node_id, row_size), DT_PROP(node_id, col_size)) + +/** + * @brief Defines the common keyboard matrix support data from devicetree + * instance, specify row and col count. + * + * @param inst Instance. + * @param row_size The matrix row count. + * @param col_size The matrix column count. + */ +#define INPUT_KBD_MATRIX_DT_INST_DEFINE_ROW_COL(inst, row_size, col_size) \ + INPUT_KBD_MATRIX_DT_DEFINE_ROW_COL(DT_DRV_INST(inst), row_size, col_size) + +/** + * @brief Defines the common keyboard matrix support data from devicetree instance. + * + * @param inst Instance. + */ +#define INPUT_KBD_MATRIX_DT_INST_DEFINE(inst) \ + INPUT_KBD_MATRIX_DT_DEFINE(DT_DRV_INST(inst)) + +/** + * @brief Initialize common keyboard matrix config from devicetree, specify row and col count. + * + * @param node_id The devicetree node identifier. + * @param _api Pointer to a @ref input_kbd_matrix_api structure. + * @param _row_size The matrix row count. + * @param _col_size The matrix column count. + */ +#define INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT_ROW_COL(node_id, _api, _row_size, _col_size) \ + { \ + .api = _api, \ + .row_size = _row_size, \ + .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_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), \ + .matrix_previous_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, previous_state), \ + .matrix_new_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, new_state), \ + .scan_cycle_idx = INPUT_KBD_MATRIX_DATA_NAME(node_id, scan_cycle_idx), \ + } + +/** + * @brief Initialize common keyboard matrix config from devicetree. + * + * @param node_id The devicetree node identifier. + * @param api Pointer to a @ref input_kbd_matrix_api structure. + */ +#define INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT(node_id, api) \ + INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT_ROW_COL( \ + node_id, api, DT_PROP(node_id, row_size), DT_PROP(node_id, col_size)) + +/** + * @brief Initialize common keyboard matrix config from devicetree instance, + * specify row and col count. + * + * @param inst Instance. + * @param api Pointer to a @ref input_kbd_matrix_api structure. + * @param row_size The matrix row count. + * @param col_size The matrix column count. + */ +#define INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT_ROW_COL(inst, api, row_size, col_size) \ + INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT_ROW_COL(DT_DRV_INST(inst), api, row_size, col_size) + +/** + * @brief Initialize common keyboard matrix config from devicetree instance. + * + * @param inst Instance. + * @param api Pointer to a @ref input_kbd_matrix_api structure. + */ +#define INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT(inst, api) \ + INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT(DT_DRV_INST(inst), api) + +/** + * @brief Common keyboard matrix data. + * + * This structure **must** be placed first in the driver's data structure. + */ +struct input_kbd_matrix_common_data { + /* Track previous cycles, used for debouncing. */ + uint32_t scan_clk_cycle[INPUT_KBD_MATRIX_SCAN_OCURRENCES]; + uint8_t scan_cycles_idx; + + struct k_sem poll_lock; + + struct k_thread thread; + + K_KERNEL_STACK_MEMBER(thread_stack, + CONFIG_INPUT_KBD_MATRIX_THREAD_STACK_SIZE); +}; + +/** + * @brief Validate the offset of the common data structures. + * + * @param config Name of the config structure. + * @param data Name of the data structure. + */ +#define INPUT_KBD_STRUCT_CHECK(config, data) \ + BUILD_ASSERT(offsetof(config, common) == 0, \ + "struct input_kbd_matrix_common_config must be placed first"); \ + BUILD_ASSERT(offsetof(data, common) == 0, \ + "struct input_kbd_matrix_common_data must be placed first") + +/** + * @brief Start scanning the keyboard matrix + * + * Starts the keyboard matrix scanning cycle, this should be called in reaction + * of a press event, after the device has been put in detect mode. + * + * @param dev Keyboard matrix device instance. + */ +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. + * + * This function must be called at the end of the device init function. + * + * @param dev Keyboard matrix device instance. + * + * @retval 0 If initialized successfully. + * @retval -errno Negative errno in case of failure. + */ +int input_kbd_matrix_common_init(const struct device *dev); + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_INPUT_KBD_MATRIX_H_ */ diff --git a/include/zephyr/input/input_keymap.h b/include/zephyr/input/input_keymap.h new file mode 100644 index 000000000000000..a3d3534b2babd01 --- /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 new file mode 100644 index 000000000000000..a9b9a642c7682b4 --- /dev/null +++ b/include/zephyr/internal/syscall_handler.h @@ -0,0 +1,659 @@ +/* + * Copyright (c) 2017, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_SYSCALL_HANDLER_H_ +#define ZEPHYR_INCLUDE_SYSCALL_HANDLER_H_ + +/** + * @brief User mode and Syscall APIs + * @defgroup syscall_apis User mode and Syscall APIs + * @ingroup internal_api + * @{ + */ + +#if defined(CONFIG_USERSPACE) || defined(__DOXYGEN__) + +#ifndef _ASMLANGUAGE +#include +#include +#include +#include +#include + +extern const _k_syscall_handler_t _k_syscall_table[K_SYSCALL_LIMIT]; + +enum _obj_init_check { + _OBJ_INIT_TRUE = 0, + _OBJ_INIT_FALSE = -1, + _OBJ_INIT_ANY = 1 +}; + +/** + * Return true if we are currently handling a system call from user mode + * + * Inside z_vrfy functions, we always know that we are handling + * a system call invoked from user context. + * + * However, some checks that are only relevant to user mode must + * instead be placed deeper within the implementation. This + * API is useful to conditionally make these checks. + * + * For performance reasons, whenever possible, checks should be placed + * in the relevant z_vrfy function since these are completely skipped + * when a syscall is invoked. + * + * This will return true only if we are handling a syscall for a + * user thread. If the system call was invoked from supervisor mode, + * or we are not handling a system call, this will return false. + * + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + * + * @return whether the current context is handling a syscall for a user + * mode thread + */ +static inline bool k_is_in_user_syscall(void) +{ + /* This gets set on entry to the syscall's generasted z_mrsh + * function and then cleared on exit. This code path is only + * encountered when a syscall is made from user mode, system + * calls from supervisor mode bypass everything directly to + * the implementation function. + */ + return !k_is_in_isr() && _current->syscall_frame != NULL; +} + +/** + * Ensure a system object is a valid object of the expected type + * + * Searches for the object and ensures that it is indeed an object + * of the expected type, that the caller has the right permissions on it, + * and that the object has been initialized. + * + * This function is intended to be called on the kernel-side system + * call handlers to validate kernel object pointers passed in from + * userspace. + * + * @param ko Kernel object metadata pointer, or NULL + * @param otype Expected type of the kernel object, or K_OBJ_ANY if type + * doesn't matter + * @param init Indicate whether the object needs to already be in initialized + * or uninitialized state, or that we don't care + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + * + * @return 0 If the object is valid + * -EBADF if not a valid object of the specified type + * -EPERM If the caller does not have permissions + * -EINVAL Object is not initialized + */ +int k_object_validate(struct k_object *ko, enum k_objects otype, + enum _obj_init_check init); + +/** + * Dump out error information on failed k_object_validate() call + * + * @param retval Return value from k_object_validate() + * @param obj Kernel object we were trying to verify + * @param ko If retval=-EPERM, struct k_object * that was looked up, or NULL + * @param otype Expected type of the kernel object + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + * + */ +void k_object_dump_error(int retval, const void *obj, + struct k_object *ko, enum k_objects otype); + +/** + * Kernel object validation function + * + * Retrieve metadata for a kernel object. This function is implemented in + * the gperf script footer, see gen_kobject_list.py + * + * @param obj Address of kernel object to get metadata + * @return Kernel object's metadata, or NULL if the parameter wasn't the + * memory address of a kernel object + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + * + */ +struct k_object *k_object_find(const void *obj); + +typedef void (*_wordlist_cb_func_t)(struct k_object *ko, void *context); + +/** + * Iterate over all the kernel object metadata in the system + * + * @param func function to run on each struct k_object + * @param context Context pointer to pass to each invocation + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + * + */ +void k_object_wordlist_foreach(_wordlist_cb_func_t func, void *context); + +/** + * Copy all kernel object permissions from the parent to the child + * + * @param parent Parent thread, to get permissions from + * @param child Child thread, to copy permissions to + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + * + */ +void k_thread_perms_inherit(struct k_thread *parent, struct k_thread *child); + +/** + * Grant a thread permission to a kernel object + * + * @param ko Kernel object metadata to update + * @param thread The thread to grant permission + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + * + */ +void k_thread_perms_set(struct k_object *ko, struct k_thread *thread); + +/** + * Revoke a thread's permission to a kernel object + * + * @param ko Kernel object metadata to update + * @param thread The thread to grant permission + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + * + */ +void k_thread_perms_clear(struct k_object *ko, struct k_thread *thread); + +/** + * Revoke access to all objects for the provided thread + * + * @note Unlike k_thread_perms_clear(), this function will not clear + * permissions on public objects. + * + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + * + * @param thread Thread object to revoke access + */ +void k_thread_perms_all_clear(struct k_thread *thread); + +/** + * Clear initialization state of a kernel object + * + * Intended for thread objects upon thread exit, or for other kernel objects + * that were released back to an object pool. + * + * @param obj Address of the kernel object + * + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +void k_object_uninit(const void *obj); + +/** + * Initialize and reset permissions to only access by the caller + * + * Intended for scenarios where objects are fetched from slab pools + * and may have had different permissions set during prior usage. + * + * This is only intended for pools of objects, where such objects are + * acquired and released to the pool. If an object has already been used, + * we do not want stale permission information hanging around, the object + * should only have permissions on the caller. Objects which are not + * managed by a pool-like mechanism should not use this API. + * + * The object will be marked as initialized and the calling thread + * granted access to it. + * + * @param obj Address of the kernel object + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +void k_object_recycle(const void *obj); + +/** + * @brief Obtain the size of a C string passed from user mode + * + * Given a C string pointer and a maximum size, obtain the true + * size of the string (not including the trailing NULL byte) just as + * if calling strnlen() on it, with the same semantics of strnlen() with + * respect to the return value and the maxlen parameter. + * + * Any memory protection faults triggered by the examination of the string + * will be safely handled and an error code returned. + * + * NOTE: Doesn't guarantee that user mode has actual access to this + * string, you will need to still do a K_SYSCALL_MEMORY_READ() + * with the obtained size value to guarantee this. + * + * @param src String to measure size of + * @param maxlen Maximum number of characters to examine + * @param err Pointer to int, filled in with -1 on memory error, 0 on + * success + * @return undefined on error, or strlen(src) if that is less than maxlen, or + * maxlen if there were no NULL terminating characters within the + * first maxlen bytes. + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +static inline size_t k_usermode_string_nlen(const char *src, size_t maxlen, + int *err) +{ + return arch_user_string_nlen(src, maxlen, err); +} + +/** + * @brief Copy data from userspace into a resource pool allocation + * + * Given a pointer and a size, allocate a similarly sized buffer in the + * caller's resource pool and copy all the data within it to the newly + * allocated buffer. This will need to be freed later with k_free(). + * + * Checks are done to ensure that the current thread would have read + * access to the provided buffer. + * + * @param src Source memory address + * @param size Size of the memory buffer + * @return An allocated buffer with the data copied within it, or NULL + * if some error condition occurred + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +void *k_usermode_alloc_from_copy(const void *src, size_t size); + +/** + * @brief Copy data from user mode + * + * Given a userspace pointer and a size, copies data from it into a provided + * destination buffer, performing checks to ensure that the caller would have + * appropriate access when in user mode. + * + * @param dst Destination memory buffer + * @param src Source memory buffer, in userspace + * @param size Number of bytes to copy + * @retval 0 On success + * @retval EFAULT On memory access error + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +int k_usermode_from_copy(void *dst, const void *src, size_t size); + +/** + * @brief Copy data to user mode + * + * Given a userspace pointer and a size, copies data to it from a provided + * source buffer, performing checks to ensure that the caller would have + * appropriate access when in user mode. + * + * @param dst Destination memory buffer, in userspace + * @param src Source memory buffer + * @param size Number of bytes to copy + * @retval 0 On success + * @retval EFAULT On memory access error + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +int k_usermode_to_copy(void *dst, const void *src, size_t size); + +/** + * @brief Copy a C string from userspace into a resource pool allocation + * + * Given a C string and maximum length, duplicate the string using an + * allocation from the calling thread's resource pool. This will need to be + * freed later with k_free(). + * + * Checks are performed to ensure that the string is valid memory and that + * the caller has access to it in user mode. + * + * @param src Source string pointer, in userspace + * @param maxlen Maximum size of the string including trailing NULL + * @return The duplicated string, or NULL if an error occurred. + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +char *k_usermode_string_alloc_copy(const char *src, size_t maxlen); + +/** + * @brief Copy a C string from userspace into a provided buffer + * + * Given a C string and maximum length, copy the string into a buffer. + * + * Checks are performed to ensure that the string is valid memory and that + * the caller has access to it in user mode. + * + * @param dst Destination buffer + * @param src Source string pointer, in userspace + * @param maxlen Maximum size of the string including trailing NULL + * @retval 0 on success + * @retval EINVAL if the source string is too long with respect + * to maxlen + * @retval EFAULT On memory access error + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +int k_usermode_string_copy(char *dst, const char *src, size_t maxlen); + +/** + * @brief Induce a kernel oops + * + * This macro can be used to induce a kernel oops which will kill the + * calling thread. + * + * @param expr Expression to be evaluated + * + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +#define K_OOPS(expr) \ + do { \ + if (expr) { \ + arch_syscall_oops(_current->syscall_frame); \ + } \ + } while (false) + +/** + * @brief Runtime expression check for system call arguments + * + * Used in handler functions to perform various runtime checks on arguments, + * and generate a kernel oops if anything is not expected, printing a custom + * message. + * + * @param expr Boolean expression to verify, a false result will trigger an + * oops + * @param fmt Printf-style format string (followed by appropriate variadic + * arguments) to print on verification failure + * @return False on success, True on failure + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +#define K_SYSCALL_VERIFY_MSG(expr, fmt, ...) ({ \ + bool expr_copy = !(expr); \ + if (expr_copy) { \ + TOOLCHAIN_IGNORE_WSHADOW_BEGIN \ + LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); \ + TOOLCHAIN_IGNORE_WSHADOW_END \ + LOG_ERR("syscall %s failed check: " fmt, \ + __func__, ##__VA_ARGS__); \ + } \ + expr_copy; }) + +/** + * @brief Runtime expression check for system call arguments + * + * Used in handler functions to perform various runtime checks on arguments, + * and generate a kernel oops if anything is not expected. + * + * @param expr Boolean expression to verify, a false result will trigger an + * oops. A stringified version of this expression will be printed. + * @return 0 on success, nonzero on failure + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +#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 + * + * Checks that the particular memory area is readable and/or writeable by the + * currently running thread if the CPU was in user mode, and generates a kernel + * oops if it wasn't. Prevents userspace from getting the kernel to read and/or + * modify memory the thread does not have access to, or passing in garbage + * pointers that would crash/pagefault the kernel if dereferenced. + * + * @param ptr Memory area to examine + * @param size Size of the memory area + * @param write If the thread should be able to write to this memory, not just + * read it + * @return 0 on success, nonzero on failure + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +#define K_SYSCALL_MEMORY(ptr, size, write) \ + 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") + +/** + * @brief Runtime check that a user thread has read permission to a memory area + * + * Checks that the particular memory area is readable by the currently running + * thread if the CPU was in user mode, and generates a kernel oops if it + * wasn't. Prevents userspace from getting the kernel to read memory the thread + * does not have access to, or passing in garbage pointers that would + * crash/pagefault the kernel if dereferenced. + * + * @param ptr Memory area to examine + * @param size Size of the memory area + * @return 0 on success, nonzero on failure + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +#define K_SYSCALL_MEMORY_READ(ptr, size) \ + K_SYSCALL_MEMORY(ptr, size, 0) + +/** + * @brief Runtime check that a user thread has write permission to a memory area + * + * Checks that the particular memory area is readable and writable by the + * currently running thread if the CPU was in user mode, and generates a kernel + * oops if it wasn't. Prevents userspace from getting the kernel to read or + * modify memory the thread does not have access to, or passing in garbage + * pointers that would crash/pagefault the kernel if dereferenced. + * + * @param ptr Memory area to examine + * @param size Size of the memory area + * @return 0 on success, nonzero on failure + * + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +#define K_SYSCALL_MEMORY_WRITE(ptr, size) \ + K_SYSCALL_MEMORY(ptr, size, 1) + +#define K_SYSCALL_MEMORY_ARRAY(ptr, nmemb, size, write) \ + ({ \ + size_t product; \ + K_SYSCALL_VERIFY_MSG(!size_mul_overflow((size_t)(nmemb), \ + (size_t)(size), \ + &product), \ + "%zux%zu array is too large", \ + (size_t)(nmemb), (size_t)(size)) || \ + K_SYSCALL_MEMORY(ptr, product, write); \ + }) + +/** + * @brief Validate user thread has read permission for sized array + * + * Used when the memory region is expressed in terms of number of elements and + * each element size, handles any overflow issues with computing the total + * array bounds. Otherwise see _SYSCALL_MEMORY_READ. + * + * @param ptr Memory area to examine + * @param nmemb Number of elements in the array + * @param size Size of each array element + * @return 0 on success, nonzero on failure + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +#define K_SYSCALL_MEMORY_ARRAY_READ(ptr, nmemb, size) \ + K_SYSCALL_MEMORY_ARRAY(ptr, nmemb, size, 0) + +/** + * @brief Validate user thread has read/write permission for sized array + * + * Used when the memory region is expressed in terms of number of elements and + * each element size, handles any overflow issues with computing the total + * array bounds. Otherwise see _SYSCALL_MEMORY_WRITE. + * + * @param ptr Memory area to examine + * @param nmemb Number of elements in the array + * @param size Size of each array element + * @return 0 on success, nonzero on failure + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +#define K_SYSCALL_MEMORY_ARRAY_WRITE(ptr, nmemb, size) \ + K_SYSCALL_MEMORY_ARRAY(ptr, nmemb, size, 1) + +static inline int k_object_validation_check(struct k_object *ko, + const void *obj, + enum k_objects otype, + enum _obj_init_check init) +{ + int ret; + + ret = k_object_validate(ko, otype, init); + +#ifdef CONFIG_LOG + if (ret != 0) { + k_object_dump_error(ret, obj, ko, otype); + } +#else + ARG_UNUSED(obj); +#endif + + return ret; +} + +#define K_SYSCALL_IS_OBJ(ptr, type, init) \ + K_SYSCALL_VERIFY_MSG(k_object_validation_check( \ + k_object_find((const void *)ptr), \ + (const void *)ptr, \ + type, init) == 0, "access denied") + +/** + * @brief Runtime check driver object pointer for presence of operation + * + * Validates if the driver object is capable of performing a certain operation. + * + * @param ptr Untrusted device instance object pointer + * @param api_name Name of the driver API struct (e.g. gpio_driver_api) + * @param op Driver operation (e.g. manage_callback) + * + * @return 0 on success, nonzero on failure + * + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +#define K_SYSCALL_DRIVER_OP(ptr, api_name, op) \ + ({ \ + struct api_name *__device__ = (struct api_name *) \ + ((const struct device *)ptr)->api; \ + K_SYSCALL_VERIFY_MSG(__device__->op != NULL, \ + "Operation %s not defined for driver " \ + "instance %p", \ + # op, __device__); \ + }) + +/** + * @brief Runtime check that device object is of a specific driver type + * + * Checks that the driver object passed in is initialized, the caller has + * correct permissions, and that it belongs to the specified driver + * subsystems. Additionally, all devices store a structure pointer of the + * driver's API. If this doesn't match the value provided, the check will fail. + * + * This provides an easy way to determine if a device object not only + * belongs to a particular subsystem, but is of a specific device driver + * implementation. Useful for defining out-of-subsystem system calls + * which are implemented for only one driver. + * + * @param _device Untrusted device pointer + * @param _dtype Expected kernel object type for the provided device pointer + * @param _api Expected driver API structure memory address + * @return 0 on success, nonzero on failure + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +#define K_SYSCALL_SPECIFIC_DRIVER(_device, _dtype, _api) \ + ({ \ + const struct device *_dev = (const struct device *)_device; \ + K_SYSCALL_OBJ(_dev, _dtype) || \ + K_SYSCALL_VERIFY_MSG(_dev->api == _api, \ + "API structure mismatch"); \ + }) + +/** + * @brief Runtime check kernel object pointer for non-init functions + * + * Calls k_object_validate and triggers a kernel oops if the check fails. + * For use in system call handlers which are not init functions; a fatal + * error will occur if the object is not initialized. + * + * @param ptr Untrusted kernel object pointer + * @param type Expected kernel object type + * @return 0 on success, nonzero on failure + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +#define K_SYSCALL_OBJ(ptr, type) \ + K_SYSCALL_IS_OBJ(ptr, type, _OBJ_INIT_TRUE) + +/** + * @brief Runtime check kernel object pointer for non-init functions + * + * See description of _SYSCALL_IS_OBJ. No initialization checks are done. + * Intended for init functions where objects may be re-initialized at will. + * + * @param ptr Untrusted kernel object pointer + * @param type Expected kernel object type + * @return 0 on success, nonzero on failure + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ + +#define K_SYSCALL_OBJ_INIT(ptr, type) \ + K_SYSCALL_IS_OBJ(ptr, type, _OBJ_INIT_ANY) + +/** + * @brief Runtime check kernel object pointer for non-init functions + * + * See description of _SYSCALL_IS_OBJ. Triggers a fatal error if the object is + * initialized. Intended for init functions where objects, once initialized, + * can only be re-used when their initialization state expires due to some + * other mechanism. + * + * @param ptr Untrusted kernel object pointer + * @param type Expected kernel object type + * @return 0 on success, nonzero on failure + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ + +#define K_SYSCALL_OBJ_NEVER_INIT(ptr, type) \ + K_SYSCALL_IS_OBJ(ptr, type, _OBJ_INIT_FALSE) + +#include + +#endif /* _ASMLANGUAGE */ + +#endif /* CONFIG_USERSPACE */ +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_SYSCALL_HANDLER_H_ */ diff --git a/include/zephyr/ipc/icmsg.h b/include/zephyr/ipc/icmsg.h index cdd1cb064d1e83f..a3b43690cc4be5a 100644 --- a/include/zephyr/ipc/icmsg.h +++ b/include/zephyr/ipc/icmsg.h @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include #ifdef __cplusplus extern "C" { @@ -33,19 +33,14 @@ enum icmsg_state { }; struct icmsg_config_t { - uintptr_t tx_shm_addr; - uintptr_t rx_shm_addr; - size_t tx_shm_size; - size_t rx_shm_size; struct mbox_channel mbox_tx; struct mbox_channel mbox_rx; }; struct icmsg_data_t { /* Tx/Rx buffers. */ - struct spsc_pbuf *tx_ib; - struct spsc_pbuf *rx_ib; - atomic_t tx_buffer_state; + struct pbuf *tx_pb; + struct pbuf *rx_pb; #ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC struct k_mutex tx_lock; #endif @@ -59,12 +54,6 @@ struct icmsg_data_t { struct k_work_delayable notify_work; struct k_work mbox_work; atomic_t state; - /* No-copy */ -#ifdef CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX - atomic_t rx_buffer_state; - const void *rx_buffer; - uint16_t rx_len; -#endif }; /** @brief Open an icmsg instance @@ -134,151 +123,6 @@ int icmsg_send(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data, const void *msg, size_t len); -/** @brief Get an empty TX buffer to be sent using @ref icmsg_send_nocopy - * - * This function can be called to get an empty TX buffer so that the - * application can directly put its data into the sending buffer avoiding copy - * performed by the icmsg library. - * - * It is the application responsibility to correctly fill the allocated TX - * buffer with data and passing correct parameters to @ref - * icmsg_send_nocopy function to perform data no-copy-send mechanism. - * - * The size parameter can be used to request a buffer with a certain size: - * - if the size can be accommodated the function returns no errors and the - * buffer is allocated - * - if the requested size is too big, the function returns -ENOMEM and the - * the buffer is not allocated. - * - if the requested size is '0' the buffer is allocated with the maximum - * allowed size. - * - * In all the cases on return the size parameter contains the maximum size for - * the returned buffer. - * - * When the function returns no errors, the buffer is intended as allocated - * and it is released under one of two conditions: (1) when sending the buffer - * using @ref icmsg_send_nocopy (and in this case the buffer is automatically - * released by the backend), (2) when using @ref icmsg_drop_tx_buffer on a - * buffer not sent. - * - * @param[in] conf Structure containing configuration parameters for the icmsg - * instance. - * @param[inout] dev_data Structure containing run-time data used by the icmsg - * instance. - * @param[out] data Pointer to the empty TX buffer. - * @param[inout] size Pointer to store the requested TX buffer size. If the - * function returns -ENOMEM, this parameter returns the - * maximum allowed size. - * - * @retval -ENOBUFS when there are no TX buffers available. - * @retval -EALREADY when a buffer was already claimed and not yet released. - * @retval -ENOMEM when the requested size is too big (and the size parameter - * contains the maximum allowed size). - * - * @retval 0 on success. - */ -int icmsg_get_tx_buffer(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - void **data, size_t *size); - -/** @brief Drop and release a TX buffer - * - * Drop and release a TX buffer. It is possible to drop only TX buffers - * obtained by using @ref icmsg_get_tx_buffer. - * - * @param[in] conf Structure containing configuration parameters for the icmsg - * instance. - * @param[inout] dev_data Structure containing run-time data used by the icmsg - * instance. - * @param[in] data Pointer to the TX buffer. - * - * @retval -EALREADY when the buffer was already dropped. - * @retval -ENXIO when the buffer was not obtained using @ref - * ipc_service_get_tx_buffer - * - * @retval 0 on success. - */ -int icmsg_drop_tx_buffer(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - const void *data); - -/** @brief Send a message from a buffer obtained by @ref icmsg_get_tx_buffer - * to the remote icmsg instance. - * - * This is equivalent to @ref icmsg_send but in this case the TX buffer must - * have been obtained by using @ref icmsg_get_tx_buffer. - * - * The API user has to take the responsibility for getting the TX buffer using - * @ref icmsg_get_tx_buffer and filling the TX buffer with the data. - * - * After the @ref icmsg_send_nocopy function is issued the TX buffer is no - * more owned by the sending task and must not be touched anymore unless the - * function fails and returns an error. - * - * If this function returns an error, @ref icmsg_drop_tx_buffer can be used - * to drop the TX buffer. - * - * @param[in] conf Structure containing configuration parameters for the icmsg - * instance. - * @param[inout] dev_data Structure containing run-time data used by the icmsg - * instance. - * @param[in] msg Pointer to a buffer containing data to send. - * @param[in] len Size of data in the @p msg buffer. - * - * - * @return Size of sent data on success. - * @retval -EBUSY when the instance has not finished handshake with the remote - * instance. - * @retval -ENODATA when the requested data to send is empty. - * @retval -EBADMSG when the requested data to send is too big. - * @retval -ENXIO when the buffer was not obtained using @ref - * ipc_service_get_tx_buffer - * @retval other errno codes from dependent modules. - */ -int icmsg_send_nocopy(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - const void *msg, size_t len); - -#ifdef CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX -/** @brief Hold RX buffer to be used outside of the received callback. - * - * @param[in] conf Structure containing configuration parameters for the icmsg - * instance. - * @param[inout] dev_data Structure containing run-time data used by the icmsg - * instance. - * @param[in] data Pointer to the buffer to be held. - * - * @retval 0 on success. - * @retval -EBUSY when the instance has not finished handshake with the remote - * instance. - * @retval -EINVAL when the @p data argument does not point to a valid RX - * buffer. - * @retval -EALREADY when the buffer is already held. - */ -int icmsg_hold_rx_buffer(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - const void *data); - -/** @brief Release RX buffer for future use. - * - * @param[in] conf Structure containing configuration parameters for the icmsg - * instance. - * @param[inout] dev_data Structure containing run-time data used by the icmsg - * instance. - * @param[in] data Pointer to the buffer to be released. - * - * @retval 0 on success. - * @retval -EBUSY when the instance has not finished handshake with the remote - * instance. - * @retval -EINVAL when the @p data argument does not point to a valid RX - * buffer. - * @retval -EALREADY when the buffer is not held. - */ -int icmsg_release_rx_buffer(const struct icmsg_config_t *conf, - struct icmsg_data_t *dev_data, - const void *data); -#endif - /** * @} */ diff --git a/include/zephyr/ipc/icmsg_me.h b/include/zephyr/ipc/icmsg_me.h index 554f5785ba837d4..9736b0148c6cd0c 100644 --- a/include/zephyr/ipc/icmsg_me.h +++ b/include/zephyr/ipc/icmsg_me.h @@ -247,118 +247,6 @@ int icmsg_me_send(const struct icmsg_config_t *conf, struct icmsg_me_data_t *data, icmsg_me_ept_id_t id, const void *msg, size_t len); -/** @brief Get an empty TX buffer to be sent using @ref icmsg_me_send_nocopy - * - * This function is a wrapper around @ref icmsg_get_tx_buffer aligning buffer - * size and pointers to fit header required by the multi-endpoint feature. - * It shares all properites and usage scenarios with @ref icmsg_get_tx_buffer. - * - * @param[in] conf Structure containing configuration parameters for the - & underlying icmsg instance. - * @param[inout] data Structure containing run-time data used by the icmsg_me - * instance. The structure is initialized with - * @ref icmsg_me_init and its content must be preserved - * while the icmsg_me instance is active. - * @param[out] buffer Pointer to the empty TX buffer. - * @param[inout] size Pointer to store the requested TX buffer size. If the - * function returns -ENOMEM, this parameter returns the - * maximum allowed size. - * @param[in] wait Timeout value to wait for a free buffer acceptable by - * the function caller. Only K_NO_WAIT is supported by icmsg. - * - * @retval 0 on success. - * @retval -ENOTSUP when requested unsupported @p wait timeout. - * @retval -ENOBUFS when there are no TX buffers available. - * @retval -ENOMEM when the requested size is too big (and the size parameter - * contains the maximum allowed size). - * @retval other errno codes from dependent modules. - */ -int icmsg_me_get_tx_buffer(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, - void **buffer, uint32_t *size, k_timeout_t wait); - -/** @brief Drop and release a TX buffer - * - * This function is a wrapper around @ref icmsg_drop_tx_buffer aligning buffer - * pointer to fit header required by the multi-endpoint feature. This function - * shares all properties and usage scenarios with @ref icmsg_drop_tx_buffer. - * - * @param[in] conf Structure containing configuration parameters for the - * underlying icmsg instance. - * @param[inout] data Structure containing run-time data used by the icmsg_me - * instance. The structure is initialized with - * @ref icmsg_me_init and its content must be preserved - * while the icmsg_me instance is active. - * @param[in] buffer Pointer to the TX buffer obtained with - * @ref icmsg_me_get_tx_buffer. - * - * @retval 0 on success. - * @retval other errno codes from dependent modules. - */ -int icmsg_me_drop_tx_buffer(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, - const void *buffer); - -/** @brief Send a message from a buffer obtained by @ref icmsg_me_get_tx_buffer - * to the remote icmsg_me instance. - * - * This function is a wrapper around @ref icmsg_send_nocopy aligning buffer - * size and pointer to fit header required by the multi-endpoint feature. This - * function shares all properties and usage scenarios with - * @ref icmsg_send_nocopy. - * - * @param[in] conf Structure containing configuration parameters for the - * underlying icmsg instance. - * @param[inout] data Structure containing run-time data used by the icmsg_me - * instance. The structure is initialized with - * @ref icmsg_me_init and its content must be preserved - * while the icmsg_me instance is active. - * @param[in] id Id of the endpoint to use. - * @param[in] msg Pointer to a buffer containing data to send. - * @param[in] len Size of data in the @p msg buffer. - * - * - * @return Size of sent data on success. - * @retval other errno codes from dependent modules. - */ -int icmsg_me_send_nocopy(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, icmsg_me_ept_id_t id, - const void *msg, size_t len); - -#ifdef CONFIG_IPC_SERVICE_ICMSG_ME_NOCOPY_RX -/** @brief Hold RX buffer to be used outside of the received callback. - * - * @param[in] conf Structure containing configuration parameters for the - * underlying icmsg instance. - * @param[inout] data Structure containing run-time data used by the icmsg_me - * instance. The structure is initialized with - * @ref icmsg_me_init and its content must be preserved - * while the icmsg_me instance is active. - * @param[in] buffer Pointer to the buffer to be held. - * - * @retval 0 on success. - * @retval other errno codes from dependent modules. - */ -int icmsg_me_hold_rx_buffer(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, void *buffer); - -/** @brief Release RX buffer for future use. - * - * @param[in] conf Structure containing configuration parameters for the - * underlying icmsg instance. - * @param[inout] data Structure containing run-time data used by the icmsg_me - * instance. The structure is initialized with - * @ref icmsg_me_init and its content must be preserved - * while the icmsg_me instance is active. - * @param[in] buffer Pointer to the buffer to be released. - * - * @retval 0 on success. - * @retval other errno codes from dependent modules. - */ -int icmsg_me_release_rx_buffer(const struct icmsg_config_t *conf, - struct icmsg_me_data_t *data, void *buffer); -#endif /* CONFIG_IPC_SERVICE_ICMSG_ME_NOCOPY_RX */ - /** * @} */ diff --git a/include/zephyr/ipc/pbuf.h b/include/zephyr/ipc/pbuf.h new file mode 100644 index 000000000000000..7e61950c808da32 --- /dev/null +++ b/include/zephyr/ipc/pbuf.h @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_IPC_PBUF_H_ +#define ZEPHYR_INCLUDE_IPC_PBUF_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Packed buffer API + * @defgroup pbuf Packed Buffer API + * @ingroup ipc + * @{ + */ + +/** @brief Size of packet length field. */ +#define PBUF_PACKET_LEN_SZ sizeof(uint32_t) + +/* Amount of data that is left unused to distinguish between empty and full. */ +#define _PBUF_IDX_SIZE sizeof(uint32_t) + +/* Minimal length of the data field in the buffer to store the smalest packet + * possible. + * (+1) for at least one byte of data. + * (+_PBUF_IDX_SIZE) to distinguish buffer full and buffer empty. + * Rounded up to keep wr/rd indexes pointing to aligned address. + */ +#define _PBUF_MIN_DATA_LEN ROUND_UP(PBUF_PACKET_LEN_SZ + 1 + _PBUF_IDX_SIZE, _PBUF_IDX_SIZE) + +/** @brief Control block of packet buffer. + * + * The structure contains configuration data. + */ +struct pbuf_cfg { + volatile uint32_t *rd_idx_loc; /* Address of the variable holding + * index value of the first valid byte + * in data[]. + */ + volatile uint32_t *wr_idx_loc; /* Address of the variable holding + * index value of the first free byte + * in data[]. + */ + uint32_t dcache_alignment; /* CPU data cache line size in bytes. + * Used for validation - TODO: To be + * replaced by flags. + */ + uint32_t len; /* Length of data[] in bytes. */ + uint8_t *data_loc; /* Location of the data[]. */ +}; + +/** + * @brief Data block of the packed buffer. + * + * The structure contains local copies of wr and rd indexes used by writer and + * reader respecitvely. + */ +struct pbuf_data { + volatile uint32_t wr_idx; /* Index of the first holding first + * free byte in data[]. Used for + * writing. + */ + volatile uint32_t rd_idx; /* Index of the first holding first + * valid byte in data[]. Used for + * reading. + */ +}; + + +/** + * @brief Scure packed buffer. + * + * The packet buffer implements lightweight unidirectional packet + * buffer with read/write semantics on top of a memory region shared + * by the reader and writer. It embeds cache and memory barrier management to + * ensure correct data access. + * + * This structure supports single writer and reader. Data stored in the buffer + * is encapsulated to a message (with length header). The read/write API is + * written in a way to protect the data from being corrupted. + */ +struct pbuf { + const struct pbuf_cfg *const cfg; /* Configuration of the + * buffer. + */ + struct pbuf_data data; /* Data used to read and write + * to the buffer + */ +}; + +/** + * @brief Macro for configuration initialization. + * + * It is recommended to use this macro to initialize packed buffer + * configuration. + * + * @param mem_addr Memory address for pbuf. + * @param size Size of the memory. + * @param dcache_align Data cache alignment. + */ +#define PBUF_CFG_INIT(mem_addr, size, dcache_align) \ +{ \ + .rd_idx_loc = (uint32_t *)(mem_addr), \ + .wr_idx_loc = (uint32_t *)((uint8_t *)(mem_addr) + \ + MAX(dcache_align, _PBUF_IDX_SIZE)), \ + .data_loc = (uint8_t *)((uint8_t *)(mem_addr) + \ + MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE), \ + .len = (uint32_t)((uint32_t)(size) - MAX(dcache_align, _PBUF_IDX_SIZE) - \ + _PBUF_IDX_SIZE), \ + .dcache_alignment = (dcache_align), \ +} + +/** + * @brief Macro calculates memory overhead taken by the header in shared memory. + * + * It contains the read index, write index and padding. + * + * @param dcache_align Data cache alignment. + */ +#define PBUF_HEADER_OVERHEAD(dcache_align) \ + (MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE) + +/** + * @brief Statically define and initialize pbuf. + * + * @param name Name of the pbuf. + * @param mem_addr Memory address for pbuf. + * @param size Size of the memory. + * @param dcache_align Data cache line size. + */ +#define PBUF_DEFINE(name, mem_addr, size, dcache_align) \ + BUILD_ASSERT(dcache_align >= 0, \ + "Cache line size must be non negative."); \ + BUILD_ASSERT((size) > 0 && IS_PTR_ALIGNED_BYTES(size, _PBUF_IDX_SIZE), \ + "Incorrect size."); \ + BUILD_ASSERT(IS_PTR_ALIGNED_BYTES(mem_addr, MAX(dcache_align, _PBUF_IDX_SIZE)), \ + "Misaligned memory."); \ + BUILD_ASSERT(size >= (MAX(dcache_align, _PBUF_IDX_SIZE) + _PBUF_IDX_SIZE + \ + _PBUF_MIN_DATA_LEN), "Insufficient size."); \ + \ + static const struct pbuf_cfg cfg_##name = \ + PBUF_CFG_INIT(mem_addr, size, dcache_align); \ + static struct pbuf name = { \ + .cfg = &cfg_##name, \ + } + +/** + * @brief Initialize the packet buffer. + * + * This function initializes the packet buffer based on provided configuration. + * If the configuration is incorrect, the function will return error. + * + * It is recommended to use PBUF_DEFINE macro for build time initialization. + * + * @param pb Pointer to the packed buffer containing + * configuration and data. Configuration has to be + * fixed before the initialization. + * @retval 0 on success. + * @retval -EINVAL when the input parameter is incorrect. + */ +int pbuf_init(struct pbuf *pb); + +/** + * @brief Write specified amount of data to the packet buffer. + * + * This function call writes specified amount of data to the packet buffer if + * the buffer will fit the data. + * + * @param pb A buffer to which to write. + * @param buf Pointer to the data to be written to the buffer. + * @param len Number of bytes to be written to the buffer. Must be positive. + * @retval int Number of bytes written, negative error code on fail. + * -EINVAL, if any of input parameter is incorrect. + * -ENOMEM, if len is bigger than the buffer can fit. + */ + +int pbuf_write(struct pbuf *pb, const char *buf, uint16_t len); + +/** + * @brief Read specified amount of data from the packet buffer. + * + * Single read allows to read the message send by the single write. + * The provided %p buf must be big enough to store the whole message. + * + * @param pb A buffer from which data will be read. + * @param buf Data pointer to which read data will be written. + * If NULL, len of stored message is returned. + * @param len Number of bytes to be read from the buffer. + * @retval int Bytes read, negative error code on fail. + * Bytes to be read, if buf == NULL. + * -EINVAL, if any of input parameter is incorrect. + * -ENOMEM, if message can not fit in provided buf. + * -EAGAIN, if not whole message is ready yet. + */ +int pbuf_read(struct pbuf *pb, char *buf, uint16_t len); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_IPC_PBUF_H_ */ diff --git a/include/zephyr/irq.h b/include/zephyr/irq.h index 1a94a732bbcf745..1fa559edccd3470 100644 --- a/include/zephyr/irq.h +++ b/include/zephyr/irq.h @@ -280,137 +280,6 @@ void z_smp_global_unlock(unsigned int key); #define irq_unlock(key) arch_irq_unlock(key) #endif -/** - * @brief Return IRQ level - * This routine returns the interrupt level number of the provided interrupt. - * - * @param irq IRQ number in its zephyr format - * - * @return 1 if IRQ level 1, 2 if IRQ level 2, 3 if IRQ level 3 - */ -static inline unsigned int irq_get_level(unsigned int irq) -{ - const uint32_t mask2 = BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS) << - CONFIG_1ST_LEVEL_INTERRUPT_BITS; - const uint32_t mask3 = BIT_MASK(CONFIG_3RD_LEVEL_INTERRUPT_BITS) << - (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS); - - if (IS_ENABLED(CONFIG_3RD_LEVEL_INTERRUPTS) && (irq & mask3) != 0) { - return 3; - } - - if (IS_ENABLED(CONFIG_2ND_LEVEL_INTERRUPTS) && (irq & mask2) != 0) { - return 2; - } - - return 1; -} - -#if defined(CONFIG_2ND_LEVEL_INTERRUPTS) -/** - * @brief Return the 2nd level interrupt number - * - * This routine returns the second level irq number of the zephyr irq - * number passed in - * - * @param irq IRQ number in its zephyr format - * - * @return 2nd level IRQ number - */ -static inline unsigned int irq_from_level_2(unsigned int irq) -{ -#if defined(CONFIG_3RD_LEVEL_INTERRUPTS) - return ((irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) & - BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS)) - 1; -#else - return (irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) - 1; -#endif -} - -/** - * @brief Converts irq from level 1 to level 2 format - * - * - * This routine converts the input into the level 2 irq number format - * - * @note Values >= 0xFF are invalid - * - * @param irq IRQ number in its zephyr format - * - * @return 2nd level IRQ number - */ -static inline unsigned int irq_to_level_2(unsigned int irq) -{ - return (irq + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS; -} - -/** - * @brief Returns the parent IRQ of the level 2 raw IRQ number - * - * - * The parent of a 2nd level interrupt is in the 1st byte - * - * @param irq IRQ number in its zephyr format - * - * @return 2nd level IRQ parent - */ -static inline unsigned int irq_parent_level_2(unsigned int irq) -{ - return irq & BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS); -} -#endif - -#ifdef CONFIG_3RD_LEVEL_INTERRUPTS -/** - * @brief Return the 3rd level interrupt number - * - * - * This routine returns the third level irq number of the zephyr irq - * number passed in - * - * @param irq IRQ number in its zephyr format - * - * @return 3rd level IRQ number - */ -static inline unsigned int irq_from_level_3(unsigned int irq) -{ - return (irq >> (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS)) - 1; -} - -/** - * @brief Converts irq from level 1 to level 3 format - * - * - * This routine converts the input into the level 3 irq number format - * - * @note Values >= 0xFF are invalid - * - * @param irq IRQ number in its zephyr format - * - * @return 3rd level IRQ number - */ -static inline unsigned int irq_to_level_3(unsigned int irq) -{ - return (irq + 1) << (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS); -} - -/** - * @brief Returns the parent IRQ of the level 3 raw IRQ number - * - * - * The parent of a 3rd level interrupt is in the 2nd byte - * - * @param irq IRQ number in its zephyr format - * - * @return 3rd level IRQ parent - */ -static inline unsigned int irq_parent_level_3(unsigned int irq) -{ - return (irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) & - BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); -} -#endif - /** * @brief Enable an IRQ. * diff --git a/include/zephyr/irq_multilevel.h b/include/zephyr/irq_multilevel.h new file mode 100644 index 000000000000000..25daa0302495c02 --- /dev/null +++ b/include/zephyr/irq_multilevel.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public interface for multi-level interrupts + */ +#ifndef ZEPHYR_INCLUDE_IRQ_MULTILEVEL_H_ +#define ZEPHYR_INCLUDE_IRQ_MULTILEVEL_H_ + +#ifndef _ASMLANGUAGE +#include +#include + +#ifdef __cplusplus +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. + * + * @param irq IRQ number in its zephyr format + * + * @return 1 if IRQ level 1, 2 if IRQ level 2, 3 if IRQ level 3 + */ +static inline unsigned int irq_get_level(unsigned int irq) +{ + const uint32_t mask2 = BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS) << + CONFIG_1ST_LEVEL_INTERRUPT_BITS; + const uint32_t mask3 = BIT_MASK(CONFIG_3RD_LEVEL_INTERRUPT_BITS) << + (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS); + + if (IS_ENABLED(CONFIG_3RD_LEVEL_INTERRUPTS) && (irq & mask3) != 0) { + return 3; + } + + if (IS_ENABLED(CONFIG_2ND_LEVEL_INTERRUPTS) && (irq & mask2) != 0) { + return 2; + } + + return 1; +} + +/** + * @brief Return the 2nd level interrupt number + * + * This routine returns the second level irq number of the zephyr irq + * number passed in + * + * @param irq IRQ number in its zephyr format + * + * @return 2nd level IRQ number + */ +static inline unsigned int irq_from_level_2(unsigned int irq) +{ + if (IS_ENABLED(CONFIG_3RD_LEVEL_INTERRUPTS)) { + return ((irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) & + BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS)) - 1; + } else { + return (irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) - 1; + } +} + +/** + * @brief Preprocessor macro to convert `irq` from level 1 to level 2 format + * + * @param irq IRQ number in its zephyr format + * + * @return 2nd level IRQ number + */ +#define IRQ_TO_L2(irq) ((irq + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS) + +/** + * @brief Converts irq from level 1 to level 2 format + * + * + * This routine converts the input into the level 2 irq number format + * + * @note Values >= 0xFF are invalid + * + * @param irq IRQ number in its zephyr format + * + * @return 2nd level IRQ number + */ +static inline unsigned int irq_to_level_2(unsigned int irq) +{ + return IRQ_TO_L2(irq); +} + +/** + * @brief Returns the parent IRQ of the level 2 raw IRQ number + * + * + * The parent of a 2nd level interrupt is in the 1st byte + * + * @param irq IRQ number in its zephyr format + * + * @return 2nd level IRQ parent + */ +static inline unsigned int irq_parent_level_2(unsigned int irq) +{ + return irq & BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS); +} + +/** + * @brief Return the 3rd level interrupt number + * + * + * This routine returns the third level irq number of the zephyr irq + * number passed in + * + * @param irq IRQ number in its zephyr format + * + * @return 3rd level IRQ number + */ +static inline unsigned int irq_from_level_3(unsigned int irq) +{ + return (irq >> (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS)) - 1; +} + +/** + * @brief Preprocessor macro to convert `irq` from level 1 to level 3 format + * + * @param irq IRQ number in its zephyr format + * + * @return 3rd level IRQ number + */ +#define IRQ_TO_L3(irq) \ + ((irq + 1) << (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS)) + +/** + * @brief Converts irq from level 1 to level 3 format + * + * + * This routine converts the input into the level 3 irq number format + * + * @note Values >= 0xFF are invalid + * + * @param irq IRQ number in its zephyr format + * + * @return 3rd level IRQ number + */ +static inline unsigned int irq_to_level_3(unsigned int irq) +{ + return IRQ_TO_L3(irq); +} + +/** + * @brief Returns the parent IRQ of the level 3 raw IRQ number + * + * + * The parent of a 3rd level interrupt is in the 2nd byte + * + * @param irq IRQ number in its zephyr format + * + * @return 3rd level IRQ parent + */ +static inline unsigned int irq_parent_level_3(unsigned int irq) +{ + return (irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) & + BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); +} + +#endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ +#endif /* ZEPHYR_INCLUDE_IRQ_MULTILEVEL_H_ */ diff --git a/include/zephyr/irq_nextlevel.h b/include/zephyr/irq_nextlevel.h index 20533cdf6e0fd3f..e5ab4ffdd8acf7d 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 5dc5848898567b8..9f2b750d166f004 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -58,12 +58,12 @@ BUILD_ASSERT(sizeof(intptr_t) == sizeof(long)); #define K_LOWEST_APPLICATION_THREAD_PRIO (K_LOWEST_THREAD_PRIO - 1) #ifdef CONFIG_POLL -#define _POLL_EVENT_OBJ_INIT(obj) \ +#define Z_POLL_EVENT_OBJ_INIT(obj) \ .poll_events = SYS_DLIST_STATIC_INIT(&obj.poll_events), -#define _POLL_EVENT sys_dlist_t poll_events +#define Z_DECL_POLL_EVENT sys_dlist_t poll_events; #else -#define _POLL_EVENT_OBJ_INIT(obj) -#define _POLL_EVENT +#define Z_POLL_EVENT_OBJ_INIT(obj) +#define Z_DECL_POLL_EVENT #endif struct k_thread; @@ -118,7 +118,7 @@ typedef void (*k_thread_user_cb_t)(const struct k_thread *thread, * list which means creation of new threads and terminations of existing * threads are blocked until this API returns. */ -extern void k_thread_foreach(k_thread_user_cb_t user_cb, void *user_data); +void k_thread_foreach(k_thread_user_cb_t user_cb, void *user_data); /** * @brief Iterate over all the threads in the system without locking. @@ -147,7 +147,7 @@ extern void k_thread_foreach(k_thread_user_cb_t user_cb, void *user_data); * Do not reuse the memory that was occupied by k_thread structure of aborted * task if it was aborted after this function was called in any context. */ -extern void k_thread_foreach_unlocked( +void k_thread_foreach_unlocked( k_thread_user_cb_t user_cb, void *user_data); /** @} */ @@ -171,7 +171,6 @@ extern 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 @@ extern 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 @@ extern 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 @@ extern 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 @@ extern 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 @@ extern 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 */ @@ -371,7 +355,7 @@ __syscall k_tid_t k_thread_create(struct k_thread *new_thread, * @param p2 2nd entry point parameter * @param p3 3rd entry point parameter */ -extern FUNC_NORETURN void k_thread_user_mode_enter(k_thread_entry_t entry, +FUNC_NORETURN void k_thread_user_mode_enter(k_thread_entry_t entry, void *p1, void *p2, void *p3); @@ -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); @@ -531,6 +518,10 @@ __syscall int32_t k_usleep(int32_t us); * k_sleep(). For example k_busy_wait(1000) may take slightly more or * less time than k_sleep(K_MSEC(1)), with the offset dependent on * clock tolerances. + * + * @note In case when @kconfig{CONFIG_SYSTEM_CLOCK_SLOPPY_IDLE} and + * @kconfig{CONFIG_PM} options are enabled, this function may not work. + * The timer/clock used for delay processing may be disabled/inactive. */ __syscall void k_busy_wait(uint32_t usec_to_wait); @@ -592,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; @@ -617,11 +609,7 @@ static inline k_tid_t k_current_get(void) * this is done via blocking the caller (in the same manner as * k_thread_join()), but in interrupt context on SMP systems the * implementation is required to spin for threads that are running on - * other CPUs. Note that as specified, this means that on SMP - * platforms it is possible for application code to create a deadlock - * condition by simultaneously aborting a cycle of threads using at - * least one termination from interrupt context. Zephyr cannot detect - * all such conditions. + * other CPUs. * * @param thread ID of thread to abort. */ @@ -639,8 +627,8 @@ __syscall void k_thread_abort(k_tid_t thread); */ __syscall void k_thread_start(k_tid_t thread); -extern k_ticks_t z_timeout_expires(const struct _timeout *timeout); -extern k_ticks_t z_timeout_remaining(const struct _timeout *timeout); +k_ticks_t z_timeout_expires(const struct _timeout *timeout); +k_ticks_t z_timeout_remaining(const struct _timeout *timeout); #ifdef CONFIG_SYS_CLOCK_EXISTS @@ -875,7 +863,7 @@ __syscall void k_thread_priority_set(k_tid_t thread, int prio); * may result in scheduled threads running in an incorrect deadline * order. * - * @note Despite the API naming, the scheduler makes no guarantees the + * @note Despite the API naming, the scheduler makes no guarantees * the thread WILL be scheduled within that deadline, nor does it take * extra metadata (like e.g. the "runtime" and "period" parameters in * Linux sched_setattr()) that allows the kernel to validate the @@ -974,6 +962,11 @@ int k_thread_cpu_pin(k_tid_t thread, int cpu); * will be canceled. On resume, the thread will begin running * immediately and return from the blocked call. * + * When the target thread is active on another CPU, the caller will block until + * the target thread is halted (suspended or aborted). But if the caller is in + * an interrupt context, it will spin waiting for that target thread active on + * another CPU to halt. + * * If @a thread is already suspended, the routine has no effect. * * @param thread ID of thread to suspend. @@ -1018,7 +1011,7 @@ __syscall void k_thread_resume(k_tid_t thread); * @param slice Maximum time slice length (in milliseconds). * @param prio Highest thread priority level eligible for time slicing. */ -extern void k_sched_time_slice_set(int32_t slice, int prio); +void k_sched_time_slice_set(int32_t slice, int prio); /** * @brief Set thread time slice @@ -1079,7 +1072,7 @@ void k_thread_time_slice_set(struct k_thread *th, int32_t slice_ticks, * @return false if invoked by a thread. * @return true if invoked by an ISR. */ -extern bool k_is_in_isr(void); +bool k_is_in_isr(void); /** * @brief Determine if code is running in a preemptible thread. @@ -1151,7 +1144,7 @@ static inline bool k_is_pre_kernel(void) * In general this is a historical API not well-suited to modern * applications, use with care. */ -extern void k_sched_lock(void); +void k_sched_lock(void); /** * @brief Unlock the scheduler. @@ -1160,7 +1153,7 @@ extern void k_sched_lock(void); * A thread must call the routine once for each time it called k_sched_lock() * before the thread becomes preemptible. */ -extern void k_sched_unlock(void); +void k_sched_unlock(void); /** * @brief Set current thread's custom data. @@ -1557,7 +1550,7 @@ typedef void (*k_timer_stop_t)(struct k_timer *timer); * @param expiry_fn Function to invoke each time the timer expires. * @param stop_fn Function to invoke if the timer is stopped while running. */ -extern void k_timer_init(struct k_timer *timer, +void k_timer_init(struct k_timer *timer, k_timer_expiry_t expiry_fn, k_timer_stop_t stop_fn); @@ -1844,7 +1837,7 @@ struct k_queue { struct k_spinlock lock; _wait_q_t wait_q; - _POLL_EVENT; + Z_DECL_POLL_EVENT SYS_PORT_TRACING_TRACKING_FIELD(k_queue) }; @@ -1858,7 +1851,7 @@ struct k_queue { .data_q = SYS_SFLIST_STATIC_INIT(&obj.data_q), \ .lock = { }, \ .wait_q = Z_WAIT_Q_INIT(&obj.wait_q), \ - _POLL_EVENT_OBJ_INIT(obj) \ + Z_POLL_EVENT_OBJ_INIT(obj) \ } /** @@ -1907,7 +1900,7 @@ __syscall void k_queue_cancel_wait(struct k_queue *queue); * @param queue Address of the queue. * @param data Address of the data item. */ -extern void k_queue_append(struct k_queue *queue, void *data); +void k_queue_append(struct k_queue *queue, void *data); /** * @brief Append an element to a queue. @@ -1939,7 +1932,7 @@ __syscall int32_t k_queue_alloc_append(struct k_queue *queue, void *data); * @param queue Address of the queue. * @param data Address of the data item. */ -extern void k_queue_prepend(struct k_queue *queue, void *data); +void k_queue_prepend(struct k_queue *queue, void *data); /** * @brief Prepend an element to a queue. @@ -1972,7 +1965,7 @@ __syscall int32_t k_queue_alloc_prepend(struct k_queue *queue, void *data); * @param prev Address of the previous data item. * @param data Address of the data item. */ -extern void k_queue_insert(struct k_queue *queue, void *prev, void *data); +void k_queue_insert(struct k_queue *queue, void *prev, void *data); /** * @brief Atomically append a list of elements to a queue. @@ -1992,7 +1985,7 @@ extern void k_queue_insert(struct k_queue *queue, void *prev, void *data); * @retval -EINVAL on invalid supplied data * */ -extern int k_queue_append_list(struct k_queue *queue, void *head, void *tail); +int k_queue_append_list(struct k_queue *queue, void *head, void *tail); /** * @brief Atomically add a list of elements to a queue. @@ -2009,7 +2002,7 @@ extern int k_queue_append_list(struct k_queue *queue, void *head, void *tail); * @retval 0 on success * @retval -EINVAL on invalid data */ -extern int k_queue_merge_slist(struct k_queue *queue, sys_slist_t *list); +int k_queue_merge_slist(struct k_queue *queue, sys_slist_t *list); /** * @brief Get an element from a queue. @@ -3106,7 +3099,7 @@ struct k_sem { unsigned int count; unsigned int limit; - _POLL_EVENT; + Z_DECL_POLL_EVENT SYS_PORT_TRACING_TRACKING_FIELD(k_sem) @@ -3120,7 +3113,7 @@ struct k_sem { .wait_q = Z_WAIT_Q_INIT(&obj.wait_q), \ .count = initial_count, \ .limit = count_limit, \ - _POLL_EVENT_OBJ_INIT(obj) \ + Z_POLL_EVENT_OBJ_INIT(obj) \ } /** @@ -3296,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); @@ -3346,7 +3339,7 @@ int k_work_submit_to_queue(struct k_work_q *queue, * * @return as with k_work_submit_to_queue(). */ -extern int k_work_submit(struct k_work *work); +int k_work_submit(struct k_work *work); /** @brief Wait for last-submitted instance to complete. * @@ -3552,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); @@ -3649,7 +3642,7 @@ int k_work_schedule_for_queue(struct k_work_q *queue, * * @return as with k_work_schedule_for_queue(). */ -extern int k_work_schedule(struct k_work_delayable *dwork, +int k_work_schedule(struct k_work_delayable *dwork, k_timeout_t delay); /** @brief Reschedule a work item to a queue after a delay. @@ -3703,7 +3696,7 @@ int k_work_reschedule_for_queue(struct k_work_q *queue, * * @return as with k_work_reschedule_for_queue(). */ -extern int k_work_reschedule(struct k_work_delayable *dwork, +int k_work_reschedule(struct k_work_delayable *dwork, k_timeout_t delay); /** @brief Flush delayable work. @@ -3802,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, @@ -3855,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. */ @@ -4224,7 +4224,7 @@ static inline int k_work_user_submit_to_queue(struct k_work_user_q *work_q, * @param name optional thread name. If not null a copy is made into the * thread's name buffer. */ -extern void k_work_user_queue_start(struct k_work_user_q *work_q, +void k_work_user_queue_start(struct k_work_user_q *work_q, k_thread_stack_t *stack, size_t stack_size, int prio, const char *name); @@ -4293,7 +4293,7 @@ struct k_work_poll { * @param work Address of triggered work item. * @param handler Function to invoke each time work item is processed. */ -extern void k_work_poll_init(struct k_work_poll *work, +void k_work_poll_init(struct k_work_poll *work, k_work_handler_t handler); /** @@ -4330,7 +4330,7 @@ extern void k_work_poll_init(struct k_work_poll *work, * @retval -EINVAL Work item is being processed or has completed its work. * @retval -EADDRINUSE Work item is pending on a different workqueue. */ -extern int k_work_poll_submit_to_queue(struct k_work_q *work_q, +int k_work_poll_submit_to_queue(struct k_work_q *work_q, struct k_work_poll *work, struct k_poll_event *events, int num_events, @@ -4367,7 +4367,7 @@ extern int k_work_poll_submit_to_queue(struct k_work_q *work_q, * @retval -EINVAL Work item is being processed or has completed its work. * @retval -EADDRINUSE Work item is pending on a different workqueue. */ -extern int k_work_poll_submit(struct k_work_poll *work, +int k_work_poll_submit(struct k_work_poll *work, struct k_poll_event *events, int num_events, k_timeout_t timeout); @@ -4386,7 +4386,7 @@ extern int k_work_poll_submit(struct k_work_poll *work, * @retval 0 Work item canceled. * @retval -EINVAL Work item is being processed or has completed its work. */ -extern int k_work_poll_cancel(struct k_work_poll *work); +int k_work_poll_cancel(struct k_work_poll *work); /** @} */ @@ -4419,7 +4419,7 @@ struct k_msgq { /** Number of used messages */ uint32_t used_msgs; - _POLL_EVENT; + Z_DECL_POLL_EVENT /** Message queue */ uint8_t flags; @@ -4445,7 +4445,7 @@ struct k_msgq { .read_ptr = q_buffer, \ .write_ptr = q_buffer, \ .used_msgs = 0, \ - _POLL_EVENT_OBJ_INIT(obj) \ + Z_POLL_EVENT_OBJ_INIT(obj) \ } /** @@ -4692,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 */ @@ -4762,7 +4760,7 @@ struct k_mbox { * * @param mbox Address of the mailbox. */ -extern void k_mbox_init(struct k_mbox *mbox); +void k_mbox_init(struct k_mbox *mbox); /** * @brief Send a mailbox message in a synchronous manner. @@ -4783,7 +4781,7 @@ extern void k_mbox_init(struct k_mbox *mbox); * @retval -ENOMSG Returned without waiting. * @retval -EAGAIN Waiting period timed out. */ -extern int k_mbox_put(struct k_mbox *mbox, struct k_mbox_msg *tx_msg, +int k_mbox_put(struct k_mbox *mbox, struct k_mbox_msg *tx_msg, k_timeout_t timeout); /** @@ -4799,7 +4797,7 @@ extern int k_mbox_put(struct k_mbox *mbox, struct k_mbox_msg *tx_msg, * @param tx_msg Address of the transmit message descriptor. * @param sem Address of a semaphore, or NULL if none is needed. */ -extern void k_mbox_async_put(struct k_mbox *mbox, struct k_mbox_msg *tx_msg, +void k_mbox_async_put(struct k_mbox *mbox, struct k_mbox_msg *tx_msg, struct k_sem *sem); /** @@ -4819,7 +4817,7 @@ extern void k_mbox_async_put(struct k_mbox *mbox, struct k_mbox_msg *tx_msg, * @retval -ENOMSG Returned without waiting. * @retval -EAGAIN Waiting period timed out. */ -extern int k_mbox_get(struct k_mbox *mbox, struct k_mbox_msg *rx_msg, +int k_mbox_get(struct k_mbox *mbox, struct k_mbox_msg *rx_msg, void *buffer, k_timeout_t timeout); /** @@ -4835,7 +4833,7 @@ extern int k_mbox_get(struct k_mbox *mbox, struct k_mbox_msg *rx_msg, * @param buffer Address of the buffer to receive data, or NULL to discard * the data. */ -extern void k_mbox_data_get(struct k_mbox_msg *rx_msg, void *buffer); +void k_mbox_data_get(struct k_mbox_msg *rx_msg, void *buffer); /** @} */ @@ -4859,7 +4857,7 @@ struct k_pipe { _wait_q_t writers; /**< Writer wait queue */ } wait_q; /** Wait queue */ - _POLL_EVENT; + Z_DECL_POLL_EVENT uint8_t flags; /**< Flags */ @@ -4887,7 +4885,7 @@ struct k_pipe { .readers = Z_WAIT_Q_INIT(&obj.wait_q.readers), \ .writers = Z_WAIT_Q_INIT(&obj.wait_q.writers) \ }, \ - _POLL_EVENT_OBJ_INIT(obj) \ + Z_POLL_EVENT_OBJ_INIT(obj) \ .flags = 0, \ } @@ -4975,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); @@ -5171,7 +5169,7 @@ struct k_mem_slab { * @retval -EINVAL invalid data supplied * */ -extern int k_mem_slab_init(struct k_mem_slab *slab, void *buffer, +int k_mem_slab_init(struct k_mem_slab *slab, void *buffer, size_t block_size, uint32_t num_blocks); /** @@ -5196,7 +5194,7 @@ extern int k_mem_slab_init(struct k_mem_slab *slab, void *buffer, * @retval -EAGAIN Waiting period timed out. * @retval -EINVAL Invalid data supplied */ -extern int k_mem_slab_alloc(struct k_mem_slab *slab, void **mem, +int k_mem_slab_alloc(struct k_mem_slab *slab, void **mem, k_timeout_t timeout); /** @@ -5208,7 +5206,7 @@ extern int k_mem_slab_alloc(struct k_mem_slab *slab, void **mem, * @param slab Address of the memory slab. * @param mem Pointer to the memory block (as returned by k_mem_slab_alloc()). */ -extern void k_mem_slab_free(struct k_mem_slab *slab, void *mem); +void k_mem_slab_free(struct k_mem_slab *slab, void *mem); /** * @brief Get the number of used blocks in a memory slab. @@ -5315,7 +5313,8 @@ struct k_heap { * @param mem Pointer to memory. * @param bytes Size of memory region, in bytes */ -void k_heap_init(struct k_heap *h, void *mem, size_t bytes); +void k_heap_init(struct k_heap *h, void *mem, + size_t bytes) __attribute_nonnull(1); /** @brief Allocate aligned memory from a k_heap * @@ -5337,7 +5336,7 @@ void k_heap_init(struct k_heap *h, void *mem, size_t bytes); * @return Pointer to memory the caller can now use */ void *k_heap_aligned_alloc(struct k_heap *h, size_t align, size_t bytes, - k_timeout_t timeout); + k_timeout_t timeout) __attribute_nonnull(1); /** * @brief Allocate memory from a k_heap @@ -5361,7 +5360,7 @@ void *k_heap_aligned_alloc(struct k_heap *h, size_t align, size_t bytes, * @return A pointer to valid heap memory, or NULL */ void *k_heap_alloc(struct k_heap *h, size_t bytes, - k_timeout_t timeout); + k_timeout_t timeout) __attribute_nonnull(1); /** * @brief Free memory allocated by k_heap_alloc() @@ -5373,7 +5372,7 @@ void *k_heap_alloc(struct k_heap *h, size_t bytes, * @param h Heap to which to return the memory * @param mem A valid memory block, or NULL */ -void k_heap_free(struct k_heap *h, void *mem); +void k_heap_free(struct k_heap *h, void *mem) __attribute_nonnull(1); /* Hand-calculated minimum heap sizes needed to return a successful * 1-byte allocation. See details in lib/os/heap.[ch] @@ -5470,7 +5469,7 @@ void k_heap_free(struct k_heap *h, void *mem); * * @return Address of the allocated memory if successful; otherwise NULL. */ -extern void *k_aligned_alloc(size_t align, size_t size); +void *k_aligned_alloc(size_t align, size_t size); /** * @brief Allocate memory from the heap. @@ -5483,7 +5482,7 @@ extern void *k_aligned_alloc(size_t align, size_t size); * * @return Address of the allocated memory if successful; otherwise NULL. */ -extern void *k_malloc(size_t size); +void *k_malloc(size_t size); /** * @brief Free memory allocated from heap. @@ -5495,7 +5494,7 @@ extern void *k_malloc(size_t size); * * @param ptr Pointer to previously allocated memory. */ -extern void k_free(void *ptr); +void k_free(void *ptr); /** * @brief Allocate memory from heap, array style @@ -5508,7 +5507,7 @@ extern void k_free(void *ptr); * * @return Address of the allocated memory if successful; otherwise NULL. */ -extern void *k_calloc(size_t nmemb, size_t size); +void *k_calloc(size_t nmemb, size_t size); /** @} */ @@ -5720,7 +5719,7 @@ struct k_poll_event { * @param obj Kernel object or poll signal. */ -extern void k_poll_event_init(struct k_poll_event *event, uint32_t type, +void k_poll_event_init(struct k_poll_event *event, uint32_t type, int mode, void *obj); /** @@ -5943,7 +5942,7 @@ static inline void k_cpu_atomic_idle(unsigned int key) /** * @internal */ -extern void z_init_static_threads(void); +void z_init_static_threads(void); #else /** * @internal @@ -5954,7 +5953,7 @@ extern void z_init_static_threads(void); /** * @internal */ -extern void z_timer_expiration_handler(struct _timeout *t); +void z_timer_expiration_handler(struct _timeout *t); /** * INTERNAL_HIDDEN @endcond */ @@ -5970,6 +5969,12 @@ extern 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. * @@ -6032,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 * @@ -6059,7 +6068,7 @@ int k_thread_runtime_stats_all_get(k_thread_runtime_stats_t *stats); * @param thread ID of thread * @return -EINVAL if invalid thread ID, otherwise 0 */ -extern int k_thread_runtime_stats_enable(k_tid_t thread); +int k_thread_runtime_stats_enable(k_tid_t thread); /** * @brief Disable gathering of runtime statistics for specified thread @@ -6070,7 +6079,7 @@ extern int k_thread_runtime_stats_enable(k_tid_t thread); * @param thread ID of thread * @return -EINVAL if invalid thread ID, otherwise 0 */ -extern int k_thread_runtime_stats_disable(k_tid_t thread); +int k_thread_runtime_stats_disable(k_tid_t thread); /** * @brief Enable gathering of system runtime statistics @@ -6079,7 +6088,7 @@ extern int k_thread_runtime_stats_disable(k_tid_t thread); * it does not affect the gathering of similar statistics for individual * threads. */ -extern void k_sys_runtime_stats_enable(void); +void k_sys_runtime_stats_enable(void); /** * @brief Disable gathering of system runtime statistics @@ -6088,7 +6097,7 @@ extern void k_sys_runtime_stats_enable(void); * it does not affect the gathering of similar statistics for individual * threads. */ -extern void k_sys_runtime_stats_disable(void); +void k_sys_runtime_stats_disable(void); #ifdef __cplusplus } diff --git a/include/zephyr/kernel/internal/mm.h b/include/zephyr/kernel/internal/mm.h new file mode 100644 index 000000000000000..b6bcd1aa3b1dc2a --- /dev/null +++ b/include/zephyr/kernel/internal/mm.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_KERNEL_INTERNAL_MM_H +#define ZEPHYR_INCLUDE_KERNEL_INTERNAL_MM_H + +#include +#include + +/** + * @defgroup kernel_mm_internal_apis Kernel Memory Management Internal APIs + * @ingroup internal_api + * @{ + */ + +/* + * This is the offset to subtract from a virtual address mapped in the + * kernel's permanent mapping of RAM, to obtain its physical address. + * + * virt_addr = phys_addr + Z_MEM_VM_OFFSET + * + * This only works for virtual addresses within the interval + * [CONFIG_KERNEL_VM_BASE, CONFIG_KERNEL_VM_BASE + (CONFIG_SRAM_SIZE * 1024)). + * + * These macros are intended for assembly, linker code, and static initializers. + * Use with care. + * + * Note that when demand paging is active, these will only work with page + * frames that are pinned to their virtual mapping at boot. + * + * TODO: This will likely need to move to an arch API or need additional + * constraints defined. + */ +#ifdef CONFIG_MMU +#define Z_MEM_VM_OFFSET ((CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_OFFSET) - \ + (CONFIG_SRAM_BASE_ADDRESS + CONFIG_SRAM_OFFSET)) +#else +#define Z_MEM_VM_OFFSET 0 +#endif + +#define Z_MEM_PHYS_ADDR(virt) ((virt) - Z_MEM_VM_OFFSET) +#define Z_MEM_VIRT_ADDR(phys) ((phys) + Z_MEM_VM_OFFSET) + +#if Z_MEM_VM_OFFSET != 0 +#define Z_VM_KERNEL 1 +#ifdef CONFIG_XIP +#error "XIP and a virtual memory kernel are not allowed" +#endif +#endif + +#ifndef _ASMLANGUAGE +#include +#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) +{ + uintptr_t addr = (uintptr_t)virt; + +#if defined(CONFIG_KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK) + __ASSERT(sys_mm_is_virt_addr_in_range(virt), + "address %p not in permanent mappings", virt); +#elif defined(CONFIG_MMU) + __ASSERT( +#if CONFIG_KERNEL_VM_BASE != 0 + (addr >= CONFIG_KERNEL_VM_BASE) && +#endif +#if (CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_SIZE) != 0 + (addr < (CONFIG_KERNEL_VM_BASE + + (CONFIG_KERNEL_VM_SIZE))), +#else + false, +#endif + "address %p not in permanent mappings", virt); +#else + /* Should be identity-mapped */ + __ASSERT( +#if CONFIG_SRAM_BASE_ADDRESS != 0 + (addr >= CONFIG_SRAM_BASE_ADDRESS) && +#endif +#if (CONFIG_SRAM_BASE_ADDRESS + (CONFIG_SRAM_SIZE * 1024UL)) != 0 + (addr < (CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024UL))), +#else + false, +#endif + "physical address 0x%lx not in RAM", + (unsigned long)addr); +#endif /* CONFIG_MMU */ + + /* TODO add assertion that this page is pinned to boot mapping, + * the above checks won't be sufficient with demand paging + */ + + return Z_MEM_PHYS_ADDR(addr); +} + +/* Just like Z_MEM_VIRT_ADDR() but with type safety and assertions */ +static inline void *z_mem_virt_addr(uintptr_t phys) +{ +#if defined(CONFIG_KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK) + __ASSERT(sys_mm_is_phys_addr_in_range(phys), + "physical address 0x%lx not in RAM", (unsigned long)phys); +#else + __ASSERT( +#if CONFIG_SRAM_BASE_ADDRESS != 0 + (phys >= CONFIG_SRAM_BASE_ADDRESS) && +#endif +#if (CONFIG_SRAM_BASE_ADDRESS + (CONFIG_SRAM_SIZE * 1024UL)) != 0 + (phys < (CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024UL))), +#else + false, +#endif + "physical address 0x%lx not in RAM", (unsigned long)phys); +#endif + + /* TODO add assertion that this page frame is pinned to boot mapping, + * the above check won't be sufficient with demand paging + */ + + return (void *)Z_MEM_VIRT_ADDR(phys); +} + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Map a physical memory region into the kernel's virtual address space + * + * This function is intended for mapping memory-mapped I/O regions into + * the virtual address space. Given a physical address and a size, return a + * linear address representing the base of where the physical region is mapped + * in the virtual address space for the Zephyr kernel. + * + * This function alters the active page tables in the area reserved + * for the kernel. This function will choose the virtual address + * and return it to the caller. + * + * Portable code should never assume that phys_addr and linear_addr will + * be equal. + * + * Caching and access properties are controlled by the 'flags' parameter. + * Unused bits in 'flags' are reserved for future expansion. + * A caching mode must be selected. By default, the region is read-only + * with user access and code execution forbidden. This policy is changed + * by passing K_MEM_CACHE_* and K_MEM_PERM_* macros into the 'flags' parameter. + * + * If there is insufficient virtual address space for the mapping this will + * generate a kernel panic. + * + * This API is only available if CONFIG_MMU is enabled. + * + * It is highly discouraged to use this function to map system RAM page + * frames. It may conflict with anonymous memory mappings and demand paging + * and produce undefined behavior. Do not use this for RAM unless you know + * exactly what you are doing. If you need a chunk of memory, use k_mem_map(). + * If you need a contiguous buffer of physical memory, statically declare it + * and pin it at build time, it will be mapped when the system boots. + * + * This API is part of infrastructure still under development and may + * change. + * + * @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); + +/** + * Unmap a virtual memory region from kernel's virtual address space. + * + * This function is intended to be used by drivers and early boot routines + * where temporary memory mappings need to be made. This allows these + * memory mappings to be discarded once they are no longer needed. + * + * This function alters the active page tables in the area reserved + * for the kernel. + * + * This will align the input parameters to page boundaries so that + * this can be used with the virtual address as returned by + * z_phys_map(). + * + * This API is only available if CONFIG_MMU is enabled. + * + * It is highly discouraged to use this function to unmap memory mappings. + * It may conflict with anonymous memory mappings and demand paging and + * produce undefined behavior. Do not use this unless you know exactly + * what you are doing. + * + * This API is part of infrastructure still under development and may + * change. + * + * @param virt Starting address of the virtual address region to be unmapped. + * @param size Size of the virtual address region + */ +void z_phys_unmap(uint8_t *virt, size_t size); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* !_ASMLANGUAGE */ +#endif /* ZEPHYR_INCLUDE_KERNEL_INTERNAL_MM_H */ diff --git a/include/zephyr/kernel/internal/smp.h b/include/zephyr/kernel/internal/smp.h index d4f70d3c07b6dca..e2b3ae15aec2a32 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 new file mode 100644 index 000000000000000..715bc94021f9d36 --- /dev/null +++ b/include/zephyr/kernel/mm.h @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_KERNEL_MM_H +#define ZEPHYR_INCLUDE_KERNEL_MM_H + +#include +#include +#if defined(CONFIG_ARM_MMU) && defined(CONFIG_ARM64) +#include +#endif + +#include + +/** + * @brief Kernel Memory Management + * @defgroup kernel_memory_management Kernel Memory Management + * @ingroup kernel_apis + * @{ + */ + +/** + * @name Caching mode definitions. + * + * These are mutually exclusive. + * + * @{ + */ + +/** No caching. Most drivers want this. */ +#define K_MEM_CACHE_NONE 2 + +/** Write-through caching. Used by certain drivers. */ +#define K_MEM_CACHE_WT 1 + +/** Full write-back caching. Any RAM mapped wants this. */ +#define K_MEM_CACHE_WB 0 + +/* + * ARM64 Specific flags are defined in arch/arm64/arm_mem.h, + * pay attention to be not conflicted when updating these flags. + */ + +/** Reserved bits for cache modes in k_map() flags argument */ +#define K_MEM_CACHE_MASK (BIT(3) - 1) + +/** @} */ + +/** + * @name Region permission attributes. + * + * Default is read-only, no user, no exec + * + * @{ + */ + +/** Region will have read/write access (and not read-only) */ +#define K_MEM_PERM_RW BIT(3) + +/** Region will be executable (normally forbidden) */ +#define K_MEM_PERM_EXEC BIT(4) + +/** Region will be accessible to user mode (normally supervisor-only) */ +#define K_MEM_PERM_USER BIT(5) + +/** @} */ + +/** + * @name Region mapping behaviour attributes + * + * @{ + */ + +/** Region will be mapped to 1:1 virtual and physical address */ +#define K_MEM_DIRECT_MAP BIT(6) + +/** @} */ + +#ifndef _ASMLANGUAGE +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name k_mem_map() control flags + * + * @{ + */ + +/** + * @brief The mapped region is not guaranteed to be zeroed. + * + * This may improve performance. The associated page frames may contain + * indeterminate data, zeroes, or even sensitive information. + * + * This may not be used with K_MEM_PERM_USER as there are no circumstances + * where this is safe. + */ +#define K_MEM_MAP_UNINIT BIT(16) + +/** + * Region will be pinned in memory and never paged + * + * Such memory is guaranteed to never produce a page fault due to page-outs + * or copy-on-write once the mapping call has returned. Physical page frames + * will be pre-fetched as necessary and pinned. + */ +#define K_MEM_MAP_LOCK BIT(17) + +/** @} */ + +/** + * Return the amount of free memory available + * + * The returned value will reflect how many free RAM page frames are available. + * If demand paging is enabled, it may still be possible to allocate more. + * + * The information reported by this function may go stale immediately if + * concurrent memory mappings or page-ins take place. + * + * @return Free physical RAM, in bytes + */ +size_t k_mem_free_get(void); + +/** + * Map anonymous memory into Zephyr's address space + * + * This function effectively increases the data space available to Zephyr. + * The kernel will choose a base virtual address and return it to the caller. + * The memory will have access permissions for all contexts set per the + * provided flags argument. + * + * If user thread access control needs to be managed in any way, do not enable + * K_MEM_PERM_USER flags here; instead manage the region's permissions + * with memory domain APIs after the mapping has been established. Setting + * K_MEM_PERM_USER here will allow all user threads to access this memory + * which is usually undesirable. + * + * Unless K_MEM_MAP_UNINIT is used, the returned memory will be zeroed. + * + * The mapped region is not guaranteed to be physically contiguous in memory. + * Physically contiguous buffers should be allocated statically and pinned + * at build time. + * + * Pages mapped in this way have write-back cache settings. + * + * The returned virtual memory pointer will be page-aligned. The size + * parameter, and any base address for re-mapping purposes must be page- + * aligned. + * + * Note that the allocation includes two guard pages immediately before + * and after the requested region. The total size of the allocation will be + * the requested size plus the size of these two guard pages. + * + * Many K_MEM_MAP_* flags have been implemented to alter the behavior of this + * function, with details in the documentation for these flags. + * + * @param size Size of the memory mapping. This must be page-aligned. + * @param flags K_MEM_PERM_*, K_MEM_MAP_* control flags. + * @return The mapped memory location, or NULL if insufficient virtual address + * space, insufficient physical memory to establish the mapping, + * or insufficient memory for paging structures. + */ +void *k_mem_map(size_t size, uint32_t flags); + +/** + * Un-map mapped memory + * + * This removes a memory mapping for the provided page-aligned region. + * Associated page frames will be free and the kernel may re-use the associated + * virtual address region. Any paged out data pages may be discarded. + * + * Calling this function on a region which was not mapped to begin with is + * undefined behavior. + * + * @param addr Page-aligned memory region base virtual address + * @param size Page-aligned memory region size + */ +void k_mem_unmap(void *addr, size_t size); + +/** + * Given an arbitrary region, provide a aligned region that covers it + * + * The returned region will have both its base address and size aligned + * to the provided alignment value. + * + * @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, + uintptr_t addr, size_t size, size_t align); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* !_ASMLANGUAGE */ +#endif /* ZEPHYR_INCLUDE_KERNEL_MM_H */ diff --git a/include/zephyr/kernel/mm/demand_paging.h b/include/zephyr/kernel/mm/demand_paging.h new file mode 100644 index 000000000000000..10412d3a7668a98 --- /dev/null +++ b/include/zephyr/kernel/mm/demand_paging.h @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_KERNEL_MM_DEMAND_PAGING_H +#define ZEPHYR_INCLUDE_KERNEL_MM_DEMAND_PAGING_H + +#include + +#include +#include + +/** + * @defgroup demand_paging Demand Paging + * @ingroup kernel_memory_management + */ + +/** + * @defgroup mem-demand-paging Demand Paging APIs + * @ingroup demand_paging + * @{ + */ + +#ifndef _ASMLANGUAGE +#include +#include +#include +#include + +/** + * Paging Statistics. + */ +struct k_mem_paging_stats_t { +#if defined(CONFIG_DEMAND_PAGING_STATS) || defined(__DOXYGEN__) + struct { + /** Number of page faults */ + unsigned long cnt; + + /** Number of page faults with IRQ locked */ + unsigned long irq_locked; + + /** Number of page faults with IRQ unlocked */ + unsigned long irq_unlocked; + +#if !defined(CONFIG_DEMAND_PAGING_ALLOW_IRQ) || defined(__DOXYGEN__) + /** Number of page faults while in ISR */ + unsigned long in_isr; +#endif + } pagefaults; + + struct { + /** Number of clean pages selected for eviction */ + unsigned long clean; + + /** Number of dirty pages selected for eviction */ + unsigned long dirty; + } eviction; +#endif /* CONFIG_DEMAND_PAGING_STATS */ +}; + +/** + * Paging Statistics Histograms. + */ +struct k_mem_paging_histogram_t { +#if defined(CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM) || defined(__DOXYGEN__) + /* Counts for each bin in timing histogram */ + unsigned long counts[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; + + /* Bounds for the bins in timing histogram, + * excluding the first and last (hence, NUM_SLOTS - 1). + */ + unsigned long bounds[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; +#endif /* CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Evict a page-aligned virtual memory region to the backing store + * + * Useful if it is known that a memory region will not be used for some time. + * All the data pages within the specified region will be evicted to the + * backing store if they weren't already, with their associated page frames + * marked as available for mappings or page-ins. + * + * None of the associated page frames mapped to the provided region should + * be pinned. + * + * Note that there are no guarantees how long these pages will be evicted, + * they could take page faults immediately. + * + * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be + * called by ISRs as the backing store may be in-use. + * + * @param addr Base page-aligned virtual address + * @param size Page-aligned data region size + * @retval 0 Success + * @retval -ENOMEM Insufficient space in backing store to satisfy request. + * The region may be partially paged out. + */ +int k_mem_page_out(void *addr, size_t size); + +/** + * Load a virtual data region into memory + * + * After the function completes, all the page frames associated with this + * function will be paged in. However, they are not guaranteed to stay there. + * This is useful if the region is known to be used soon. + * + * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be + * called by ISRs as the backing store may be in-use. + * + * @param addr Base page-aligned virtual address + * @param size Page-aligned data region size + */ +void k_mem_page_in(void *addr, size_t size); + +/** + * Pin an aligned virtual data region, paging in as necessary + * + * After the function completes, all the page frames associated with this + * region will be resident in memory and pinned such that they stay that way. + * This is a stronger version of z_mem_page_in(). + * + * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be + * called by ISRs as the backing store may be in-use. + * + * @param addr Base page-aligned virtual address + * @param size Page-aligned data region size + */ +void k_mem_pin(void *addr, size_t size); + +/** + * Un-pin an aligned virtual data region + * + * After the function completes, all the page frames associated with this + * region will be no longer marked as pinned. This does not evict the region, + * follow this with z_mem_page_out() if you need that. + * + * @param addr Base page-aligned virtual address + * @param size Page-aligned data region size + */ +void k_mem_unpin(void *addr, size_t size); + +/** + * Get the paging statistics since system startup + * + * This populates the paging statistics struct being passed in + * as argument. + * + * @param[in,out] stats Paging statistics struct to be filled. + */ +__syscall void k_mem_paging_stats_get(struct k_mem_paging_stats_t *stats); + +struct k_thread; +/** + * Get the paging statistics since system startup for a thread + * + * This populates the paging statistics struct being passed in + * as argument for a particular thread. + * + * @param[in] thread Thread + * @param[in,out] stats Paging statistics struct to be filled. + */ +__syscall +void k_mem_paging_thread_stats_get(struct k_thread *thread, + struct k_mem_paging_stats_t *stats); + +/** + * Get the eviction timing histogram + * + * This populates the timing histogram struct being passed in + * as argument. + * + * @param[in,out] hist Timing histogram struct to be filled. + */ +__syscall void k_mem_paging_histogram_eviction_get( + struct k_mem_paging_histogram_t *hist); + +/** + * Get the backing store page-in timing histogram + * + * This populates the timing histogram struct being passed in + * as argument. + * + * @param[in,out] hist Timing histogram struct to be filled. + */ +__syscall void k_mem_paging_histogram_backing_store_page_in_get( + struct k_mem_paging_histogram_t *hist); + +/** + * Get the backing store page-out timing histogram + * + * This populates the timing histogram struct being passed in + * as argument. + * + * @param[in,out] hist Timing histogram struct to be filled. + */ +__syscall void k_mem_paging_histogram_backing_store_page_out_get( + struct k_mem_paging_histogram_t *hist); + +#include + +/** @} */ + +/** + * Eviction algorithm APIs + * + * @defgroup mem-demand-paging-eviction Eviction Algorithm APIs + * @ingroup demand_paging + * @{ + */ + +/** + * Select a page frame for eviction + * + * The kernel will invoke this to choose a page frame to evict if there + * are no free page frames. + * + * This function will never be called before the initial + * k_mem_paging_eviction_init(). + * + * This function is invoked with interrupts locked. + * + * @param [out] dirty Whether the page to evict is dirty + * @return The page frame to evict + */ +struct z_page_frame *k_mem_paging_eviction_select(bool *dirty); + +/** + * Initialization function + * + * Called at POST_KERNEL to perform any necessary initialization tasks for the + * eviction algorithm. k_mem_paging_eviction_select() is guaranteed to never be + * called until this has returned, and this will only be called once. + */ +void k_mem_paging_eviction_init(void); + +/** @} */ + +/** + * Backing store APIs + * + * @defgroup mem-demand-paging-backing-store Backing Store APIs + * @ingroup demand_paging + * @{ + */ + +/** + * Reserve or fetch a storage location for a data page loaded into a page frame + * + * The returned location token must be unique to the mapped virtual address. + * This location will be used in the backing store to page out data page + * contents for later retrieval. The location value must be page-aligned. + * + * This function may be called multiple times on the same data page. If its + * page frame has its Z_PAGE_FRAME_BACKED bit set, it is expected to return + * the previous backing store location for the data page containing a cached + * clean copy. This clean copy may be updated on page-out, or used to + * discard clean pages without needing to write out their contents. + * + * If the backing store is full, some other backing store location which caches + * a loaded data page may be selected, in which case its associated page frame + * will have the Z_PAGE_FRAME_BACKED bit cleared (as it is no longer cached). + * + * pf->addr will indicate the virtual address the page is currently mapped to. + * Large, sparse backing stores which can contain the entire address space + * may simply generate location tokens purely as a function of pf->addr with no + * other management necessary. + * + * This function distinguishes whether it was called on behalf of a page + * fault. A free backing store location must always be reserved in order for + * page faults to succeed. If the page_fault parameter is not set, this + * function should return -ENOMEM even if one location is available. + * + * This function is invoked with interrupts locked. + * + * @param pf Virtual address to obtain a storage location + * @param [out] location storage location token + * @param page_fault Whether this request was for a page fault + * @return 0 Success + * @return -ENOMEM Backing store is full + */ +int k_mem_paging_backing_store_location_get(struct z_page_frame *pf, + uintptr_t *location, + bool page_fault); + +/** + * Free a backing store location + * + * Any stored data may be discarded, and the location token associated with + * this address may be re-used for some other data page. + * + * This function is invoked with interrupts locked. + * + * @param location Location token to free + */ +void k_mem_paging_backing_store_location_free(uintptr_t location); + +/** + * Copy a data page from Z_SCRATCH_PAGE to the specified location + * + * Immediately before this is called, Z_SCRATCH_PAGE will be mapped read-write + * to the intended source page frame for the calling context. + * + * Calls to this and k_mem_paging_backing_store_page_in() will always be + * serialized, but interrupts may be enabled. + * + * @param location Location token for the data page, for later retrieval + */ +void k_mem_paging_backing_store_page_out(uintptr_t location); + +/** + * Copy a data page from the provided location to Z_SCRATCH_PAGE. + * + * Immediately before this is called, Z_SCRATCH_PAGE will be mapped read-write + * to the intended destination page frame for the calling context. + * + * Calls to this and k_mem_paging_backing_store_page_out() will always be + * serialized, but interrupts may be enabled. + * + * @param location Location token for the data page + */ +void k_mem_paging_backing_store_page_in(uintptr_t location); + +/** + * Update internal accounting after a page-in + * + * This is invoked after k_mem_paging_backing_store_page_in() and interrupts + * have been* re-locked, making it safe to access the z_page_frame data. + * The location value will be the same passed to + * k_mem_paging_backing_store_page_in(). + * + * The primary use-case for this is to update custom fields for the backing + * store in the page frame, to reflect where the data should be evicted to + * if it is paged out again. This may be a no-op in some implementations. + * + * If the backing store caches paged-in data pages, this is the appropriate + * time to set the Z_PAGE_FRAME_BACKED bit. The kernel only skips paging + * out clean data pages if they are noted as clean in the page tables and the + * Z_PAGE_FRAME_BACKED bit is set in their associated page frame. + * + * @param pf Page frame that was loaded in + * @param location Location of where the loaded data page was retrieved + */ +void k_mem_paging_backing_store_page_finalize(struct z_page_frame *pf, + uintptr_t location); + +/** + * Backing store initialization function. + * + * The implementation may expect to receive page in/out calls as soon as this + * returns, but not before that. Called at POST_KERNEL. + * + * This function is expected to do two things: + * - Initialize any internal data structures and accounting for the backing + * store. + * - If the backing store already contains all or some loaded kernel data pages + * at boot time, Z_PAGE_FRAME_BACKED should be appropriately set for their + * associated page frames, and any internal accounting set up appropriately. + */ +void k_mem_paging_backing_store_init(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !_ASMLANGUAGE */ +#endif /* ZEPHYR_INCLUDE_KERNEL_MM_DEMAND_PAGING_H */ diff --git a/include/zephyr/kernel/smp.h b/include/zephyr/kernel/smp.h new file mode 100644 index 000000000000000..883f4820a749f1f --- /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 7a231196cb49c9c..91cf710e870c661 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 @@ -351,6 +351,11 @@ struct k_thread { struct k_obj_core obj_core; #endif +#ifdef CONFIG_SMP + /** threads waiting in k_thread_suspend() */ + _wait_q_t halt_queue; +#endif + /** arch-specifics: must always be at the end */ struct _thread_arch arch; }; diff --git a/include/zephyr/kernel_structs.h b/include/zephyr/kernel_structs.h index d066db620cef222..986165006eb4be4 100644 --- a/include/zephyr/kernel_structs.h +++ b/include/zephyr/kernel_structs.h @@ -60,9 +60,12 @@ extern "C" { /* Thread is suspended */ #define _THREAD_SUSPENDED (BIT(4)) -/* Thread is being aborted */ +/* Thread is in the process of aborting */ #define _THREAD_ABORTING (BIT(5)) +/* Thread is in the process of suspending */ +#define _THREAD_SUSPENDING (BIT(6)) + /* Thread is present in the ready queue */ #define _THREAD_QUEUED (BIT(7)) @@ -232,7 +235,7 @@ typedef struct { struct _priq_rb waitq; } _wait_q_t; -extern bool z_priq_rb_lessthan(struct rbnode *a, struct rbnode *b); +bool z_priq_rb_lessthan(struct rbnode *a, struct rbnode *b); #define Z_WAIT_Q_INIT(wait_q) { { { .lessthan_fn = z_priq_rb_lessthan } } } diff --git a/include/zephyr/kernel_version.h b/include/zephyr/kernel_version.h index 6d3109fed309772..7a21b4377684838 100644 --- a/include/zephyr/kernel_version.h +++ b/include/zephyr/kernel_version.h @@ -44,7 +44,7 @@ extern "C" { * * @return kernel version */ -extern uint32_t sys_kernel_version_get(void); +uint32_t sys_kernel_version_get(void); /** * @} diff --git a/include/zephyr/linker/common-ram.ld b/include/zephyr/linker/common-ram.ld index d2d1a5ca7f1be71..df70b13ca73dd3b 100644 --- a/include/zephyr/linker/common-ram.ld +++ b/include/zephyr/linker/common-ram.ld @@ -12,10 +12,6 @@ #endif #endif /* NETWORKING */ -#if defined(CONFIG_BT_MESH) - ITERABLE_SECTION_RAM(bt_mesh_ext_adv, 4) -#endif - #if defined(CONFIG_GEN_SW_ISR_TABLE) && defined(CONFIG_DYNAMIC_INTERRUPTS) SECTION_DATA_PROLOGUE(sw_isr_table,,) { @@ -137,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-kernel-devices.ld b/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld index 3d074ac1b386413..dfa19d13492eccf 100644 --- a/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld +++ b/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld @@ -22,6 +22,26 @@ ITERABLE_SECTION_ROM_NUMERIC(device, 4) +#if defined(CONFIG_GEN_SW_ISR_TABLE) && defined(CONFIG_SHARED_INTERRUPTS) + /* since z_shared_isr() is not referenced anywhere when + * zephyr_pre0.elf is built, the linker will end up dropping it. + * Later on, during the second linking stage (when zephyr.elf is + * built), the symbol will be added to the text section since it's + * now being referenced (thanks to isr_tables.c). This is very + * problematic because adding the z_shared_isr symbol between + * the linking stages will end up shifting the addresses of the + * functions, which, in turn, will end up messing the ISR table + * (as the entries from _sw_isr_table will end up pointing to + * old addresses of the registered ISRs). To prevent this from + * happening, instruct the linker to avoid dropping z_shared_isr + * if it's not being referenced anywhere. + */ + SECTION_PROLOGUE(.text.z_shared_isr,,) + { + KEEP(*(.text.z_shared_isr)) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) +#endif + #if defined(CONFIG_GEN_SW_ISR_TABLE) && !defined(CONFIG_DYNAMIC_INTERRUPTS) SECTION_PROLOGUE(sw_isr_table,,) { @@ -55,7 +75,7 @@ /* Build-time assignment of permissions to kernel objects to * threads declared with K_THREAD_DEFINE() */ - ITERABLE_SECTION_ROM(z_object_assignment, 4) + ITERABLE_SECTION_ROM(k_object_assignment, 4) #endif SECTION_DATA_PROLOGUE(app_shmem_regions,,) diff --git a/include/zephyr/linker/common-rom/common-rom-logging.ld b/include/zephyr/linker/common-rom/common-rom-logging.ld index f39fed01b21f517..9bb3e34626c9a27 100644 --- a/include/zephyr/linker/common-rom/common-rom-logging.ld +++ b/include/zephyr/linker/common-rom/common-rom-logging.ld @@ -2,7 +2,14 @@ #include +#if defined(CONFIG_LOG_FMT_SECTION_STRIP) && defined(DEVNULL_REGION) + SECTION_PROLOGUE(log_strings,(COPY),SUBALIGN(4)) + { + Z_LINK_ITERABLE(log_strings); + } GROUP_ROM_LINK_IN(DEVNULL_REGION, DEVNULL_REGION) +#else ITERABLE_SECTION_ROM(log_strings, 4) +#endif ITERABLE_SECTION_ROM(log_const, 4) diff --git a/include/zephyr/linker/common-rom/common-rom-misc.ld b/include/zephyr/linker/common-rom/common-rom-misc.ld index 5da776a6aaf15a5..189a9e31885af08 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 */ @@ -59,3 +60,11 @@ ITERABLE_SECTION_ROM(shell_dynamic_subcmds, 4) ITERABLE_SECTION_ROM(cfb_font, 4) + +#if defined(CONFIG_GNSS) + ITERABLE_SECTION_ROM(gnss_data_callback, 4) +#endif + +#if defined(CONFIG_GNSS_SATELLITES) + ITERABLE_SECTION_ROM(gnss_satellites_callback, 4) +#endif diff --git a/include/zephyr/linker/common-rom/common-rom-net.ld b/include/zephyr/linker/common-rom/common-rom-net.ld index e535f5f1fd01880..e73addfd16655ba 100644 --- a/include/zephyr/linker/common-rom/common-rom-net.ld +++ b/include/zephyr/linker/common-rom/common-rom-net.ld @@ -17,3 +17,15 @@ #if defined(CONFIG_HTTP_SERVER) ITERABLE_SECTION_ROM(http_service_desc, 4) #endif + +#if defined(CONFIG_COAP_SERVER) + 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/kobject-text.ld b/include/zephyr/linker/kobject-text.ld index 47a989f4c2319e7..b1c2b69e6df9b8a 100644 --- a/include/zephyr/linker/kobject-text.ld +++ b/include/zephyr/linker/kobject-text.ld @@ -18,8 +18,8 @@ PROVIDE(z_object_gperf_find = .); PROVIDE(z_object_gperf_wordlist_foreach = .); #else - PROVIDE(z_object_find = .); - PROVIDE(z_object_wordlist_foreach = .); + PROVIDE(k_object_find = .); + PROVIDE(k_object_wordlist_foreach = .); #endif #endif diff --git a/include/zephyr/linker/linker-devnull.h b/include/zephyr/linker/linker-devnull.h new file mode 100644 index 000000000000000..d5455dd6da2344f --- /dev/null +++ b/include/zephyr/linker/linker-devnull.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * DESCRIPTION + * Platform independent set of macros for creating a memory segment for + * aggregating data that shall be kept in the elf file but not in the binary. + */ + +#ifndef ZEPHYR_INCLUDE_LINKER_LINKER_DEVNULL_H_ + +#if defined(CONFIG_LINKER_DEVNULL_MEMORY) + +#if defined(CONFIG_XIP) +#if (!defined(ROM_ADDR) && !defined(ROM_BASE)) || !defined(ROM_SIZE) +#error "ROM_SIZE, ROM_ADDR or ROM_BASE not defined" +#endif +#endif /* CONFIG_XIP */ + +#if (!defined(RAM_ADDR) && !defined(RAM_BASE)) || !defined(RAM_SIZE) +#error "RAM_SIZE, RAM_ADDR or RAM_BASE not defined" +#endif + +#if defined(CONFIG_XIP) && !defined(ROM_ADDR) +#define ROM_ADDR ROM_BASE +#endif + +#if !defined(RAM_ADDR) +#define RAM_ADDR RAM_BASE +#endif + +#define ROM_END_ADDR (ROM_ADDR + ROM_SIZE) +#define DEVNULL_SIZE CONFIG_LINKER_DEVNULL_MEMORY_SIZE +#define ROM_DEVNULL_END_ADDR (ROM_END_ADDR + DEVNULL_SIZE) +#define MAX_ADDR UINT32_MAX + +/* Determine where to put the devnull region. It should be adjacent to the ROM + * region. If ROM starts after RAM or the distance between ROM and RAM is big + * enough to fit the devnull region then devnull region is placed just after + * the ROM region. If it cannot be done then the devnull region is placed before + * the ROM region. It is possible that the devnull region cannot be placed + * adjacent to the ROM (e.g. ROM starts at 0 and RAM follows ROM). In that + * case compilation fails and the devnull region is not supported in that + * configuration. + */ +#if !defined(CONFIG_XIP) + +#if RAM_ADDR >= DEVNULL_SIZE +#define DEVNULL_ADDR (RAM_ADDR - DEVNULL_SIZE) +#else +#define DEVNULL_ADDR (RAM_ADDR + RAM_SIZE) +#endif + +#else /* CONFIG_XIP */ + +#if ((ROM_ADDR > RAM_ADDR) && ((MAX_ADDR - ROM_END_ADDR) >= DEVNULL_SIZE)) || \ + ((ROM_END_ADDR + DEVNULL_SIZE) <= RAM_ADDR) +#define DEVNULL_ADDR ROM_END_ADDR +#elif ROM_ADDR > DEVNULL_SIZE +#define DEVNULL_ADDR (ROM_ADDR - DEVNULL_SIZE) +#else +#error "Cannot place devnull segment adjacent to ROM region." +#endif + +#endif /* CONFIG_XIP */ + +#define DEVNULL_REGION DEVNULL_ROM + +#endif /* CONFIG_LINKER_DEVNULL_MEMORY */ + +#endif /* ZEPHYR_INCLUDE_LINKER_LINKER_DEVNULL_H_ */ diff --git a/include/zephyr/linker/linker-tool-gcc.h b/include/zephyr/linker/linker-tool-gcc.h index e5364b5a3d93c6e..ab8a3ad7f9aaa95 100644 --- a/include/zephyr/linker/linker-tool-gcc.h +++ b/include/zephyr/linker/linker-tool-gcc.h @@ -15,7 +15,7 @@ #ifndef ZEPHYR_INCLUDE_LINKER_LINKER_TOOL_GCC_H_ #define ZEPHYR_INCLUDE_LINKER_LINKER_TOOL_GCC_H_ -#include +#include #if defined(CONFIG_ARM) #if defined(CONFIG_BIG_ENDIAN) diff --git a/include/zephyr/linker/section_tags.h b/include/zephyr/linker/section_tags.h index d0ef2ecf1266106..5678a07325bc6b7 100644 --- a/include/zephyr/linker/section_tags.h +++ b/include/zephyr/linker/section_tags.h @@ -49,8 +49,10 @@ #if defined(CONFIG_NOCACHE_MEMORY) #define __nocache __in_section_unique(_NOCACHE_SECTION_NAME) +#define __nocache_noinit __nocache #else #define __nocache +#define __nocache_noinit __noinit #endif /* CONFIG_NOCACHE_MEMORY */ #if defined(CONFIG_KERNEL_COHERENCE) diff --git a/include/zephyr/llext/buf_loader.h b/include/zephyr/llext/buf_loader.h index c75d20e453084f5..5a50e215bd3cefc 100644 --- a/include/zephyr/llext/buf_loader.h +++ b/include/zephyr/llext/buf_loader.h @@ -37,6 +37,7 @@ struct llext_buf_loader { /** @cond ignore */ int llext_buf_read(struct llext_loader *ldr, void *buf, size_t len); int llext_buf_seek(struct llext_loader *ldr, size_t pos); +void *llext_buf_peek(struct llext_loader *ldr, size_t pos); /** @endcond */ /** @@ -49,7 +50,8 @@ int llext_buf_seek(struct llext_loader *ldr, size_t pos); { \ .loader = { \ .read = llext_buf_read, \ - .seek = llext_buf_seek \ + .seek = llext_buf_seek, \ + .peek = llext_buf_peek, \ }, \ .buf = (_buf), \ .len = (_buf_len), \ diff --git a/include/zephyr/llext/elf.h b/include/zephyr/llext/elf.h index 1e83142dcd3a4f3..a9fd8f86a94c4c2 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 @@ -306,6 +306,12 @@ struct elf32_rel { elf32_word r_info; }; +struct elf32_rela { + elf32_addr r_offset; + elf32_word r_info; + elf32_word r_addend; +}; + /** * @brief Relocation symbol index from r_info * @@ -330,6 +336,12 @@ struct elf64_rel { elf64_xword r_info; }; +struct elf64_rela { + elf64_addr r_offset; + elf64_word r_info; + elf64_word r_addend; +}; + /** @brief Relocation symbol from r_info * * @param i Value of r_info @@ -435,7 +447,8 @@ typedef elf64_half elf_half; /** Machine sized integer */ typedef elf64_xword elf_word; /** Machine sized relocation struct */ -typedef struct elf64_rela elf_rel_t; +typedef struct elf64_rel elf_rel_t; +typedef struct elf64_rela elf_rela_t; /** Machine sized symbol struct */ typedef struct elf64_sym elf_sym_t; /** Machine sized macro alias for obtaining a relocation symbol */ @@ -461,6 +474,7 @@ typedef elf32_half elf_half; typedef elf32_word elf_word; /** Machine sized relocation struct */ typedef struct elf32_rel elf_rel_t; +typedef struct elf32_rela elf_rela_t; /** Machine sized symbol struct */ typedef struct elf32_sym elf_sym_t; /** Machine sized macro alias for obtaining a relocation symbol */ diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index 56ad0eefea5209c..832aba25caca916 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -10,8 +10,8 @@ #include #include #include -#include #include +#include #ifdef __cplusplus extern "C" { @@ -25,17 +25,23 @@ 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, LLEXT_MEM_COUNT, }; +struct llext_loader; + /** * @brief Linkable loadable extension */ @@ -50,17 +56,30 @@ struct llext { /** Lookup table of llext memory regions */ void *mem[LLEXT_MEM_COUNT]; - /** Total size of the llext memory usage */ - size_t mem_size; + /** Is the memory for this section allocated on heap? */ + bool mem_on_heap[LLEXT_MEM_COUNT]; - /** Exported symbols from the llext, may be linked against by other llext */ + /** Size of each stored section */ + size_t mem_size[LLEXT_MEM_COUNT]; + + /** 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 @@ -71,6 +90,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 * @@ -80,20 +125,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. @@ -133,7 +180,27 @@ int llext_call_fn(struct llext *ext, const char *sym_name); * @param[in] opaddr Address of operation to rewrite with relocation * @param[in] opval Value of looked up symbol to relocate */ -void arch_elf_relocate(elf_rel_t *rel, uintptr_t opaddr, uintptr_t opval); +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 db4157168aa6853..7eb49d611bed300 100644 --- a/include/zephyr/llext/loader.h +++ b/include/zephyr/llext/loader.h @@ -21,26 +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, -}; +#include /** * @brief Linkable loadable extension loader context @@ -73,17 +54,47 @@ struct llext_loader { * @retval 0 Success * @retval -errno Error reading (any errno) */ - int (*seek)(struct llext_loader *s, size_t pos); + int (*seek)(struct llext_loader *ldr, size_t pos); + + /** + * @brief Peek at an absolute location + * + * Return a pointer to the buffer at specified offset. + * + * @param[in] ldr Loader + * @param[in] pos Position to obtain a pointer to + * + * @retval pointer into the buffer + */ + void *(*peek)(struct llext_loader *ldr, size_t pos); /** @cond ignore */ elf_ehdr_t hdr; - elf_shdr_t sects[LLEXT_SECT_COUNT]; - uint32_t *sect_map; + elf_shdr_t sects[LLEXT_MEM_COUNT]; + enum llext_mem *sect_map; uint32_t sect_cnt; - uint32_t sym_cnt; /** @endcond */ }; +static inline int llext_read(struct llext_loader *l, void *buf, size_t len) +{ + return l->read(l, buf, len); +} + +static inline int llext_seek(struct llext_loader *l, size_t pos) +{ + return l->seek(l, pos); +} + +static inline void *llext_peek(struct llext_loader *l, size_t pos) +{ + if (l->peek) { + return l->peek(l, pos); + } + + return NULL; +} + /** * @} */ diff --git a/include/zephyr/llext/symbol.h b/include/zephyr/llext/symbol.h index f4b69ef5010c5e5..19f34649026b358 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 @@ -44,7 +45,7 @@ struct llext_const_symbol { */ struct llext_symbol { /** Name of symbol */ - char *name; + const char *name; /** Address of symbol */ void *addr; @@ -75,9 +76,23 @@ struct llext_symtable { */ #define EXPORT_SYMBOL(x) \ static const STRUCT_SECTION_ITERABLE(llext_const_symbol, x ## _sym) = { \ - .name = STRINGIFY(x), .addr = x, \ + .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 + * + * Takes a system call name and uses @a EXPORT_SYMBOL() to export the respective + * function. + * + * @param x System call to export + */ +#define EXPORT_SYSCALL(x) EXPORT_SYMBOL(z_impl_ ## x) + /** * @} */ diff --git a/include/zephyr/logging/log.h b/include/zephyr/logging/log.h index e6db645c742b9ec..d04f5b1ab827769 100644 --- a/include/zephyr/logging/log.h +++ b/include/zephyr/logging/log.h @@ -298,14 +298,19 @@ void z_log_vprintk(const char *fmt, va_list ap); /* Return first argument */ #define _LOG_ARG1(arg1, ...) arg1 -#define _LOG_MODULE_CONST_DATA_CREATE(_name, _level) \ - IF_ENABLED(LOG_IN_CPLUSPLUS, (extern)) \ - const STRUCT_SECTION_ITERABLE_ALTERNATE(log_const, \ - log_source_const_data, \ - Z_LOG_ITEM_CONST_DATA(_name)) = \ - { \ - .name = STRINGIFY(_name), \ - .level = _level \ +#define _LOG_MODULE_CONST_DATA_CREATE(_name, _level) \ + IF_ENABLED(CONFIG_LOG_FMT_SECTION, ( \ + static const char UTIL_CAT(_name, _str)[] \ + __in_section(_log_strings, static, _CONCAT(_name, _)) __used __noasan = \ + STRINGIFY(_name);)) \ + IF_ENABLED(LOG_IN_CPLUSPLUS, (extern)) \ + const STRUCT_SECTION_ITERABLE_ALTERNATE(log_const, \ + log_source_const_data, \ + Z_LOG_ITEM_CONST_DATA(_name)) = \ + { \ + .name = COND_CODE_1(CONFIG_LOG_FMT_SECTION, \ + (UTIL_CAT(_name, _str)), (STRINGIFY(_name))), \ + .level = _level \ } #define _LOG_MODULE_DYNAMIC_DATA_CREATE(_name) \ diff --git a/include/zephyr/logging/log_backend_net.h b/include/zephyr/logging/log_backend_net.h index 9141b481b8d40fb..cde5ff3ea285019 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 f1ec834507303d3..7321b569f34d748 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__); \ @@ -290,7 +320,7 @@ static inline char z_log_minimal_level_to_char(int level) break; \ } \ /* For instance logging check instance specific static level */ \ - if (_inst & !IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING)) { \ + if (_inst && !IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING)) { \ if (_level > ((struct log_source_const_data *)_source)->level) { \ break; \ } \ @@ -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) @@ -413,7 +450,7 @@ TYPE_SECTION_END_EXTERN(struct log_source_const_data, log_const); z_log_printf_arg_checker(__VA_ARGS__); \ } \ Z_LOG_MSG_CREATE(!IS_ENABLED(CONFIG_USERSPACE), _mode, \ - Z_LOG_LOCAL_DOMAIN_ID, (uintptr_t)_is_raw, \ + Z_LOG_LOCAL_DOMAIN_ID, (const void *)(uintptr_t)_is_raw, \ LOG_LEVEL_INTERNAL_RAW_STRING, NULL, 0, __VA_ARGS__);\ } while (0) diff --git a/include/zephyr/logging/log_ctrl.h b/include/zephyr/logging/log_ctrl.h index dc5f39a2e7df6e1..9e5e3e3c077e7ee 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_frontend.h b/include/zephyr/logging/log_frontend.h index 058afa1f57669fc..132a78eb7483c9a 100644 --- a/include/zephyr/logging/log_frontend.h +++ b/include/zephyr/logging/log_frontend.h @@ -12,7 +12,7 @@ */ void log_frontend_init(void); -/** @brief Log message. +/** @brief Log generic message. * * Message details does not contain timestamp. Since function is called in the * context of log message call, implementation can use its own timestamping scheme. @@ -32,6 +32,52 @@ void log_frontend_msg(const void *source, const struct log_msg_desc desc, uint8_t *package, const void *data); +/** @brief Log message with 0 arguments. + * + * Optimized version for log message which does not have arguments (only string). + * This API is optional and is used only if optimizing common log messages is enabled. + * + * @param source Pointer to a structure associated with given source. It points to + * static structure or dynamic structure if runtime filtering is enabled. + * @ref log_const_source_id or @ref log_dynamic_source_id can be used to determine + * source id. + * @param level Severity level. + * @param fmt String. + */ +void log_frontend_simple_0(const void *source, uint32_t level, const char *fmt); + +/** @brief Log message with 1 argument. + * + * Optimized version for log message which has one argument that fits in a 32 bit word. + * This API is optional and is used only if optimizing common log messages is enabled. + * + * @param source Pointer to a structure associated with given source. It points to + * static structure or dynamic structure if runtime filtering is enabled. + * @ref log_const_source_id or @ref log_dynamic_source_id can be used to determine + * source id. + * @param level Severity level. + * @param fmt String. + * @param arg Argument passed to the string. + */ +void log_frontend_simple_1(const void *source, uint32_t level, const char *fmt, uint32_t arg); + +/** @brief Log message with 2 arguments. + * + * Optimized version for log message which has two arguments that fit in a 32 bit word. + * This API is optional and is used only if optimizing common log messages is enabled. + * + * @param source Pointer to a structure associated with given source. It points to + * static structure or dynamic structure if runtime filtering is enabled. + * @ref log_const_source_id or @ref log_dynamic_source_id can be used to determine + * source id. + * @param level Severity level. + * @param fmt String. + * @param arg0 First argument passed to the string. + * @param arg1 Second argument passed to the string. + */ +void log_frontend_simple_2(const void *source, uint32_t level, + const char *fmt, uint32_t arg0, uint32_t arg1); + /** @brief Panic state notification. */ void log_frontend_panic(void); diff --git a/include/zephyr/logging/log_msg.h b/include/zephyr/logging/log_msg.h index 0279fb0d2cdbb1d..39cbf1cedbc54bc 100644 --- a/include/zephyr/logging/log_msg.h +++ b/include/zephyr/logging/log_msg.h @@ -79,11 +79,10 @@ struct log_msg_hdr { const void *source; log_timestamp_t timestamp; #endif -#if CONFIG_LOG_THREAD_ID_PREFIX +#if defined(CONFIG_LOG_THREAD_ID_PREFIX) void *tid; #endif }; - /* Messages are aligned to alignment required by cbprintf package. */ #define Z_LOG_MSG_ALIGNMENT CBPRINTF_PACKAGE_ALIGNMENT @@ -141,6 +140,9 @@ enum z_log_msg_mode { * more code size. */ Z_LOG_MSG_MODE_ZERO_COPY, + + /* Mode optimized for simple messages with 0 to 2 32 bit word arguments.*/ + Z_LOG_MSG_MODE_SIMPLE, }; #define Z_LOG_MSG_DESC_INITIALIZER(_domain_id, _level, _plen, _dlen) \ @@ -227,6 +229,102 @@ enum z_log_msg_mode { #define Z_LOG_ARM64_VLA_PROTECT() compiler_barrier() +#define _LOG_MSG_SIMPLE_XXXX0 1 +#define _LOG_MSG_SIMPLE_XXXX1 1 +#define _LOG_MSG_SIMPLE_XXXX2 1 + +/* Determine if amount of arguments (less than 3) qualifies to simple message. */ +#define LOG_MSG_SIMPLE_ARG_CNT_CHECK(...) \ + COND_CODE_1(UTIL_CAT(_LOG_MSG_SIMPLE_XXXX, NUM_VA_ARGS_LESS_1(__VA_ARGS__)), (1), (0)) + +/* Set of marcos used to determine if arguments type allows simplified message creation mode. */ +#define LOG_MSG_SIMPLE_ARG_TYPE_CHECK_0(fmt) 1 +#define LOG_MSG_SIMPLE_ARG_TYPE_CHECK_1(fmt, arg) Z_CBPRINTF_IS_WORD_NUM(arg) +#define LOG_MSG_SIMPLE_ARG_TYPE_CHECK_2(fmt, arg0, arg1) \ + Z_CBPRINTF_IS_WORD_NUM(arg0) && Z_CBPRINTF_IS_WORD_NUM(arg1) + +/** brief Determine if string arguments types allow to use simplified message creation mode. + * + * @param ... String with arguments. + */ +#define LOG_MSG_SIMPLE_ARG_TYPE_CHECK(...) \ + UTIL_CAT(LOG_MSG_SIMPLE_ARG_TYPE_CHECK_, NUM_VA_ARGS_LESS_1(__VA_ARGS__))(__VA_ARGS__) + +/** @brief Check if message can be handled using simplified method. + * + * Following conditions must be met: + * - 32 bit platform + * - Number of arguments from 0 to 2 + * - Type of an argument must be a numeric value that fits in 32 bit word. + * + * @param ... String with arguments. + * + * @retval 1 if message qualifies. + * @retval 0 if message does not qualify. + */ +#define LOG_MSG_SIMPLE_CHECK(...) \ + COND_CODE_1(CONFIG_64BIT, (0), (\ + COND_CODE_1(LOG_MSG_SIMPLE_ARG_CNT_CHECK(__VA_ARGS__), ( \ + LOG_MSG_SIMPLE_ARG_TYPE_CHECK(__VA_ARGS__)), (0)))) + +/* Helper macro for handing log with one argument. Macro casts the first argument to uint32_t. */ +#define Z_LOG_MSG_SIMPLE_CREATE_1(_source, _level, ...) \ + z_log_msg_simple_create_1(_source, _level, GET_ARG_N(1, __VA_ARGS__), \ + (uint32_t)(uintptr_t)GET_ARG_N(2, __VA_ARGS__)) + +/* Helper macro for handing log with two arguments. Macro casts arguments to uint32_t. + */ +#define Z_LOG_MSG_SIMPLE_CREATE_2(_source, _level, ...) \ + z_log_msg_simple_create_2(_source, _level, GET_ARG_N(1, __VA_ARGS__), \ + (uint32_t)(uintptr_t)GET_ARG_N(2, __VA_ARGS__), \ + (uint32_t)(uintptr_t)GET_ARG_N(3, __VA_ARGS__)) + +/* Call specific function based on the number of arguments. + * Since up 2 to arguments are supported COND_CODE_0 and COND_CODE_1 can be used to + * handle all cases (0, 1 and 2 arguments). When tracing is enable then for each + * function a macro is create. The difference between function and macro is that + * macro is applied to any input arguments so we need to make sure that it is + * always called with proper number of arguments. For that it is wrapped around + * into another macro and dummy arguments to cover for cases when there is less + * arguments in a log call. + */ +#define Z_LOG_MSG_SIMPLE_FUNC2(arg_cnt, _source, _level, ...) \ + COND_CODE_0(arg_cnt, \ + (z_log_msg_simple_create_0(_source, _level, GET_ARG_N(1, __VA_ARGS__))), \ + (COND_CODE_1(arg_cnt, ( \ + Z_LOG_MSG_SIMPLE_CREATE_1(_source, _level, __VA_ARGS__, dummy) \ + ), ( \ + Z_LOG_MSG_SIMPLE_CREATE_2(_source, _level, __VA_ARGS__, dummy, dummy) \ + ) \ + ))) + +/** @brief Call specific function to create a log message. + * + * Macro picks matching function (based on number of arguments) and calls it. + * String arguments are casted to uint32_t. + * + * @param _source Source. + * @param _level Severity level. + * @param ... String with arguments. + */ +#define LOG_MSG_SIMPLE_FUNC(_source, _level, ...) \ + Z_LOG_MSG_SIMPLE_FUNC2(NUM_VA_ARGS_LESS_1(__VA_ARGS__), _source, _level, __VA_ARGS__) + +/** @brief Create log message using simplified method. + * + * Macro is gated by the argument count check to run @ref LOG_MSG_SIMPLE_FUNC only + * on entries with 2 or less arguments. + * + * @param _domain_id Domain ID. + * @param _source Pointer to the source structure. + * @param _level Severity level. + * @param ... String with arguments. + */ +#define Z_LOG_MSG_SIMPLE_ARGS_CREATE(_domain_id, _source, _level, ...) \ + IF_ENABLED(LOG_MSG_SIMPLE_ARG_CNT_CHECK(__VA_ARGS__), (\ + LOG_MSG_SIMPLE_FUNC(_source, _level, __VA_ARGS__); \ + )) + #define Z_LOG_MSG_STACK_CREATE(_cstr_cnt, _domain_id, _source, _level, _data, _dlen, ...) \ do { \ int _plen; \ @@ -430,6 +528,19 @@ do { \ _level, Z_LOG_FMT_ARGS(_fmt, ##__VA_ARGS__)); \ _mode = Z_LOG_MSG_MODE_ZERO_COPY; \ } else { \ + IF_ENABLED(UTIL_AND(IS_ENABLED(CONFIG_LOG_SIMPLE_MSG_OPTIMIZE), \ + UTIL_AND(UTIL_NOT(_domain_id), UTIL_NOT(_cstr_cnt))), \ + ( \ + bool can_simple = LOG_MSG_SIMPLE_CHECK(__VA_ARGS__); \ + if (can_simple && ((_dlen) == 0) && !k_is_user_context()) { \ + LOG_MSG_DBG("create fast message\n");\ + Z_LOG_MSG_SIMPLE_ARGS_CREATE(_domain_id, _source, _level, \ + Z_LOG_FMT_ARGS(_fmt, ##__VA_ARGS__)); \ + _mode = Z_LOG_MSG_MODE_SIMPLE; \ + break; \ + } \ + ) \ + ) \ LOG_MSG_DBG("create on stack message\n");\ Z_LOG_MSG_STACK_CREATE(_cstr_cnt, _domain_id, _source, _level, _data, \ _dlen, Z_LOG_FMT_ARGS(_fmt, ##__VA_ARGS__)); \ @@ -503,7 +614,37 @@ struct log_msg *z_log_msg_alloc(uint32_t wlen); void z_log_msg_finalize(struct log_msg *msg, const void *source, const struct log_msg_desc desc, const void *data); -/** @brief Create simple message from message details and string package. +/** @brief Create log message using simplified method for string with no arguments. + * + * @param source Pointer to the source structure. + * @param level Severity level. + * @param fmt String pointer. + */ +__syscall void z_log_msg_simple_create_0(const void *source, uint32_t level, + const char *fmt); + +/** @brief Create log message using simplified method for string with a one argument. + * + * @param source Pointer to the source structure. + * @param level Severity level. + * @param fmt String pointer. + * @param arg String argument. + */ +__syscall void z_log_msg_simple_create_1(const void *source, uint32_t level, + const char *fmt, uint32_t arg); + +/** @brief Create log message using simplified method for string with two arguments. + * + * @param source Pointer to the source structure. + * @param level Severity level. + * @param fmt String pointer. + * @param arg0 String argument. + * @param arg1 String argument. + */ +__syscall void z_log_msg_simple_create_2(const void *source, uint32_t level, + const char *fmt, uint32_t arg0, uint32_t arg1); + +/** @brief Create a logging message from message details and string package. * * @param source Source. * @@ -538,11 +679,11 @@ __syscall void z_log_msg_static_create(const void *source, * * @param ap Variable list of string arguments. */ -__syscall void z_log_msg_runtime_vcreate(uint8_t domain_id, const void *source, - uint8_t level, const void *data, - size_t dlen, uint32_t package_flags, - const char *fmt, - va_list ap); +void z_log_msg_runtime_vcreate(uint8_t domain_id, const void *source, + uint8_t level, const void *data, + size_t dlen, uint32_t package_flags, + const char *fmt, + va_list ap); /** @brief Create message at runtime. * @@ -666,7 +807,7 @@ static inline log_timestamp_t log_msg_get_timestamp(struct log_msg *msg) */ static inline void *log_msg_get_tid(struct log_msg *msg) { -#if CONFIG_LOG_THREAD_ID_PREFIX +#if defined(CONFIG_LOG_THREAD_ID_PREFIX) return msg->hdr.tid; #else ARG_UNUSED(msg); diff --git a/include/zephyr/logging/log_output.h b/include/zephyr/logging/log_output.h index e55170605c9e170..e28d1015aa4d1f5 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 @@ -159,7 +162,7 @@ void log_output_process(const struct log_output *log_output, log_timestamp_t timestamp, const char *domain, const char *source, - const k_tid_t tid, + k_tid_t tid, uint8_t level, const uint8_t *package, const uint8_t *data, diff --git a/include/zephyr/lorawan/lorawan.h b/include/zephyr/lorawan/lorawan.h index 519e6e4bea16e5a..b0f0117d91d3297 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 /** @@ -175,22 +177,32 @@ struct lorawan_downlink_cb { }; /** - * @brief Add battery level callback function. + * @brief Defines the battery level callback handler function signature. + * + * @retval 0 if the node is connected to an external power source + * @retval 1..254 battery level, where 1 is the minimum and 254 is the maximum value + * @retval 255 if the node was not able to measure the battery level + */ +typedef uint8_t (*lorawan_battery_level_cb_t)(void); + +/** + * @brief Defines the datarate changed callback handler function signature. + * + * @param dr Updated datarate. + */ +typedef void (*lorawan_dr_changed_cb_t)(enum lorawan_datarate dr); + +/** + * @brief Register a battery level callback function. * * Provide the LoRaWAN stack with a function to be called whenever a battery - * level needs to be read. As per LoRaWAN specification the callback needs to - * return "0: node is connected to an external power source, - * 1..254: battery level, where 1 is the minimum and 254 is the maximum - * value, - * 255: the node was not able to measure the battery level" + * level needs to be read. * * Should no callback be provided the lorawan backend will report 255. * - * @param battery_lvl_cb Pointer to the battery level function - * - * @return 0 if successful, negative errno code if failure + * @param cb Pointer to the battery level function */ -int lorawan_set_battery_level_callback(uint8_t (*battery_lvl_cb)(void)); +void lorawan_register_battery_level_callback(lorawan_battery_level_cb_t cb); /** * @brief Register a callback to be run on downlink packets @@ -205,12 +217,9 @@ void lorawan_register_downlink_callback(struct lorawan_downlink_cb *cb); * The callback is called once upon successfully joining a network and again * each time the datarate changes due to ADR. * - * The callback function takes one parameter: - * - dr - updated datarate - * - * @param dr_cb Pointer to datarate update callback + * @param cb Pointer to datarate update callback */ -void lorawan_register_dr_changed_callback(void (*dr_cb)(enum lorawan_datarate)); +void lorawan_register_dr_changed_callback(lorawan_dr_changed_cb_t cb); /** * @brief Join the LoRaWAN network 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 000000000000000..60cf183dd49bae7 --- /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/backend.h b/include/zephyr/mgmt/ec_host_cmd/backend.h index fe0581b092e9c04..ed61e0e33c2f563 100644 --- a/include/zephyr/mgmt/ec_host_cmd/backend.h +++ b/include/zephyr/mgmt/ec_host_cmd/backend.h @@ -43,11 +43,14 @@ struct ec_host_cmd_rx_ctx { /** * Buffer to hold received data. The buffer is provided by the handler if * CONFIG_EC_HOST_CMD_HANDLER_RX_BUFFER_SIZE > 0. Otherwise, the backend should provide - * the buffer on its own and overwrites @a buf pointer in the init function. + * the buffer on its own and overwrites @a buf pointer and @a len_max + * in the init function. */ uint8_t *buf; /** Number of bytes written to @a buf by backend. */ size_t len; + /** Maximum number of bytes to receive with one request packet. */ + size_t len_max; }; /** @@ -63,7 +66,7 @@ struct ec_host_cmd_tx_buf { void *buf; /** Number of bytes to write from @a buf. */ size_t len; - /** Size of @a buf. */ + /** Maximum number of bytes to send with one response packet. */ size_t len_max; }; 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 55c226d217ce9e3..c11e423e26dd3a6 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/img_mgmt/img_mgmt_client.h b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h index 8cede40d64e1f93..61e12afb16492ac 100644 --- a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h +++ b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h @@ -11,6 +11,13 @@ #include #include +/** + * @brief MCUmgr Image management client API + * @defgroup mcumgr_img_mgmt_client MCUmgr img_mgmt_client API + * @ingroup mcumgr + * @{ + */ + #ifdef __cplusplus extern "C" { #endif @@ -186,6 +193,10 @@ int img_mgmt_client_state_read(struct img_mgmt_client *client, struct mcumgr_ima int img_mgmt_client_erase(struct img_mgmt_client *client, uint32_t slot); +/** + * @} + */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h index e1ac45e63897aae..505ee6554748271 100644 --- a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h @@ -41,6 +41,12 @@ enum os_mgmt_err_code_t { /** Query was not recognized. */ OS_MGMT_ERR_QUERY_YIELDS_NO_ANSWER, + + /** RTC is not set */ + OS_MGMT_ERR_RTC_NOT_SET, + + /** RTC command failed */ + OS_MGMT_ERR_RTC_COMMAND_FAILED, }; /* Bitmask values used by the os info command handler. Note that the width of this variable is 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 12e8abde246c18c..ba63c136f5010fd 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 @@ -10,6 +10,13 @@ #include #include +/** + * @brief MCUmgr OS management client API + * @defgroup mcumgr_os_mgmt_client MCUmgr os_mgmt_client API + * @ingroup mcumgr + * @{ + */ + #ifdef __cplusplus extern "C" { #endif @@ -38,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. @@ -54,6 +62,10 @@ int os_mgmt_client_echo(struct os_mgmt_client *client, const char *echo_string); */ int os_mgmt_client_reset(struct os_mgmt_client *client); +/** + * @} + */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h b/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h index c3a9a5687d855e6..7678a70fdf9e6bd 100644 --- a/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h +++ b/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h @@ -197,6 +197,12 @@ enum os_mgmt_group_events { /** Callback when an info command needs to output data, data is os_mgmt_info_append. */ MGMT_EVT_OP_OS_MGMT_INFO_APPEND = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_OS, 2), + /** Callback when a datetime get command has been received. */ + MGMT_EVT_OP_OS_MGMT_DATETIME_GET = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_OS, 3), + + /** Callback when a datetime set command has been received, data is struct rtc_time(). */ + MGMT_EVT_OP_OS_MGMT_DATETIME_SET = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_OS, 4), + /** Used to enable all os_mgmt_group events. */ MGMT_EVT_OP_OS_MGMT_ALL = MGMT_DEF_EVT_OP_ALL(MGMT_EVT_GRP_OS), }; @@ -245,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 ed84b03763341ed..7699dd57cc6d678 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/mcumgr/smp/smp_client.h b/include/zephyr/mgmt/mcumgr/smp/smp_client.h index 88b2af701b09f4d..2e0eee2cfe66645 100644 --- a/include/zephyr/mgmt/mcumgr/smp/smp_client.h +++ b/include/zephyr/mgmt/mcumgr/smp/smp_client.h @@ -13,6 +13,13 @@ #include #include +/** + * @brief MCUmgr SMP client API + * @defgroup mcumgr_smp_client SMP client API + * @ingroup mcumgr + * @{ + */ + /** * @brief SMP client object */ @@ -102,6 +109,10 @@ void smp_client_buf_free(struct net_buf *nb); int smp_client_send_cmd(struct smp_client_object *smp_client, struct net_buf *nb, smp_client_res_fn cb, void *user_data, int timeout_in_sec); +/** + * @} + */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/mgmt/osdp.h b/include/zephyr/mgmt/osdp.h index 1408082123940e6..b73314aece2c5ce 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 1fba0ac669df23b..7043594b8ec6b25 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 1aebe9e2030277f..5f9f99370a01e1d 100644 --- a/include/zephyr/modem/backend/uart.h +++ b/include/zephyr/modem/backend/uart.h @@ -31,7 +31,8 @@ struct modem_backend_uart_isr { struct modem_backend_uart_async { uint8_t *receive_bufs[2]; uint32_t receive_buf_size; - struct ring_buf receive_rdb[2]; + struct ring_buf receive_rb; + struct k_spinlock receive_rb_lock; uint8_t *transmit_buf; uint32_t transmit_buf_size; struct k_work rx_disabled_work; @@ -42,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 d46ffc7c24a2052..28a2bc6bf9f173f 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 b64c00b992781e7..58959d6136b969d 100644 --- a/include/zephyr/modem/cmux.h +++ b/include/zephyr/modem/cmux.h @@ -33,14 +33,14 @@ extern "C" { #endif -struct modem_cmux; +/** + * @brief Modem CMUX + * @defgroup modem_cmux Modem CMUX + * @ingroup modem + * @{ + */ -enum modem_cmux_state { - MODEM_CMUX_STATE_DISCONNECTED = 0, - MODEM_CMUX_STATE_CONNECTING, - MODEM_CMUX_STATE_CONNECTED, - MODEM_CMUX_STATE_DISCONNECTING, -}; +struct modem_cmux; enum modem_cmux_event { MODEM_CMUX_EVENT_CONNECTED = 0, @@ -50,12 +50,20 @@ enum modem_cmux_event { typedef void (*modem_cmux_callback)(struct modem_cmux *cmux, enum modem_cmux_event event, void *user_data); +/** + * @cond INTERNAL_HIDDEN + */ + +enum modem_cmux_state { + MODEM_CMUX_STATE_DISCONNECTED = 0, + MODEM_CMUX_STATE_CONNECTING, + MODEM_CMUX_STATE_CONNECTED, + MODEM_CMUX_STATE_DISCONNECTING, +}; + 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, @@ -74,11 +82,6 @@ enum modem_cmux_dlci_state { MODEM_CMUX_DLCI_STATE_CLOSING, }; -enum modem_cmux_dlci_event { - MODEM_CMUX_DLCI_EVENT_OPENED, - MODEM_CMUX_DLCI_EVENT_CLOSED, -}; - struct modem_cmux_dlci { sys_snode_t node; @@ -157,6 +160,10 @@ struct modem_cmux { struct k_event event; }; +/** + * @endcond + */ + /** * @brief Contains CMUX instance configuration data */ @@ -205,7 +212,7 @@ struct modem_pipe *modem_cmux_dlci_init(struct modem_cmux *cmux, struct modem_cm const struct modem_cmux_dlci_config *config); /** - * @brief Initialize CMUX instance + * @brief Attach CMUX instance to pipe * * @param cmux CMUX instance * @param pipe Pipe instance to attach CMUX instance to @@ -243,7 +250,8 @@ int modem_cmux_connect_async(struct modem_cmux *cmux); * * @param cmux CMUX instance * - * @note When disconnected, the bus pipe can be used directly again + * @note The bus pipe must be released using modem_cmux_release() after disconnecting + * before being reused. */ int modem_cmux_disconnect(struct modem_cmux *cmux); @@ -254,12 +262,27 @@ int modem_cmux_disconnect(struct modem_cmux *cmux); * * @param cmux CMUX instance * - * @note When disconnected, the bus pipe can be used directly again + * @note The bus pipe must be released using modem_cmux_release() after disconnecting + * before being reused. */ int modem_cmux_disconnect_async(struct modem_cmux *cmux); +/** + * @brief Release CMUX instance from pipe + * + * @details Releases the pipe and hard resets the CMUX instance internally. CMUX should + * be disconnected using modem_cmux_disconnect(). + * + * @param cmux CMUX instance + * + * @note The bus pipe can be used directly again after CMUX instance is released. + */ void modem_cmux_release(struct modem_cmux *cmux); +/** + * @} + */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/modem/pipe.h b/include/zephyr/modem/pipe.h index 124af5d42694411..a741a94a34c816d 100644 --- a/include/zephyr/modem/pipe.h +++ b/include/zephyr/modem/pipe.h @@ -14,8 +14,38 @@ extern "C" { #endif +/** + * @brief Modem Pipe + * @defgroup modem_pipe Modem Pipe + * @ingroup modem + * @{ + */ + +/** Modem pipe event */ +enum modem_pipe_event { + MODEM_PIPE_EVENT_OPENED = 0, + MODEM_PIPE_EVENT_RECEIVE_READY, + MODEM_PIPE_EVENT_TRANSMIT_IDLE, + MODEM_PIPE_EVENT_CLOSED, +}; + +/** + * @cond INTERNAL_HIDDEN + */ + struct modem_pipe; +/** + * @endcond + */ + +typedef void (*modem_pipe_api_callback)(struct modem_pipe *pipe, enum modem_pipe_event event, + void *user_data); + +/** + * @cond INTERNAL_HIDDEN + */ + typedef int (*modem_pipe_api_open)(void *data); typedef int (*modem_pipe_api_transmit)(void *data, const uint8_t *buf, size_t size); @@ -36,15 +66,6 @@ enum modem_pipe_state { MODEM_PIPE_STATE_OPEN, }; -enum modem_pipe_event { - MODEM_PIPE_EVENT_OPENED = 0, - MODEM_PIPE_EVENT_RECEIVE_READY, - MODEM_PIPE_EVENT_CLOSED, -}; - -typedef void (*modem_pipe_api_callback)(struct modem_pipe *pipe, enum modem_pipe_event event, - void *user_data); - struct modem_pipe { void *data; struct modem_pipe_api *api; @@ -53,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; }; /** @@ -65,6 +87,10 @@ struct modem_pipe { */ void modem_pipe_init(struct modem_pipe *pipe, void *data, struct modem_pipe_api *api); +/** + * @endcond + */ + /** * @brief Open pipe * @@ -158,6 +184,10 @@ int modem_pipe_close(struct modem_pipe *pipe); */ int modem_pipe_close_async(struct modem_pipe *pipe); +/** + * @cond INTERNAL_HIDDEN + */ + /** * @brief Notify user of pipe that it has opened * @@ -185,6 +215,23 @@ 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 + */ + +/** + * @} + */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/modem/ppp.h b/include/zephyr/modem/ppp.h index 5d6d485e3086e5b..c0eca885fcdc346 100644 --- a/include/zephyr/modem/ppp.h +++ b/include/zephyr/modem/ppp.h @@ -20,6 +20,20 @@ extern "C" { #endif +/** + * @brief Modem PPP + * @defgroup modem_ppp Modem PPP + * @ingroup modem + * @{ + */ + +/** L2 network interface init callback */ +typedef void (*modem_ppp_init_iface)(struct net_if *iface); + +/** + * @cond INTERNAL_HIDDEN + */ + enum modem_ppp_receive_state { /* Searching for start of frame and header */ MODEM_PPP_RECEIVE_STATE_HDR_SOF = 0, @@ -57,8 +71,6 @@ enum modem_ppp_transmit_state { MODEM_PPP_TRANSMIT_STATE_EOF, }; -typedef void (*modem_ppp_init_iface)(struct net_if *iface); - struct modem_ppp { /* Network interface instance is bound to */ struct net_if *iface; @@ -103,6 +115,10 @@ struct modem_ppp { #endif }; +/** + * @endcond + */ + /** * @brief Attach pipe to instance and connect * @@ -126,6 +142,10 @@ struct net_if *modem_ppp_get_iface(struct modem_ppp *ppp); */ void modem_ppp_release(struct modem_ppp *ppp); +/** + * @cond INTERNAL_HIDDEN + */ + /** * @brief Initialize modem PPP instance device * @param dev Device instance associated with network interface @@ -133,6 +153,10 @@ void modem_ppp_release(struct modem_ppp *ppp); */ int modem_ppp_init_internal(const struct device *dev); +/** + * @endcond + */ + /** * @brief Define a modem PPP module and bind it to a network interface * @@ -163,6 +187,9 @@ int modem_ppp_init_internal(const struct device *dev); modem_ppp_init_internal, NULL, &_name, NULL, _prio, &modem_ppp_ppp_api, \ PPP_L2, NET_L2_GET_CTX_TYPE(PPP_L2), _mtu) +/** + * @} + */ #ifdef __cplusplus } diff --git a/include/zephyr/net/buf.h b/include/zephyr/net/buf.h index 91d0f601183638f..6e7f8b5b2a8fac5 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)]; \ @@ -1358,6 +1351,13 @@ static inline void net_buf_destroy(struct net_buf *buf) { struct net_buf_pool *pool = net_buf_pool_get(buf->pool_id); + if (buf->__buf) { + if (!(buf->flags & NET_BUF_EXTERNAL_DATA)) { + pool->alloc->cb->unref(buf, buf->__buf); + } + buf->__buf = NULL; + } + k_lifo_put(&pool->free, buf); } @@ -2414,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/coap.h b/include/zephyr/net/coap.h index 6fc21a6280b404e..cd57c560bee4f72 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -60,7 +60,9 @@ enum coap_option_num { COAP_OPTION_SIZE2 = 28, /**< Size2 (RFC 7959) */ COAP_OPTION_PROXY_URI = 35, /**< Proxy-Uri */ COAP_OPTION_PROXY_SCHEME = 39, /**< Proxy-Scheme */ - COAP_OPTION_SIZE1 = 60 /**< Size1 */ + COAP_OPTION_SIZE1 = 60, /**< Size1 */ + COAP_OPTION_ECHO = 252, /**< Echo (RFC 9175) */ + COAP_OPTION_REQUEST_TAG = 292 /**< Request-Tag (RFC 9175) */ }; /** @@ -272,7 +274,7 @@ struct coap_packet { uint8_t hdr_len; /**< CoAP header length */ uint16_t opt_len; /**< Total options length (delta + len + value) */ uint16_t delta; /**< Used for delta calculation in CoAP packet */ -#if defined(CONFIG_COAP_KEEP_USER_DATA) || defined(DOXGEN) +#if defined(CONFIG_COAP_KEEP_USER_DATA) || defined(DOXYGEN) /** * Application specific user data. * Only available when @kconfig{CONFIG_COAP_KEEP_USER_DATA} is enabled. @@ -307,6 +309,18 @@ typedef int (*coap_reply_t)(const struct coap_packet *response, struct coap_reply *reply, const struct sockaddr *from); +/** + * @brief CoAP transmission parameters. + */ +struct coap_transmission_parameters { + /** Initial ACK timeout. Value is used as a base value to retry pending CoAP packets. */ + uint32_t ack_timeout; + /** Set CoAP retry backoff factor. A value of 200 means a factor of 2.0. */ + uint16_t coap_backoff_percent; + /** Maximum number of retransmissions. */ + uint8_t max_retransmission; +}; + /** * @brief Represents a request awaiting for an acknowledgment (ACK). */ @@ -318,6 +332,7 @@ struct coap_pending { uint8_t *data; /**< User allocated buffer */ uint16_t len; /**< Length of the CoAP packet */ uint8_t retries; /**< Number of times the request has been sent */ + struct coap_transmission_parameters params; /**< Transmission parameters */ }; /** @@ -371,6 +386,15 @@ uint8_t coap_header_get_token(const struct coap_packet *cpkt, uint8_t *token); */ uint8_t coap_header_get_code(const struct coap_packet *cpkt); +/** + * @brief Modifies the code of the CoAP packet. + * + * @param cpkt CoAP packet representation + * @param code CoAP code + * @return 0 on success, -EINVAL on failure + */ +int coap_header_set_code(const struct coap_packet *cpkt, uint8_t code); + /** * @brief Returns the message id associated with the CoAP packet. * @@ -392,6 +416,20 @@ uint16_t coap_header_get_id(const struct coap_packet *cpkt); const uint8_t *coap_packet_get_payload(const struct coap_packet *cpkt, uint16_t *len); +/** + * @brief Verify if CoAP URI path matches with provided options. + * + * @param path Null-terminated array of strings. + * @param options Parsed options from coap_packet_parse() + * @param opt_num Number of options + * + * @return true if the CoAP URI path matches, + * false otherwise. + */ +bool coap_uri_path_match(const char * const *path, + struct coap_option *options, + uint8_t opt_num); + /** * @brief Parses the CoAP packet in data, validating it and * initializing @a cpkt. @a data must remain valid while @a cpkt is used. @@ -566,18 +604,52 @@ int coap_packet_append_payload_marker(struct coap_packet *cpkt); int coap_packet_append_payload(struct coap_packet *cpkt, const uint8_t *payload, uint16_t payload_len); +/** + * @brief Check if a CoAP packet is a CoAP request. + * + * @param cpkt Packet to be checked. + * + * @return true if the packet is a request, + * false otherwise. + */ +bool coap_packet_is_request(const struct coap_packet *cpkt); + /** * @brief When a request is received, call the appropriate methods of * the matching resources. * * @param cpkt Packet received * @param resources Array of known resources + * @param resources_len Number of resources in the array * @param options Parsed options from coap_packet_parse() * @param opt_num Number of options * @param addr Peer address * @param addr_len Peer address length * - * @retval 0 in case of success. + * @retval >= 0 in case of success. + * @retval -ENOTSUP in case of invalid request code. + * @retval -EPERM in case resource handler is not implemented. + * @retval -ENOENT in case the resource is not found. + */ +int coap_handle_request_len(struct coap_packet *cpkt, + struct coap_resource *resources, + size_t resources_len, + struct coap_option *options, + uint8_t opt_num, + struct sockaddr *addr, socklen_t addr_len); + +/** + * @brief When a request is received, call the appropriate methods of + * the matching resources. + * + * @param cpkt Packet received + * @param resources Array of known resources (terminated with empty resource) + * @param options Parsed options from coap_packet_parse() + * @param opt_num Number of options + * @param addr Peer address + * @param addr_len Peer address length + * + * @retval >= 0 in case of success. * @retval -ENOTSUP in case of invalid request code. * @retval -EPERM in case resource handler is not implemented. * @retval -ENOENT in case the resource is not found. @@ -839,10 +911,30 @@ bool coap_register_observer(struct coap_resource *resource, * * @param resource Resource in which to remove the observer * @param observer Observer to be removed + * + * @return true if the observer was found and removed. */ -void coap_remove_observer(struct coap_resource *resource, +bool coap_remove_observer(struct coap_resource *resource, struct coap_observer *observer); +/** + * @brief Returns the observer that matches address @a addr + * and has token @a token. + * + * @param observers Pointer to the array of observers + * @param len Size of the array of observers + * @param addr Address of the endpoint observing a resource + * @param token Pointer to the token + * @param token_len Length of valid bytes in the token + * + * @return A pointer to a observer if a match is found, NULL + * otherwise. + */ +struct coap_observer *coap_find_observer( + struct coap_observer *observers, size_t len, + const struct sockaddr *addr, + const uint8_t *token, uint8_t token_len); + /** * @brief Returns the observer that matches address @a addr. * @@ -850,6 +942,9 @@ void coap_remove_observer(struct coap_resource *resource, * @param len Size of the array of observers * @param addr Address of the endpoint observing a resource * + * @note The function coap_find_observer() should be preferred + * if both the observer's address and token are known. + * * @return A pointer to a observer if a match is found, NULL * otherwise. */ @@ -857,6 +952,24 @@ struct coap_observer *coap_find_observer_by_addr( struct coap_observer *observers, size_t len, const struct sockaddr *addr); +/** + * @brief Returns the observer that has token @a token. + * + * @param observers Pointer to the array of observers + * @param len Size of the array of observers + * @param token Pointer to the token + * @param token_len Length of valid bytes in the token + * + * @note The function coap_find_observer() should be preferred + * if both the observer's address and token are known. + * + * @return A pointer to a observer if a match is found, NULL + * otherwise. + */ +struct coap_observer *coap_find_observer_by_token( + struct coap_observer *observers, size_t len, + const uint8_t *token, uint8_t token_len); + /** * @brief Returns the next available observer representation. * @@ -889,14 +1002,15 @@ void coap_reply_init(struct coap_reply *reply, * confirmation message, initialized with data from @a request * @param request Message waiting for confirmation * @param addr Address to send the retransmission - * @param retries Maximum number of retransmissions of the message. + * @param params Pointer to the CoAP transmission parameters struct, + * or NULL to use default values * * @return 0 in case of success or negative in case of error. */ int coap_pending_init(struct coap_pending *pending, const struct coap_packet *request, const struct sockaddr *addr, - uint8_t retries); + const struct coap_transmission_parameters *params); /** * @brief Returns the next available pending struct, that can be used @@ -998,6 +1112,15 @@ void coap_pending_clear(struct coap_pending *pending); */ void coap_pendings_clear(struct coap_pending *pendings, size_t len); +/** + * @brief Count number of pending requests. + * + * @param len Number of elements in array. + * @param pendings Array of pending requests. + * @return count of elements where timeout is not zero. + */ +size_t coap_pendings_count(struct coap_pending *pendings, size_t len); + /** * @brief Cancels awaiting for this reply, so it becomes available * again. User responsibility to free the memory associated with data. @@ -1034,6 +1157,20 @@ int coap_resource_notify(struct coap_resource *resource); */ bool coap_request_is_observe(const struct coap_packet *request); +/** + * @brief Get currently active CoAP transmission parameters. + * + * @return CoAP transmission parameters structure. + */ +struct coap_transmission_parameters coap_get_transmission_parameters(void); + +/** + * @brief Set CoAP transmission parameters. + * + * @param params Pointer to the transmission parameters structure. + */ +void coap_set_transmission_parameters(const struct coap_transmission_parameters *params); + #ifdef __cplusplus } #endif diff --git a/include/zephyr/net/coap_client.h b/include/zephyr/net/coap_client.h index 86c4911de5be605..e48048d5c265183 100644 --- a/include/zephyr/net/coap_client.h +++ b/include/zephyr/net/coap_client.h @@ -20,6 +20,7 @@ */ #include +#include #define MAX_COAP_MSG_LEN (CONFIG_COAP_CLIENT_MESSAGE_HEADER_SIZE + \ @@ -82,13 +83,13 @@ struct coap_client_internal_request { uint32_t offset; uint32_t last_id; uint8_t request_tkl; - uint8_t retry_count; bool request_ongoing; struct coap_block_context recv_blk_ctx; struct coap_block_context send_blk_ctx; struct coap_pending pending; struct coap_client_request coap_request; struct coap_packet request; + uint8_t request_tag[COAP_TOKEN_MAX_LEN]; }; struct coap_client { @@ -100,6 +101,8 @@ struct coap_client { uint8_t send_buf[MAX_COAP_MSG_LEN]; uint8_t recv_buf[MAX_COAP_MSG_LEN]; struct coap_client_internal_request requests[CONFIG_COAP_CLIENT_MAX_REQUESTS]; + struct coap_option echo_option; + bool send_echo; }; /** @endcond */ @@ -127,12 +130,12 @@ int coap_client_init(struct coap_client *client, const char *info); * @param sock Open socket file descriptor. * @param addr the destination address of the request, NULL if socket is already connected. * @param req CoAP request structure - * @param retries How many times to retry or -1 to use default. + * @param params Pointer to transmission parameters structure or NULL to use default values. * @return zero when operation started successfully or negative error code otherwise. */ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr *addr, - struct coap_client_request *req, int retries); + struct coap_client_request *req, struct coap_transmission_parameters *params); /** * @} diff --git a/include/zephyr/net/coap_link_format.h b/include/zephyr/net/coap_link_format.h index 17374202b6d0079..cabfb9ff859d928 100644 --- a/include/zephyr/net/coap_link_format.h +++ b/include/zephyr/net/coap_link_format.h @@ -24,15 +24,45 @@ extern "C" { /** * This resource should be added before all other resources that should be - * included in the responses of the .well-known/core resource. + * included in the responses of the .well-known/core resource if is to be used with + * coap_well_known_core_get. */ #define COAP_WELL_KNOWN_CORE_PATH \ ((const char * const[]) { ".well-known", "core", NULL }) +/** + * @brief Build a CoAP response for a .well-known/core CoAP request. + * + * @param resource Array of known resources, terminated with an empty resource + * @param request A pointer to the .well-known/core CoAP request + * @param response A pointer to a CoAP response, will be initialized + * @param data A data pointer to be used to build the CoAP response + * @param data_len The maximum length of the data buffer + * + * @return 0 in case of success or negative in case of error. + */ int coap_well_known_core_get(struct coap_resource *resource, - struct coap_packet *request, + const struct coap_packet *request, struct coap_packet *response, - uint8_t *data, uint16_t len); + uint8_t *data, uint16_t data_len); + +/** + * @brief Build a CoAP response for a .well-known/core CoAP request. + * + * @param resources Array of known resources + * @param resources_len Number of resources in the array + * @param request A pointer to the .well-known/core CoAP request + * @param response A pointer to a CoAP response, will be initialized + * @param data A data pointer to be used to build the CoAP response + * @param data_len The maximum length of the data buffer + * + * @return 0 in case of success or negative in case of error. + */ +int coap_well_known_core_get_len(struct coap_resource *resources, + size_t resources_len, + const struct coap_packet *request, + struct coap_packet *response, + uint8_t *data, uint16_t data_len); /** * In case you want to add attributes to the resources included in the diff --git a/include/zephyr/net/coap_mgmt.h b/include/zephyr/net/coap_mgmt.h new file mode 100644 index 000000000000000..f19eec6eb4b436e --- /dev/null +++ b/include/zephyr/net/coap_mgmt.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief CoAP Events code public header + */ + +#ifndef ZEPHYR_INCLUDE_NET_COAP_MGMT_H_ +#define ZEPHYR_INCLUDE_NET_COAP_MGMT_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief CoAP Manager Events + * @defgroup coap_mgmt CoAP Manager Events + * @ingroup networking + * @{ + */ + +/** @cond INTERNAL_HIDDEN */ + +/* CoAP events */ +#define _NET_COAP_LAYER NET_MGMT_LAYER_L4 +#define _NET_COAP_CODE 0x1c0 +#define _NET_COAP_IF_BASE (NET_MGMT_EVENT_BIT | \ + NET_MGMT_LAYER(_NET_COAP_LAYER) | \ + NET_MGMT_LAYER_CODE(_NET_COAP_CODE)) + +struct coap_service; +struct coap_resource; +struct coap_observer; + +/** @endcond */ + +enum net_event_coap_cmd { + /* Service events */ + NET_EVENT_COAP_CMD_SERVICE_STARTED = 1, + NET_EVENT_COAP_CMD_SERVICE_STOPPED, + /* Observer events */ + NET_EVENT_COAP_CMD_OBSERVER_ADDED, + NET_EVENT_COAP_CMD_OBSERVER_REMOVED, +}; + +/** + * @brief coap_mgmt event raised when a service has started + */ +#define NET_EVENT_COAP_SERVICE_STARTED \ + (_NET_COAP_IF_BASE | NET_EVENT_COAP_CMD_SERVICE_STARTED) + +/** + * @brief coap_mgmt event raised when a service has stopped + */ +#define NET_EVENT_COAP_SERVICE_STOPPED \ + (_NET_COAP_IF_BASE | NET_EVENT_COAP_CMD_SERVICE_STOPPED) + +/** + * @brief coap_mgmt event raised when an observer has been added to a resource + */ +#define NET_EVENT_COAP_OBSERVER_ADDED \ + (_NET_COAP_IF_BASE | NET_EVENT_COAP_CMD_OBSERVER_ADDED) + +/** + * @brief coap_mgmt event raised when an observer has been removed from a resource + */ +#define NET_EVENT_COAP_OBSERVER_REMOVED \ + (_NET_COAP_IF_BASE | NET_EVENT_COAP_CMD_OBSERVER_REMOVED) + +/** + * @brief CoAP Service event structure. + */ +struct net_event_coap_service { + /* The CoAP service for which the event is emitted */ + const struct coap_service *service; +}; + +/** + * @brief CoAP Observer event structure. + */ +struct net_event_coap_observer { + /* The CoAP resource for which the event is emitted */ + struct coap_resource *resource; + /* The observer that is added/removed */ + struct coap_observer *observer; +}; + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_NET_COAP_MGMT_H_ */ diff --git a/include/zephyr/net/coap_service.h b/include/zephyr/net/coap_service.h new file mode 100644 index 000000000000000..b894fecf519e8d1 --- /dev/null +++ b/include/zephyr/net/coap_service.h @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief CoAP Service API + * + * An API for applications to respond to CoAP requests + */ + +#ifndef ZEPHYR_INCLUDE_NET_COAP_SERVICE_H_ +#define ZEPHYR_INCLUDE_NET_COAP_SERVICE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief CoAP Service API + * @defgroup coap_service CoAP service API + * @ingroup networking + * @{ + */ + +/** + * @name CoAP Service configuration flags + * @anchor COAP_SERVICE_FLAGS + * @{ + */ + +/** Start the service on boot. */ +#define COAP_SERVICE_AUTOSTART BIT(0) + +/** @} */ + +/** @cond INTERNAL_HIDDEN */ + +struct coap_service_data { + int sock_fd; + struct coap_observer observers[CONFIG_COAP_SERVICE_OBSERVERS]; + struct coap_pending pending[CONFIG_COAP_SERVICE_PENDING_MESSAGES]; +}; + +struct coap_service { + const char *name; + const char *host; + uint16_t *port; + uint8_t flags; + struct coap_resource *res_begin; + struct coap_resource *res_end; + struct coap_service_data *data; +}; + +#define __z_coap_service_define(_name, _host, _port, _flags, _res_begin, _res_end) \ + static struct coap_service_data coap_service_data_##_name = { \ + .sock_fd = -1, \ + }; \ + const STRUCT_SECTION_ITERABLE(coap_service, _name) = { \ + .name = STRINGIFY(_name), \ + .host = _host, \ + .port = (uint16_t *)(_port), \ + .flags = _flags, \ + .res_begin = (_res_begin), \ + .res_end = (_res_end), \ + .data = &coap_service_data_##_name, \ + } + +/** @endcond */ + +/** + * @brief Define a static CoAP resource owned by the service named @p _service . + * + * @note The handlers registered with the resource can return a CoAP response code to reply with + * an acknowledge without any payload, nothing is sent if the return value is 0 or negative. + * As seen in the example. + * + * @code{.c} + * static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios); + * + * static int led_put(struct coap_resource *resource, struct coap_packet *request, + * struct sockaddr *addr, socklen_t addr_len) + * { + * const uint8_t *payload; + * uint16_t payload_len; + * + * payload = coap_packet_get_payload(request, &payload_len); + * if (payload_len != 1) { + * return COAP_RESPONSE_CODE_BAD_REQUEST; + * } + * + * if (gpio_pin_set_dt(&led, payload[0]) < 0) { + * return COAP_RESPONSE_CODE_INTERNAL_ERROR; + * } + * + * return COAP_RESPONSE_CODE_CHANGED; + * } + * + * COAP_RESOURCE_DEFINE(my_resource, my_service, { + * .put = led_put, + * }); + * @endcode + * + * @param _name Name of the resource. + * @param _service Name of the associated service. + */ +#define COAP_RESOURCE_DEFINE(_name, _service, ...) \ + STRUCT_SECTION_ITERABLE_ALTERNATE(coap_resource_##_service, coap_resource, _name) \ + = __VA_ARGS__ + +/** + * @brief Define a CoAP service with static resources. + * + * @note The @p _host parameter can be `NULL`. If not, it is used to specify an IP address either in + * IPv4 or IPv6 format a fully-qualified hostname or a virtual host, otherwise the any address is + * used. + * + * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port + * number to use for the service. If the specified port number is zero, then an ephemeral port + * number will be used and the actual port number assigned will be written back to memory. For + * ephemeral port numbers, the memory pointed to by @p _port must be writeable. + * + * @param _name Name of the service. + * @param _host IP address or hostname associated with the service. + * @param[inout] _port Pointer to port associated with the service. + * @param _flags Configuration flags @see @ref COAP_SERVICE_FLAGS. + */ +#define COAP_SERVICE_DEFINE(_name, _host, _port, _flags) \ + extern struct coap_resource _CONCAT(_coap_resource_##_name, _list_start)[]; \ + extern struct coap_resource _CONCAT(_coap_resource_##_name, _list_end)[]; \ + __z_coap_service_define(_name, _host, _port, _flags, \ + &_CONCAT(_coap_resource_##_name, _list_start)[0], \ + &_CONCAT(_coap_resource_##_name, _list_end)[0]) + +/** + * @brief Count the number of CoAP services. + * + * @param[out] _dst Pointer to location where result is written. + */ +#define COAP_SERVICE_COUNT(_dst) STRUCT_SECTION_COUNT(coap_service, _dst) + +/** + * @brief Count CoAP service static resources. + * + * @param _service Pointer to a service. + */ +#define COAP_SERVICE_RESOURCE_COUNT(_service) ((_service)->res_end - (_service)->res_begin) + +/** + * @brief Check if service has the specified resource. + * + * @param _service Pointer to a service. + * @param _resource Pointer to a resource. + */ +#define COAP_SERVICE_HAS_RESOURCE(_service, _resource) \ + ((_service)->res_begin <= _resource && _resource < (_service)->res_end) + +/** + * @brief Iterate over all CoAP services. + * + * @param _it Name of iterator (of type @ref coap_service) + */ +#define COAP_SERVICE_FOREACH(_it) STRUCT_SECTION_FOREACH(coap_service, _it) + +/** + * @brief Iterate over static CoAP resources associated with a given @p _service. + * + * @note This macro requires that @p _service is defined with @ref COAP_SERVICE_DEFINE. + * + * @param _service Name of CoAP service + * @param _it Name of iterator (of type @ref coap_resource) + */ +#define COAP_RESOURCE_FOREACH(_service, _it) \ + STRUCT_SECTION_FOREACH_ALTERNATE(coap_resource_##_service, coap_resource, _it) + +/** + * @brief Iterate over all static resources associated with @p _service . + * + * @note This macro is suitable for a @p _service defined with @ref COAP_SERVICE_DEFINE. + * + * @param _service Pointer to COAP service + * @param _it Name of iterator (of type @ref coap_resource) + */ +#define COAP_SERVICE_FOREACH_RESOURCE(_service, _it) \ + for (struct coap_resource *_it = (_service)->res_begin; ({ \ + __ASSERT(_it <= (_service)->res_end, "unexpected list end location"); \ + _it < (_service)->res_end; \ + }); _it++) + +/** + * @brief Start the provided @p service . + * + * @note This function is suitable for a @p service defined with @ref COAP_SERVICE_DEFINE. + * + * @param service Pointer to CoAP service + * @retval 0 in case of success. + * @retval -EALREADY in case of an already running service. + * @retval -ENOTSUP in case the server has no valid host and port configuration. + */ +int coap_service_start(const struct coap_service *service); + +/** + * @brief Stop the provided @p service . + * + * @note This function is suitable for a @p service defined with @ref COAP_SERVICE_DEFINE. + * + * @param service Pointer to CoAP service + * @retval 0 in case of success. + * @retval -EALREADY in case the service isn't running. + */ +int coap_service_stop(const struct coap_service *service); + +/** + * @brief Query the provided @p service running state. + * + * @note This function is suitable for a @p service defined with @ref COAP_SERVICE_DEFINE. + * + * @param service Pointer to CoAP service + * @retval 1 if the service is running + * @retval 0 if the service is stopped + * @retval negative in case of an error. + */ +int coap_service_is_running(const struct coap_service *service); + +/** + * @brief Send a CoAP message from the provided @p service . + * + * @note This function is suitable for a @p service defined with @ref COAP_SERVICE_DEFINE. + * + * @param service Pointer to CoAP service + * @param cpkt CoAP Packet to send + * @param addr Peer address + * @param addr_len Peer address length + * @param params Pointer to transmission parameters structure or NULL to use default values. + * @return 0 in case of success or negative in case of error. + */ +int coap_service_send(const struct coap_service *service, const struct coap_packet *cpkt, + const struct sockaddr *addr, socklen_t addr_len, + const struct coap_transmission_parameters *params); + +/** + * @brief Send a CoAP message from the provided @p resource . + * + * @note This function is suitable for a @p resource defined with @ref COAP_RESOURCE_DEFINE. + * + * @param resource Pointer to CoAP resource + * @param cpkt CoAP Packet to send + * @param addr Peer address + * @param addr_len Peer address length + * @param params Pointer to transmission parameters structure or NULL to use default values. + * @return 0 in case of success or negative in case of error. + */ +int coap_resource_send(const struct coap_resource *resource, const struct coap_packet *cpkt, + const struct sockaddr *addr, socklen_t addr_len, + const struct coap_transmission_parameters *params); + +/** + * @brief Parse a CoAP observe request for the provided @p resource . + * + * @note This function is suitable for a @p resource defined with @ref COAP_RESOURCE_DEFINE. + * + * If the observe option value is equal to 0, an observer will be added, if the value is equal + * to 1, an existing observer will be removed. + * + * @param resource Pointer to CoAP resource + * @param request CoAP request to parse + * @param addr Peer address + * @return the observe option value in case of success or negative in case of error. + */ +int coap_resource_parse_observe(struct coap_resource *resource, const struct coap_packet *request, + const struct sockaddr *addr); + +/** + * @brief Lookup an observer by address and remove it from the @p resource . + * + * @note This function is suitable for a @p resource defined with @ref COAP_RESOURCE_DEFINE. + * + * @param resource Pointer to CoAP resource + * @param addr Peer address + * @return 0 in case of success or negative in case of error. + */ +int coap_resource_remove_observer_by_addr(struct coap_resource *resource, + const struct sockaddr *addr); + +/** + * @brief Lookup an observer by token and remove it from the @p resource . + * + * @note This function is suitable for a @p resource defined with @ref COAP_RESOURCE_DEFINE. + * + * @param resource Pointer to CoAP resource + * @param token Pointer to the token + * @param token_len Length of valid bytes in the token + * @return 0 in case of success or negative in case of error. + */ +int coap_resource_remove_observer_by_token(struct coap_resource *resource, + const uint8_t *token, uint8_t token_len); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_NET_COAP_SERVICE_H_ */ 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 000000000000000..88ef775ad1ebeac --- /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/dhcpv4_server.h b/include/zephyr/net/dhcpv4_server.h new file mode 100644 index 000000000000000..18c4af114cda302 --- /dev/null +++ b/include/zephyr/net/dhcpv4_server.h @@ -0,0 +1,118 @@ +/** @file + * @brief DHCPv4 Server API + */ + +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_NET_DHCPV4_SERVER_H_ +#define ZEPHYR_INCLUDE_NET_DHCPV4_SERVER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief DHCPv4 server + * @defgroup dhcpv4_server DHCPv4 server + * @ingroup networking + * @{ + */ + +/** @cond INTERNAL_HIDDEN */ + +struct net_if; + +#define DHCPV4_CLIENT_ID_MAX_SIZE 20 + +enum dhcpv4_server_addr_state { + DHCPV4_SERVER_ADDR_FREE, + DHCPV4_SERVER_ADDR_RESERVED, + DHCPV4_SERVER_ADDR_ALLOCATED, + DHCPV4_SERVER_ADDR_DECLINED, +}; + +struct dhcpv4_client_id { + uint8_t buf[DHCPV4_CLIENT_ID_MAX_SIZE]; + uint8_t len; +}; + +struct dhcpv4_addr_slot { + enum dhcpv4_server_addr_state state; + struct dhcpv4_client_id client_id; + struct in_addr addr; + uint32_t lease_time; + k_timepoint_t expiry; +}; + +/** @endcond */ + +/** + * @brief Start DHCPv4 server instance on an iface + * + * @details Start DHCPv4 server on a given interface. The server will start + * listening for DHCPv4 Discover/Request messages on the interface and assign + * IPv4 addresses from the configured address pool accordingly. + * + * @param iface A valid pointer on an interface + * @param base_addr First IPv4 address from the DHCPv4 address pool. The number + * of addresses in the pool is configured statically with Kconfig + * (CONFIG_NET_DHCPV4_SERVER_ADDR_COUNT). + * + * @return 0 on success, a negative error code otherwise. + */ +int net_dhcpv4_server_start(struct net_if *iface, struct in_addr *base_addr); + +/** + * @brief Stop DHCPv4 server instance on an iface + * + * @details Stop DHCPv4 server on a given interface. DHCPv4 requests will no + * longer be handled on the interface, and all of the allocations are cleared. + * + * @param iface A valid pointer on an interface + * + * @return 0 on success, a negative error code otherwise. + */ +int net_dhcpv4_server_stop(struct net_if *iface); + +/** + * @typedef net_dhcpv4_lease_cb_t + * @brief Callback used while iterating over active DHCPv4 address leases + * + * @param iface Pointer to the network interface + * @param lease Pointer to the DHPCv4 address lease slot + * @param user_data A valid pointer to user data or NULL + */ +typedef void (*net_dhcpv4_lease_cb_t)(struct net_if *iface, + struct dhcpv4_addr_slot *lease, + void *user_data); + +/** + * @brief Iterate over all DHCPv4 address leases on a given network interface + * and call callback for each lease. In case no network interface is provided + * (NULL interface pointer), will iterate over all interfaces running DHCPv4 + * server instance. + * + * @param iface Pointer to the network interface, can be NULL + * @param cb User-supplied callback function to call + * @param user_data User specified data + */ +int net_dhcpv4_server_foreach_lease(struct net_if *iface, + net_dhcpv4_lease_cb_t cb, + void *user_data); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_NET_DHCPV4_SERVER_H_ */ diff --git a/include/zephyr/net/dns_resolve.h b/include/zephyr/net/dns_resolve.h index 50e6501a730b424..46e5ad8e4df06aa 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 d291f93d5086218..0be84c80191aa96 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/ethernet.h b/include/zephyr/net/ethernet.h index a47ec767a608f7e..faa6cf7fc0b4de7 100644 --- a/include/zephyr/net/ethernet.h +++ b/include/zephyr/net/ethernet.h @@ -179,6 +179,9 @@ enum ethernet_hw_caps { /** TXTIME supported */ ETHERNET_TXTIME = BIT(19), + + /** TX-Injection supported */ + ETHERNET_TXINJECTION_MODE = BIT(20), }; /** @cond INTERNAL_HIDDEN */ @@ -196,6 +199,8 @@ enum ethernet_config_type { ETHERNET_CONFIG_TYPE_PRIORITY_QUEUES_NUM, ETHERNET_CONFIG_TYPE_FILTER, ETHERNET_CONFIG_TYPE_PORTS_NUM, + ETHERNET_CONFIG_TYPE_T1S_PARAM, + ETHERNET_CONFIG_TYPE_TXINJECTION_MODE, }; enum ethernet_qav_param_type { @@ -206,7 +211,53 @@ enum ethernet_qav_param_type { ETHERNET_QAV_PARAM_TYPE_STATUS, }; +enum ethernet_t1s_param_type { + ETHERNET_T1S_PARAM_TYPE_PLCA_CONFIG, +}; + /** @endcond */ +struct ethernet_t1s_param { + /** Type of T1S parameter */ + enum ethernet_t1s_param_type type; + union { + /* PLCA is the Physical Layer (PHY) Collision + * Avoidance technique employed with multidrop + * 10Base-T1S standard. + * + * The PLCA parameters are described in standard [1] + * as registers in memory map 4 (MMS = 4) (point 9.6). + * + * IDVER (PLCA ID Version) + * CTRL0 (PLCA Control 0) + * CTRL1 (PLCA Control 1) + * STATUS (PLCA Status) + * TOTMR (PLCA TO Control) + * BURST (PLCA Burst Control) + * + * Those registers are implemented by each OA TC6 + * compliant vendor (like for e.g. LAN865x - e.g. [2]). + * + * Documents: + * [1] - "OPEN Alliance 10BASE-T1x MAC-PHY Serial + * Interface" (ver. 1.1) + * [2] - "DS60001734C" - LAN865x data sheet + */ + struct { + /** T1S PLCA enabled */ + bool enable; + /** T1S PLCA node id range: 0 to 254 */ + uint8_t node_id; + /** T1S PLCA node count range: 1 to 255 */ + uint8_t node_count; + /** T1S PLCA burst count range: 0x0 to 0xFF */ + uint8_t burst_count; + /** T1S PLCA burst timer */ + uint8_t burst_timer; + /** T1S PLCA TO value */ + uint8_t to_timer; + } plca; + }; +}; struct ethernet_qav_param { /** ID of the priority queue to use */ @@ -395,6 +446,7 @@ struct ethernet_config { bool auto_negotiation; bool full_duplex; bool promisc_mode; + bool txinjection_mode; struct { bool link_10bt; @@ -404,6 +456,7 @@ struct ethernet_config { struct net_eth_addr mac_address; + struct ethernet_t1s_param t1s_param; struct ethernet_qav_param qav_param; struct ethernet_qbv_param qbv_param; struct ethernet_qbu_param qbu_param; @@ -981,6 +1034,17 @@ void net_eth_carrier_off(struct net_if *iface); */ int net_eth_promisc_mode(struct net_if *iface, bool enable); +/** + * @brief Set TX-Injection mode either ON or OFF. + * + * @param iface Network interface + * + * @param enable on (true) or off (false) + * + * @return 0 if mode set or unset was successful, <0 otherwise. + */ +int net_eth_txinjection_mode(struct net_if *iface, bool enable); + /** * @brief Return PTP clock that is tied to this ethernet network interface. * diff --git a/include/zephyr/net/ethernet_mgmt.h b/include/zephyr/net/ethernet_mgmt.h index 9d95fa7a42e72b0..18039e9f3aaeea0 100644 --- a/include/zephyr/net/ethernet_mgmt.h +++ b/include/zephyr/net/ethernet_mgmt.h @@ -51,6 +51,9 @@ enum net_request_ethernet_cmd { NET_REQUEST_ETHERNET_CMD_GET_QBV_PARAM, NET_REQUEST_ETHERNET_CMD_GET_QBU_PARAM, NET_REQUEST_ETHERNET_CMD_GET_TXTIME_PARAM, + NET_REQUEST_ETHERNET_CMD_SET_T1S_PARAM, + NET_REQUEST_ETHERNET_CMD_SET_TXINJECTION_MODE, + NET_REQUEST_ETHERNET_CMD_GET_TXINJECTION_MODE, }; #define NET_REQUEST_ETHERNET_SET_AUTO_NEGOTIATION \ @@ -128,6 +131,21 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_QBU_PARAM); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_TXTIME_PARAM); +#define NET_REQUEST_ETHERNET_SET_T1S_PARAM \ + (_NET_ETHERNET_BASE | NET_REQUEST_ETHERNET_CMD_SET_T1S_PARAM) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_T1S_PARAM); + +#define NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE \ + (_NET_ETHERNET_BASE | NET_REQUEST_ETHERNET_CMD_SET_TXINJECTION_MODE) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE); + +#define NET_REQUEST_ETHERNET_GET_TXINJECTION_MODE \ + (_NET_ETHERNET_BASE | NET_REQUEST_ETHERNET_CMD_GET_TXINJECTION_MODE) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_TXINJECTION_MODE); + struct net_eth_addr; struct ethernet_qav_param; struct ethernet_qbv_param; @@ -139,6 +157,7 @@ struct ethernet_req_params { bool auto_negotiation; bool full_duplex; bool promisc_mode; + bool txinjection_mode; struct { bool link_10bt; @@ -152,6 +171,7 @@ struct ethernet_req_params { struct ethernet_qbv_param qbv_param; struct ethernet_qbu_param qbu_param; struct ethernet_txtime_param txtime_param; + struct ethernet_t1s_param t1s_param; int priority_queues_num; int ports_num; diff --git a/include/zephyr/net/hostname.h b/include/zephyr/net/hostname.h index e34c1df31acde2f..196e9ab18e7bbf4 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/ieee802154_ie.h b/include/zephyr/net/ieee802154_ie.h new file mode 100644 index 000000000000000..0be4c1576e5c070 --- /dev/null +++ b/include/zephyr/net/ieee802154_ie.h @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2023 Florian Grandel, Zephyr Project. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief IEEE 802.15.4 MAC information element (IE) related types and helpers + * + * This is not to be included by the application. This file contains only those + * parts of the types required for IE support that need to be visible to IEEE + * 802.15.4 drivers and L2 at the same time, i.e. everything related to header + * IE representation, parsing and generation. + * + * All specification references in this file refer to IEEE 802.15.4-2020. + * + * @note All structs and attributes in this file that directly represent parts + * of IEEE 802.15.4 frames are in LITTLE ENDIAN, see section 4, especially + * section 4.3. + */ + +#ifndef ZEPHYR_INCLUDE_NET_IEEE802154_IE_H_ +#define ZEPHYR_INCLUDE_NET_IEEE802154_IE_H_ + +#include +#include + +/** + * @addtogroup ieee802154_driver + * @{ + * + * @name IEEE 802.15.4, section 7.4.2: MAC header information elements + * @{ + */ + +/** + * @brief Information Element Types. + * + * @details See sections 7.4.2.1 and 7.4.3.1. + */ +enum ieee802154_ie_type { + IEEE802154_IE_TYPE_HEADER = 0x0, + IEEE802154_IE_TYPE_PAYLOAD, +}; + +/** + * @brief Header Information Element IDs. + * + * @details See section 7.4.2.1, table 7-7, partial list, only IEs actually used + * are implemented. + */ +enum ieee802154_header_ie_element_id { + IEEE802154_HEADER_IE_ELEMENT_ID_VENDOR_SPECIFIC_IE = 0x00, + IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE = 0x1a, + IEEE802154_HEADER_IE_ELEMENT_ID_RIT_IE = 0x1b, + IEEE802154_HEADER_IE_ELEMENT_ID_RENDEZVOUS_TIME_IE = 0x1d, + IEEE802154_HEADER_IE_ELEMENT_ID_TIME_CORRECTION_IE = 0x1e, + IEEE802154_HEADER_IE_ELEMENT_ID_HEADER_TERMINATION_1 = 0x7e, + IEEE802154_HEADER_IE_ELEMENT_ID_HEADER_TERMINATION_2 = 0x7f, + /* partial list, add additional ids as needed */ +}; + +/** @cond INTERNAL_HIDDEN */ +#define IEEE802154_VENDOR_SPECIFIC_IE_OUI_LEN 3 +/** INTERNAL_HIDDEN @endcond */ + +/** @brief Vendor Specific Header IE, see section 7.4.2.3. */ +struct ieee802154_header_ie_vendor_specific { + uint8_t vendor_oui[IEEE802154_VENDOR_SPECIFIC_IE_OUI_LEN]; + uint8_t *vendor_specific_info; +} __packed; + +/** @brief Full CSL IE, see section 7.4.2.3. */ +struct ieee802154_header_ie_csl_full { + uint16_t csl_phase; + uint16_t csl_period; + uint16_t csl_rendezvous_time; +} __packed; + +/** @brief Reduced CSL IE, see section 7.4.2.3. */ +struct ieee802154_header_ie_csl_reduced { + uint16_t csl_phase; + uint16_t csl_period; +} __packed; + +/** @brief Generic CSL IE, see section 7.4.2.3. */ +struct ieee802154_header_ie_csl { + union { + struct ieee802154_header_ie_csl_full full; + struct ieee802154_header_ie_csl_reduced reduced; + }; +} __packed; + +/** @brief RIT IE, see section 7.4.2.4. */ +struct ieee802154_header_ie_rit { + uint8_t time_to_first_listen; + uint8_t number_of_repeat_listen; + uint16_t repeat_listen_interval; +} __packed; + +/** + * @brief Full Rendezvous Time IE, see section 7.4.2.6 + * (macCslInterval is nonzero). + */ +struct ieee802154_header_ie_rendezvous_time_full { + uint16_t rendezvous_time; + uint16_t wakeup_interval; +} __packed; + +/** + * @brief Reduced Rendezvous Time IE, see section 7.4.2.6 + * (macCslInterval is zero). + */ +struct ieee802154_header_ie_rendezvous_time_reduced { + uint16_t rendezvous_time; +} __packed; + +/** @brief Rendezvous Time IE, see section 7.4.2.6. */ +struct ieee802154_header_ie_rendezvous_time { + union { + struct ieee802154_header_ie_rendezvous_time_full full; + struct ieee802154_header_ie_rendezvous_time_reduced reduced; + }; +} __packed; + +/** @brief Time Correction IE, see section 7.4.2.7. */ +struct ieee802154_header_ie_time_correction { + uint16_t time_sync_info; +} __packed; + +/* @brief Generic Header IE, see section 7.4.2.1. */ +struct ieee802154_header_ie { +#if CONFIG_LITTLE_ENDIAN + uint16_t length : 7; + uint16_t element_id_low : 1; /* see enum ieee802154_header_ie_element_id */ + uint16_t element_id_high : 7; + uint16_t type : 1; /* always 0 */ +#else + uint16_t element_id_low : 1; /* see enum ieee802154_header_ie_element_id */ + uint16_t length : 7; + uint16_t type : 1; /* always 0 */ + uint16_t element_id_high : 7; +#endif + union { + struct ieee802154_header_ie_vendor_specific vendor_specific; + struct ieee802154_header_ie_csl csl; + struct ieee802154_header_ie_rit rit; + struct ieee802154_header_ie_rendezvous_time rendezvous_time; + struct ieee802154_header_ie_time_correction time_correction; + /* add additional supported header IEs here */ + } content; +} __packed; + +/** @brief The header IE's header length (2 bytes). */ +#define IEEE802154_HEADER_IE_HEADER_LENGTH sizeof(uint16_t) + + +/** @cond INTERNAL_HIDDEN */ +#define IEEE802154_DEFINE_HEADER_IE(_element_id, _length, _content, _content_type) \ + (struct ieee802154_header_ie) { \ + .length = (_length), \ + .element_id_high = (_element_id) >> 1U, .element_id_low = (_element_id) & 0x01, \ + .type = IEEE802154_IE_TYPE_HEADER, \ + .content._content_type = _content, \ + } + +#define IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC_CONTENT_LEN(_vendor_specific_info_len) \ + (IEEE802154_VENDOR_SPECIFIC_IE_OUI_LEN + (_vendor_specific_info_len)) + +#define IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC_CONTENT(_vendor_oui, _vendor_specific_info) \ + (struct ieee802154_header_ie_vendor_specific) { \ + .vendor_oui = _vendor_oui, .vendor_specific_info = (_vendor_specific_info), \ + } + +#define IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED_CONTENT(_csl_phase, _csl_period) \ + (struct ieee802154_header_ie_csl_reduced) { \ + .csl_phase = sys_cpu_to_le16(_csl_phase), \ + .csl_period = sys_cpu_to_le16(_csl_period), \ + } + +#define IEEE802154_DEFINE_HEADER_IE_CSL_FULL_CONTENT(_csl_phase, _csl_period, \ + _csl_rendezvous_time) \ + (struct ieee802154_header_ie_csl_full) { \ + .csl_phase = sys_cpu_to_le16(_csl_phase), \ + .csl_period = sys_cpu_to_le16(_csl_period), \ + .csl_rendezvous_time = sys_cpu_to_le16(_csl_rendezvous_time), \ + } + +#define IEEE802154_HEADER_IE_TIME_CORRECTION_NACK 0x8000 +#define IEEE802154_HEADER_IE_TIME_CORRECTION_MASK 0x0fff +#define IEEE802154_HEADER_IE_TIME_CORRECTION_SIGN_BIT_MASK 0x0800 + +#define IEEE802154_DEFINE_HEADER_IE_TIME_CORRECTION_CONTENT(_ack, _time_correction_us) \ + (struct ieee802154_header_ie_time_correction) { \ + .time_sync_info = sys_cpu_to_le16( \ + (!(_ack) * IEEE802154_HEADER_IE_TIME_CORRECTION_NACK) | \ + ((_time_correction_us) & IEEE802154_HEADER_IE_TIME_CORRECTION_MASK)), \ + } +/** INTERNAL_HIDDEN @endcond */ + +/** + * @brief Define a vendor specific header IE, see section 7.4.2.3. + * + * @details Example usage (all parameters in little endian): + * + * @code{.c} + * uint8_t vendor_specific_info[] = {...some vendor specific IE content...}; + * struct ieee802154_header_ie header_ie = IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC( + * {0x9b, 0xb8, 0xea}, vendor_specific_info, sizeof(vendor_specific_info)); + * @endcode + * + * @param _vendor_oui an initializer for a 3 byte vendor oui array in little + * endian + * @param _vendor_specific_info pointer to a variable length uint8_t array with + * the vendor specific IE content + * @param _vendor_specific_info_len the length of the vendor specific IE content + * (in bytes) + */ +#define IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC(_vendor_oui, _vendor_specific_info, \ + _vendor_specific_info_len) \ + IEEE802154_DEFINE_HEADER_IE(IEEE802154_HEADER_IE_ELEMENT_ID_VENDOR_SPECIFIC_IE, \ + IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC_CONTENT_LEN( \ + _vendor_specific_info_len), \ + IEEE802154_DEFINE_HEADER_IE_VENDOR_SPECIFIC_CONTENT( \ + _vendor_oui, _vendor_specific_info), \ + vendor_specific) + +/** + * @brief Define a reduced CSL IE, see section 7.4.2.3. + * + * @details Example usage (all parameters in CPU byte order): + * + * @code{.c} + * uint16_t csl_phase = ...; + * uint16_t csl_period = ...; + * struct ieee802154_header_ie header_ie = + * IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED(csl_phase, csl_period); + * @endcode + * + * @param _csl_phase CSL phase in CPU byte order + * @param _csl_period CSL period in CPU byte order + */ +#define IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED(_csl_phase, _csl_period) \ + IEEE802154_DEFINE_HEADER_IE( \ + IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE, \ + sizeof(struct ieee802154_header_ie_csl_reduced), \ + IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED_CONTENT(_csl_phase, _csl_period), \ + csl.reduced) + +/** + * @brief Define a full CSL IE, see section 7.4.2.3. + * + * @details Example usage (all parameters in CPU byte order): + * + * @code{.c} + * uint16_t csl_phase = ...; + * uint16_t csl_period = ...; + * uint16_t csl_rendezvous_time = ...; + * struct ieee802154_header_ie header_ie = + * IEEE802154_DEFINE_HEADER_IE_CSL_REDUCED(csl_phase, csl_period, csl_rendezvous_time); + * @endcode + * + * @param _csl_phase CSL phase in CPU byte order + * @param _csl_period CSL period in CPU byte order + * @param _csl_rendezvous_time CSL rendezvous time in CPU byte order + */ +#define IEEE802154_DEFINE_HEADER_IE_CSL_FULL(_csl_phase, _csl_period, _csl_rendezvous_time) \ + IEEE802154_DEFINE_HEADER_IE(IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE, \ + sizeof(struct ieee802154_header_ie_csl_full), \ + IEEE802154_DEFINE_HEADER_IE_CSL_FULL_CONTENT( \ + _csl_phase, _csl_period, _csl_rendezvous_time), \ + csl.full) + +/** + * @brief Define a Time Correction IE, see section 7.4.2.7. + * + * @details Example usage (parameter in CPU byte order): + * + * @code{.c} + * uint16_t time_sync_info = ...; + * struct ieee802154_header_ie header_ie = + * IEEE802154_DEFINE_HEADER_IE_TIME_CORRECTION(true, time_sync_info); + * @endcode + * + * @param _ack whether or not the enhanced ACK frame that receives this IE is an + * ACK (true) or NACK (false) + * @param _time_correction_us the positive or negative deviation from expected + * RX time in microseconds + */ +#define IEEE802154_DEFINE_HEADER_IE_TIME_CORRECTION(_ack, _time_correction_us) \ + IEEE802154_DEFINE_HEADER_IE( \ + IEEE802154_HEADER_IE_ELEMENT_ID_TIME_CORRECTION_IE, \ + sizeof(struct ieee802154_header_ie_time_correction), \ + IEEE802154_DEFINE_HEADER_IE_TIME_CORRECTION_CONTENT(_ack, _time_correction_us), \ + time_correction) + +/** + * @brief Retrieve the time correction value in microseconds from a Time Correction IE, + * see section 7.4.2.7. + * + * @param[in] ie pointer to the Time Correction IE structure + * + * @return The time correction value in microseconds. + */ +static inline int16_t +ieee802154_header_ie_get_time_correction_us(struct ieee802154_header_ie_time_correction *ie) +{ + if (ie->time_sync_info & IEEE802154_HEADER_IE_TIME_CORRECTION_SIGN_BIT_MASK) { + /* Negative integer */ + return (int16_t)ie->time_sync_info | ~IEEE802154_HEADER_IE_TIME_CORRECTION_MASK; + } + + /* Positive integer */ + return (int16_t)ie->time_sync_info & IEEE802154_HEADER_IE_TIME_CORRECTION_MASK; +} + +/** + * @brief Set the element ID of a header IE. + * + * @param[in] ie pointer to a header IE + * @param[in] element_id IE element id in CPU byte order + */ +static inline void ieee802154_header_ie_set_element_id(struct ieee802154_header_ie *ie, + uint8_t element_id) +{ + ie->element_id_high = element_id >> 1U; + ie->element_id_low = element_id & 0x01; +} + +/** + * @brief Get the element ID of a header IE. + * + * @param[in] ie pointer to a header IE + * + * @return header IE element id in CPU byte order + */ +static inline uint8_t ieee802154_header_ie_get_element_id(struct ieee802154_header_ie *ie) +{ + return (ie->element_id_high << 1U) | ie->element_id_low; +} + +/** @brief The length in bytes of a "Time Correction" header IE. */ +#define IEEE802154_TIME_CORRECTION_HEADER_IE_LEN \ + (IEEE802154_HEADER_IE_HEADER_LENGTH + sizeof(struct ieee802154_header_ie_time_correction)) + +/** @brief The length in bytes of a "Header Termination 1" header IE. */ +#define IEEE802154_HEADER_TERMINATION_1_HEADER_IE_LEN IEEE802154_HEADER_IE_HEADER_LENGTH + +/** + * @} + * + * @} + */ + +#endif /* ZEPHYR_INCLUDE_NET_IEEE802154_IE_H_ */ diff --git a/include/zephyr/net/ieee802154_pkt.h b/include/zephyr/net/ieee802154_pkt.h index a1dca4724482aed..3270f9942483df0 100644 --- a/include/zephyr/net/ieee802154_pkt.h +++ b/include/zephyr/net/ieee802154_pkt.h @@ -59,16 +59,9 @@ struct net_pkt_cb_ieee802154 { */ uint8_t rssi; }; -#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) - /* TX packets */ - struct { - int8_t txpwr; /* TX power in dBm. */ - }; -#endif /* CONFIG_IEEE802154_SELECTIVE_TXPOWER */ }; /* Flags */ - uint8_t arb : 1; /* ACK Request Bit is set in the frame */ uint8_t ack_fpb : 1; /* Frame Pending Bit was set in the ACK */ uint8_t frame_secured : 1; /* Frame is authenticated and * encrypted according to its @@ -80,9 +73,6 @@ struct net_pkt_cb_ieee802154 { * e.g. Frame Counter injection. */ #if defined(CONFIG_NET_L2_OPENTHREAD) - uint8_t fv2015: 1; /* Frame version is IEEE 802.15.4 (0b10), - * see section 7.2.2.10, table 7-3. - */ uint8_t ack_seb : 1; /* Security Enabled Bit was set in the ACK */ #endif }; @@ -189,28 +179,6 @@ static inline void net_pkt_set_ieee802154_rssi_dbm(struct net_pkt *pkt, int16_t CODE_UNREACHABLE; } -#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) -static inline int8_t net_pkt_ieee802154_txpwr(struct net_pkt *pkt) -{ - return net_pkt_cb_ieee802154(pkt)->txpwr; -} - -static inline void net_pkt_set_ieee802154_txpwr(struct net_pkt *pkt, int8_t txpwr) -{ - net_pkt_cb_ieee802154(pkt)->txpwr = txpwr; -} -#endif /* CONFIG_IEEE802154_SELECTIVE_TXPOWER */ - -static inline bool net_pkt_ieee802154_arb(struct net_pkt *pkt) -{ - return net_pkt_cb_ieee802154(pkt)->arb; -} - -static inline void net_pkt_set_ieee802154_arb(struct net_pkt *pkt, bool arb) -{ - net_pkt_cb_ieee802154(pkt)->arb = arb; -} - static inline bool net_pkt_ieee802154_ack_fpb(struct net_pkt *pkt) { return net_pkt_cb_ieee802154(pkt)->ack_fpb; @@ -262,16 +230,6 @@ static inline void net_pkt_set_ieee802154_ack_keyid(struct net_pkt *pkt, uint8_t net_pkt_cb_ieee802154(pkt)->ack_keyid = keyid; } -static inline bool net_pkt_ieee802154_fv2015(struct net_pkt *pkt) -{ - return net_pkt_cb_ieee802154(pkt)->fv2015; -} - -static inline void net_pkt_set_ieee802154_fv2015(struct net_pkt *pkt, bool fv2015) -{ - net_pkt_cb_ieee802154(pkt)->fv2015 = fv2015; -} - static inline bool net_pkt_ieee802154_ack_seb(struct net_pkt *pkt) { return net_pkt_cb_ieee802154(pkt)->ack_seb; diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index f4d8ff6d318e584..259d67b43214f4c 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -482,7 +483,30 @@ enum ieee802154_hw_caps { /** TX at specified time supported */ IEEE802154_HW_TXTIME = BIT(8), - /** TX directly from sleep supported */ + /** TX directly from sleep supported + * + * @note This HW capability does not conform to the requirements + * specified in #61227 as it closely couples the driver to OpenThread's + * capability and device model which is different from Zephyr's: + * - "Sleeping" is a well defined term in Zephyr related to internal + * power and thread management and different from "RX off" as + * defined in OT. + * - Currently all OT-capable drivers have the "sleep to TX" + * capability anyway plus we expect future drivers to implement it + * ootb as well, so no information is actually conveyed by this + * capability. + * - The `start()`/`stop()` API of a net device controls the + * interface's operational state. Drivers MUST respond with + * -ENETDOWN when calling `tx()` while their operational state is + * "DOWN", only devices in the "UP" state MAY transmit packets (RFC + * 2863). + * - A migration path has been defined in #63670 for actual removal of + * this capability in favor of a standard compliant + * `configure(rx_on/rx_off)` call, see there for details. + * + * @deprecated Drivers and L2 SHALL not introduce additional references + * to this capability and remove existing ones as outlined in #63670. + */ IEEE802154_HW_SLEEP_TO_TX = BIT(9), /** Timed RX window scheduling supported */ @@ -491,13 +515,16 @@ enum ieee802154_hw_caps { /** TX security supported (key management, encryption and authentication) */ IEEE802154_HW_TX_SEC = BIT(11), + /** RxOnWhenIdle handling supported */ + IEEE802154_RX_ON_WHEN_IDLE = BIT(12), + /* Note: Update also IEEE802154_HW_CAPS_BITS_COMMON_COUNT when changing * the ieee802154_hw_caps type. */ }; /** @brief Number of bits used by ieee802154_hw_caps type. */ -#define IEEE802154_HW_CAPS_BITS_COMMON_COUNT (12) +#define IEEE802154_HW_CAPS_BITS_COMMON_COUNT (13) /** @brief This and higher values are specific to the protocol- or driver-specific extensions. */ #define IEEE802154_HW_CAPS_BITS_PRIV_START IEEE802154_HW_CAPS_BITS_COMMON_COUNT @@ -524,7 +551,7 @@ enum ieee802154_event { * synchronously switched of due to a call to `stop()` or an RX slot * being configured. */ - IEEE802154_EVENT_SLEEP, + IEEE802154_EVENT_RX_OFF, }; /** RX failed event reasons, see @ref IEEE802154_EVENT_RX_FAILED */ @@ -565,11 +592,16 @@ struct ieee802154_filter { * IEEE802154_CONFIG_MAC_KEYS. */ struct ieee802154_key { + /** Key material */ uint8_t *key_value; + /** Initial value of frame counter associated with the key, see section 9.4.3 */ uint32_t key_frame_counter; + /** Indicates if per-key frame counter should be used, see section 9.4.3 */ bool frame_counter_per_key; + /** Key Identifier Mode, see section 9.4.2.3, Table 9-7 */ uint8_t key_id_mode; - uint8_t key_index; + /** Key Identifier, see section 9.4.4 */ + uint8_t *key_id; }; /** IEEE 802.15.4 Transmission mode. */ @@ -598,6 +630,9 @@ enum ieee802154_tx_mode { * Transmit packet in the future, perform CCA before transmission. * * @note requires IEEE802154_HW_TXTIME capability. + * + * @note Required for Thread 1.2 Coordinated Sampled Listening feature + * (see Thread specification 1.2.0, ch. 3.2.6.3). */ IEEE802154_TX_MODE_TXTIME_CCA, @@ -675,7 +710,8 @@ enum ieee802154_config_type { * larger than the current frame counter associated with the same key, * see sections 8.2.2, 9.2.4 g/h) and 9.4.3. * - * @note Available in any interface operational state. + * @note Requires @ref IEEE802154_HW_TX_SEC capability and is available + * in any interface operational state. */ IEEE802154_CONFIG_MAC_KEYS, @@ -691,7 +727,8 @@ enum ieee802154_config_type { * Drivers SHALL return -EINVAL in case the configured frame counter * does not conform to this requirement. * - * @note Available in any interface operational state. + * @note Requires @ref IEEE802154_HW_TX_SEC capability and is available + * in any interface operational state. */ IEEE802154_CONFIG_FRAME_COUNTER, @@ -699,7 +736,8 @@ enum ieee802154_config_type { * Sets the current MAC frame counter value if the provided value is greater than * the current one. * - * @note Available in any interface operational state. + * @note Requires @ref IEEE802154_HW_TX_SEC capability and is available + * in any interface operational state. * * @warning This configuration option does not conform to the * requirements specified in #61227 as it is redundant with @ref @@ -753,79 +791,309 @@ enum ieee802154_config_type { * * @note requires @ref IEEE802154_HW_RXTIME capability and is available * in any interface operational state. + * + * @note Required for Thread 1.2 Coordinated Sampled Listening feature + * (see Thread specification 1.2.0, ch. 3.2.6.3). */ IEEE802154_CONFIG_RX_SLOT, /** - * Configure CSL receiver (Endpoint) period. - * - * @details In order to configure a CSL receiver the upper layer should combine several - * configuration options in the following way: - * 1. Use @ref IEEE802154_CONFIG_ENH_ACK_HEADER_IE once to inform the driver of the - * short and extended addresses of the peer to which it should inject CSL IEs. - * 2. Use @ref IEEE802154_CONFIG_CSL_RX_TIME periodically, before each use of - * @ref IEEE802154_CONFIG_CSL_PERIOD setting parameters of the nearest CSL RX window, - * and before each use of IEEE_CONFIG_RX_SLOT setting parameters of the following (not - * the nearest one) CSL RX window, to allow the driver to calculate the proper - * CSL phase to the nearest CSL window to inject in the CSL IEs for both transmitted - * data and ACK frames. - * 3. Use @ref IEEE802154_CONFIG_CSL_PERIOD on each value change to update the current - * CSL period value which will be injected in the CSL IEs together with the CSL phase - * based on @ref IEEE802154_CONFIG_CSL_RX_TIME. - * 4. Use @ref IEEE802154_CONFIG_RX_SLOT periodically to schedule the immediate receive - * window early enough before the expected window start time, taking into account - * possible clock drifts and scheduling uncertainties. - * - * This diagram shows the usage of the four options over time: - * - * Start CSL Schedule CSL window - * - * ENH_ACK_HEADER_IE CSL_RX_TIME (following window) - * | | - * | CSL_RX_TIME (nearest window) | RX_SLOT (nearest window) - * | | | | - * | | CSL_PERIOD | | - * | | | | | - * v v v v v - * ----------------------------------------------------------[ CSL window ]-----+ - * ^ | - * | | - * +--------------------- loop ---------+ + * Enables or disables a device as a CSL receiver and configures its CSL + * period. + * + * @details Configures the CSL period in units of 10 symbol periods. + * Values greater than zero enable CSL if the driver supports it and the + * device starts to operate as a CSL receiver. Setting this to zero + * disables CSL on the device. If the driver does not support CSL, the + * configuration call SHALL return -ENOTSUP. + * + * See section 7.4.2.3 and section 8.4.3.6, table 8-104, macCslPeriod. + * + * @note Confusingly the standard calls the CSL receiver "CSL + * coordinator" (i.e. "coordinating the CSL protocol timing", see + * section 6.12.2.2), although, typically, a CSL coordinator is NOT also + * an IEEE 802.15.4 FFD coordinator or PAN coordintor but a simple RFD + * end device (compare the device roles outlined in sections 5.1, 5.3, + * 5.5 and 6.1). To avoid confusion we therefore prefer calling CSL + * coordinators (typically an RFD end device) "CSL receivers" and CSL + * peer devices (typically FFD coordinators or PAN coordinators) "CSL + * transmitters". Also note that at this time, we do NOT support + * unsynchronized transmission with CSL wake up frames as specified in + * section 6.12.2.4.4. + * + * To offload CSL receiver timing to the driver the upper layer SHALL + * combine several configuration options in the following way: + * + * 1. Use @ref IEEE802154_CONFIG_ENH_ACK_HEADER_IE once with an + * appropriate pre-filled CSL IE and the CSL phase set to an + * arbitrary value or left uninitialized. The CSL phase SHALL be + * injected on-the-fly by the driver at runtime as outlined in 2. + * below. Adding a short and extended address will inform the driver + * of the specific CSL receiver to which it SHALL inject CSL IEs. If + * no addresses are given then the CSL IE will be injected into all + * enhanced ACK frames as soon as CSL is enabled. This configuration + * SHALL be done before enabling CSL by setting a CSL period greater + * than zero. + * + * 2. Configure @ref IEEE802154_CONFIG_EXPECTED_RX_TIME immediately + * followed by @ref IEEE802154_CONFIG_CSL_PERIOD. To prevent race + * conditions, the upper layer SHALL ensure that the receiver is not + * enabled during or between the two calls (e.g. by a previously + * configured RX slot) nor SHALL a frame be transmitted concurrently. + * + * The expected RX time SHALL point to the end of SFD of an ideally + * timed RX frame in an arbitrary past or future CSL channel sample, + * i.e. whose "end of SFD" arrives exactly at the locally predicted + * time inside the CSL channel sample. + * + * The driver SHALL derive CSL anchor points and the CSL phase from + * the given expected RX time as follows: + * + * cslAnchorPointNs = last expected RX time + * + PHY-specific PHR duration in ns + * + * startOfMhrNs = start of MHR of the frame containing the + * CSL IE relative to the local network clock + * + * cslPhase = (startOfMhrNs - cslAnchorPointNs) + * / (10 * PHY specific symbol period in ns) + * % cslPeriod + * + * The driver SHALL set the CSL phase in the IE configured in 1. and + * inject that IE on-the-fly into outgoing enhanced ACK frames if the + * destination address conforms to the IE's address filter. + * + * 3. Use @ref IEEE802154_CONFIG_RX_SLOT periodically to schedule + * each CSL channel sample early enough before its start time. The + * size of the CSL channel sample SHALL take relative clock drift and + * scheduling uncertainties with respect to CSL transmitters into + * account as specified by the standard such that at least the full + * SHR of a legitimate RX frame is guaranteed to land inside the + * channel sample. + * + * To this avail, the last configured expected RX time plus an + * integer number of CSL periods SHALL point to a fixed offset of the + * RX slot (not necessarily its center): + * + * expectedRxTimeNs_N = last expected RX time + * + N * (cslPeriod * 10 * PHY-specific symbol period in ns) + * + * expectedRxTimeNs_N - rxSlot_N.start == const for all N + * + * While the configured CSL period is greater than zero, drivers + * SHOULD validate the offset of the expected RX time inside each RX + * slot accordingly. If the driver finds that the offset varies from + * slot to slot, drivers SHOULD log the difference but SHALL + * nevertheless accept and schedule the RX slot with a zero success + * value to work around minor implementation or rounding errors in + * upper layers. + * + * Configure and start a CSL receiver: + * + * ENH_ACK_HEADER_IE + * | + * | EXPECTED_RX_TIME (end of SFD of a perfectly timed RX frame + * | | in any past or future channel sample) + * | | + * | | CSL_PERIOD (>0) RX_SLOT + * | | | | + * v v v v + * -----------------------------------------------[-CSL channel sample ]----+ + * ^ | + * | | + * +--------------------- loop ---------+ + * + * Disable CSL on the receiver: + * + * CSL_PERIOD (=0) + * | + * v + * --------------------- + * + * Update the CSL period to a new value: + * + * EXPECTED_RX_TIME (based on updated period) + * | + * | CSL_PERIOD (>0, updated) RX_SLOT + * | | | + * v v v + * -----------------------------------------------[-CSL channel sample ]----+ + * ^ | + * | | + * +--------------------- loop ---------+ * * @note Available in any interface operational state. * - * @warning This configuration option does not conform to the - * requirements specified in #61227 as it is incompatible with standard - * primitives and may therefore be deprecated in the future. + * @note Required for Thread 1.2 Coordinated Sampled Listening feature + * (see Thread specification 1.2.0, ch. 3.2.6.3). */ IEEE802154_CONFIG_CSL_PERIOD, /** - * @brief Configure the next CSL receive window (i.e. "channel sample") - * center, in units of nanoseconds relative to the network subsystem's - * local clock. + * Configure a timepoint at which an RX frame is expected to arrive. + * + * @details Configure the nanosecond resolution timepoint relative to + * the network subsystem's local clock at which an RX frame's end of SFD + * (i.e. equivalently its end of SHR, start of PHR, or in the case of + * PHYs with RDEV or ERDEV capability the RMARKER) is expected to arrive + * at the local antenna assuming perfectly synchronized local and remote + * network clocks and zero distance between antennas. + * + * This parameter MAY be used to offload parts of timing sensitive TDMA + * (e.g. TSCH, beacon-enabled PAN including DSME), low-energy (e.g. + * CSL, RIT) or ranging (TDoA) protocols to the driver. In these + * protocols, medium access is tightly controlled such that the expected + * arrival time of a frame can be predicted within a well-defined time + * window. This feature will typically be combined with @ref + * IEEE802154_CONFIG_RX_SLOT although this is not a hard requirement. + * + * The "expected RX time" MAY be interpreted slightly differently + * depending on the protocol context: + * - CSL phase (i.e. time to the next expected CSL transmission) or anchor + * time (i.e. any arbitrary timepoint with "zero CSL phase") SHALL be + * derived by adding the PHY header duration to the expected RX time + * to calculate the "start of MHR" ("first symbol of MAC", see section + * 6.12.2.1) required by the CSL protocol, compare @ref + * IEEE802154_CONFIG_CSL_PERIOD. + * - In TSCH the expected RX time MAY be set to macTsRxOffset + + * macTsRxWait / 2. Then the time correction SHALL be calculated as + * the expected RX time minus actual arrival timestamp, see section + * 6.5.4.3. + * - In ranging applications, time difference of arrival (TDOA) MAY be + * calculated inside the driver comparing actual RMARKER timestamps + * against the assumed synchronized time at which the ranging frame + * was sent, see IEEE 802.15.4z. + * + * In case of periodic protocols (e.g. CSL channel samples, periodic + * beacons of a single PAN, periodic ranging "blinks"), a single + * timestamp at any time in the past or in the future may be given from + * which other expected timestamps can be derived by adding or + * substracting multiples of the RX period. See e.g. the CSL + * documentation in this API. + * + * Additionally this parameter MAY be used by drivers to discipline + * their local representation of a distributed network clock by deriving + * synchronization instants related to a remote representation of the + * same clock (as in PTP). * * @note Available in any interface operational state. * - * @warning This configuration option does not conform to the - * requirements specified in #61227 as it is incompatible with standard - * primitives and may therefore be deprecated in the future. + * @note Required for Thread 1.2 Coordinated Sampled Listening feature + * (see Thread specification 1.2.0, ch. 3.2.6.3). */ - IEEE802154_CONFIG_CSL_RX_TIME, + IEEE802154_CONFIG_EXPECTED_RX_TIME, /** - * Indicates whether to inject IE into ENH ACK Frame for specific address - * or not. Disabling the ENH ACK with no address provided (NULL pointer) - * should disable it for all enabled addresses. - * - * @note Available in any interface operational state. - * - * @warning This configuration option does not conform to the - * requirements specified in #61227 as it is incompatible with standard - * primitives and may therefore be modified in the future. + * Adds a header information element (IE) to be injected into enhanced + * ACK frames generated by the driver if the given destination address + * filter matches. + * + * @details Drivers implementing the @ref IEEE802154_HW_RX_TX_ACK + * capability generate ACK frames autonomously. Setting this + * configuration will ask the driver to inject the given preconfigured + * header IE when generating enhanced ACK frames where appropriate by + * the standard. IEs for all other frame types SHALL be provided by L2. + * + * The driver shall return -ENOTSUP in the following cases: + * - It does not support the @ref IEEE802154_HW_RX_TX_ACK, + * - It does not support header IE injection, + * - It cannot inject the runtime fields on-the-fly required for the + * given IE element ID (see list below). + * + * Enhanced ACK header IEs (element IDs in parentheses) that either + * need to be rejected or explicitly supported and parsed by the driver + * because they require on-the-fly timing information injection are: + * - CSL IE (0x1a) + * - Rendezvous Time IE (0x1d) + * - Time Correction IE (0x1e) + * + * Drivers accepting this configuration option SHALL check the list of + * configured IEs for each outgoing enhanced ACK frame, select the ones + * appropriate for the received frame based on their element ID, inject + * any required runtime information on-the-fly and include the selected + * IEs into the enhanced ACK frame's MAC header. + * + * Drivers supporting enhanced ACK header IE injection SHALL + * autonomously inject header termination IEs as required by the + * standard. + * + * A destination short address and extended address MAY be given by L2 + * to filter the devices to which the given IE is included. Setting the + * short address to the broadcast address and the extended address to + * NULL will inject the given IE into all ACK frames unless a more + * specific filter is also present for any given destination device + * (fallback configuration). L2 SHALL take care to either set both + * address fields to valid device addresses or none. + * + * This configuration type may be called several times with distinct + * element IDs and/or addresses. The driver SHALL either store all + * configured IE/address combinations or return -ENOMEM if no + * additional configuration can be stored. + * + * Configuring a header IE with a previously configured element ID and + * address filter SHALL override the previous configuration. This + * implies that repetition of the same header IE/address combination is + * NOT supported. + * + * Configuring an existing element ID/address filter combination with + * the header IE's length field set to zero SHALL remove that + * configuration. SHALL remove the fallback configuration if no address + * is given. + * + * Configuring a header IE for an address filter with the header IE + * pointer set to NULL SHALL remove all header IE's for that address + * filter. SHALL remove ALL header IE configuration (including but not + * limited to fallbacks) if no address is given. + * + * If any of the deleted configurations didn't previously exist, then + * the call SHALL be ignored. Whenever the length field is set to zero, + * the content fields MUST NOT be accessed by the driver. + * + * L2 SHALL minimize the space required to keep IE configuration inside + * the driver by consolidating address filters and by removing + * configuation that is no longer required. + * + * @note requires @ref IEEE802154_HW_RX_TX_ACK capability and is + * available in any interface operational state. Currently we only + * support header IEs but that may change in the future. + * + * @note Required for Thread 1.2 Coordinated Sampled Listening feature + * (see Thread specification 1.2.0, ch. 3.2.6.3). + * + * @note Required for Thread 1.2 Link Metrics feature (see Thread + * specification 1.2.0, ch. 4.11.3.3). */ IEEE802154_CONFIG_ENH_ACK_HEADER_IE, + /** + * Enable/disable RxOnWhenIdle MAC PIB attribute (Table 8-94). + * + * Since there is no clear guidance in IEEE 802.15.4 specification about the definition of + * an "idle period", this implementation expects that drivers use the RxOnWhenIdle attribute + * to determine next radio state (false --> off, true --> receive) in the following + * scenarios: + * - Finalization of a regular frame reception task, provided that: + * - The frame is received without errors and passes the filtering and it's not an + * spurious ACK. + * - ACK is not requested or transmission of ACK is not possible due to internal + * conditions. + * - Finalization of a frame transmission or transmission of an ACK frame, when ACK is not + * requested in the transmitted frame. + * - Finalization of the reception operation of a requested ACK due to: + * - ACK timeout expiration. + * - Reception of an invalid ACK or not an ACK frame. + * - Reception of the proper ACK, unless the transmitted frame was a Data Request Command + * and the frame pending bit on the received ACK is set to true. In this case the radio + * platform implementation SHOULD keep the receiver on until a determined timeout which + * triggers an idle period start. + * - Finalization of a stand alone CCA task. + * - Finalization of a CCA operation with busy result during CSMA/CA procedure. + * - Finalization of an Energy Detection task. + * - Finalization of a scheduled radio reception window + * (see @ref IEEE802154_CONFIG_RX_SLOT). + */ + IEEE802154_CONFIG_RX_ON_WHEN_IDLE, + /** Number of types defined in ieee802154_config_type. */ IEEE802154_CONFIG_COMMON_COUNT, @@ -872,6 +1140,9 @@ struct ieee802154_config { /** see @ref IEEE802154_CONFIG_PROMISCUOUS */ bool promiscuous; + /** see @ref IEEE802154_CONFIG_RX_ON_WHEN_IDLE */ + bool rx_on_when_idle; + /** see @ref IEEE802154_CONFIG_EVENT_HANDLER */ ieee802154_event_cb_t event_handler; @@ -927,52 +1198,58 @@ struct ieee802154_config { /** * see @ref IEEE802154_CONFIG_CSL_PERIOD * - * The CSL period in units of 10 symbol periods, - * see section 7.4.2.3. - * * in CPU byte order */ uint32_t csl_period; /** - * see @ref IEEE802154_CONFIG_CSL_RX_TIME - * - * Nanosecond resolution timestamp relative to the network - * subsystem's local clock defining the center of the CSL RX window - * at which the receiver is expected to be fully started up - * (i.e. not including any startup times). + * see @ref IEEE802154_CONFIG_EXPECTED_RX_TIME */ - net_time_t csl_rx_time; + net_time_t expected_rx_time; /** see @ref IEEE802154_CONFIG_ENH_ACK_HEADER_IE */ struct { /** - * Header IEs to be added to the Enh-Ack frame. + * Pointer to the header IE, see section 7.4.2.1, + * figure 7-21 * - * in little endian + * Certain header IEs may be incomplete if they require + * timing information to be injected at runtime + * on-the-fly, see the list in @ref + * IEEE802154_CONFIG_ENH_ACK_HEADER_IE. */ - const uint8_t *data; + struct ieee802154_header_ie *header_ie; - /** length of the header IEs */ - uint16_t data_len; + /** + * Filters the devices that will receive this IE by + * extended address. MAY be set to NULL to configure a + * fallback for all devices (implies that short_addr + * MUST also be set to @ref + * IEEE802154_BROADCAST_ADDRESS). + * + * in big endian + */ + const uint8_t *ext_addr; /** * Filters the devices that will receive this IE by * short address. MAY be set to @ref - * IEEE802154_BROADCAST_ADDRESS to disable the filter. + * IEEE802154_BROADCAST_ADDRESS to configure a fallback + * for all devices (implies that ext_addr MUST also set + * to NULL in this case). * * in CPU byte order */ uint16_t short_addr; /** - * Filters the devices that will receive this IE by - * extended address. MAY be set to NULL to disable the - * filter. - * - * in big endian + * Flag for purging enh ACK header IEs. + * When flag is set to true, driver should remove all existing + * header IEs, and all other entries in config should be ignored. + * This means that purging current header IEs and + * configuring a new one in the same call is not allowed. */ - const uint8_t *ext_addr; + bool purge_ie; } ack_ie; }; }; diff --git a/include/zephyr/net/ieee802154_radio_openthread.h b/include/zephyr/net/ieee802154_radio_openthread.h index 39a316b325105c6..f6f9949d328feb1 100644 --- a/include/zephyr/net/ieee802154_radio_openthread.h +++ b/include/zephyr/net/ieee802154_radio_openthread.h @@ -79,6 +79,17 @@ enum ieee802154_openthread_config_type { IEEE802154_OPENTHREAD_CONFIG_MAX_EXTRA_CCA_ATTEMPTS = IEEE802154_CONFIG_PRIV_START }; +/** + * Thread vendor OUI for vendor specific header or nested information elements, + * see IEEE 802.15.4-2020, sections 7.4.2.2 and 7.4.4.30. + * + * in little endian + */ +#define IEEE802154_OPENTHREAD_THREAD_IE_VENDOR_OUI { 0x9b, 0xb8, 0xea } + +/** length of IEEE 802.15.4-2020 vendor OUIs */ +#define IEEE802154_OPENTHREAD_VENDOR_OUI_LEN 3 + /** OpenThread specific configuration data of ieee802154 driver. */ struct ieee802154_openthread_config { union { diff --git a/include/zephyr/net/igmp.h b/include/zephyr/net/igmp.h index 7119676f237de4c..ed39a31359f2b04 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/lwm2m.h b/include/zephyr/net/lwm2m.h index 6262f6d103df86c..c643c32f0bf155b 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -49,6 +49,7 @@ #define LWM2M_OBJECT_PORTFOLIO_ID 16 /**< Portfolio object */ #define LWM2M_OBJECT_BINARYAPPDATACONTAINER_ID 19 /**< Binary App Data Container object */ #define LWM2M_OBJECT_EVENT_LOG_ID 20 /**< Event Log object */ +#define LWM2M_OBJECT_OSCORE_ID 21 /**< OSCORE object */ #define LWM2M_OBJECT_GATEWAY_ID 25 /**< Gateway object */ /* clang-format on */ @@ -133,6 +134,22 @@ typedef void (*lwm2m_ctx_event_cb_t)(struct lwm2m_ctx *ctx, enum lwm2m_rd_client_event event); +/** + * @brief Different traffic states of the LwM2M socket. + * + * This information can be used to give hints for the network interface + * that can decide what kind of power management should be used. + * + * These hints are given from CoAP layer messages, so usage of DTLS might affect the + * actual number of expected datagrams. + */ +enum lwm2m_socket_states { + LWM2M_SOCKET_STATE_ONGOING, /**< Ongoing traffic is expected. */ + LWM2M_SOCKET_STATE_ONE_RESPONSE, /**< One response is expected for the next message. */ + LWM2M_SOCKET_STATE_LAST, /**< Next message is the last one. */ + LWM2M_SOCKET_STATE_NO_DATA, /**< No more data is expected. */ +}; + /** * @brief LwM2M context structure to maintain information for a single * LwM2M connection. @@ -248,6 +265,14 @@ struct lwm2m_ctx { * copied into the actual resource buffer. */ uint8_t validate_buf[CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE]; + + /** + * Callback to indicate transmission states. + * Client application may request LwM2M engine to indicate hints about + * transmission states and use that information to control various power + * saving modes. + */ + void (*set_socket_state)(int fd, enum lwm2m_socket_states state); }; /** @@ -550,7 +575,6 @@ void lwm2m_firmware_set_cancel_cb_inst(uint16_t obj_inst_id, lwm2m_engine_user_c */ lwm2m_engine_user_cb_t lwm2m_firmware_get_cancel_cb_inst(uint16_t obj_inst_id); -#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT) || defined(__DOXYGEN__) /** * @brief Set data callback to handle firmware update execute events. * @@ -587,8 +611,6 @@ void lwm2m_firmware_set_update_cb_inst(uint16_t obj_inst_id, lwm2m_engine_execut */ lwm2m_engine_execute_cb_t lwm2m_firmware_get_update_cb_inst(uint16_t obj_inst_id); #endif -#endif - #if defined(CONFIG_LWM2M_SWMGMT_OBJ_SUPPORT) || defined(__DOXYGEN__) @@ -987,11 +1009,16 @@ int lwm2m_engine_set_u64(const char *pathstr, uint64_t value); /** * @brief Set resource (instance) value (u64) * + * @deprecated Unsigned 64bit value type does not exits. + * This is internally handled as a int64_t. + * Use lwm2m_set_s64() instead. + * * @param[in] path LwM2M path as a struct * @param[in] value u64 value * * @return 0 for success or negative in case of error. */ +__deprecated int lwm2m_set_u64(const struct lwm2m_obj_path *path, uint64_t value); /** @@ -1313,11 +1340,16 @@ int lwm2m_engine_get_u64(const char *pathstr, uint64_t *value); /** * @brief Get resource (instance) value (u64) * + * @deprecated Unsigned 64bit value type does not exits. + * This is internally handled as a int64_t. + * Use lwm2m_get_s64() instead. + * @param[in] path LwM2M path as a struct * @param[out] value u64 buffer to copy data into * * @return 0 for success or negative in case of error. */ +__deprecated int lwm2m_get_u64(const struct lwm2m_obj_path *path, uint64_t *value); /** @@ -2074,6 +2106,7 @@ enum lwm2m_rd_client_event { LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR, LWM2M_RD_CLIENT_EVENT_REG_UPDATE, LWM2M_RD_CLIENT_EVENT_DEREGISTER, + LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED, }; /** diff --git a/include/zephyr/net/mdio.h b/include/zephyr/net/mdio.h index e7161a7a7668cb2..8d1998f7cec93eb 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 7700558f1fefc40..cb1a6d3373123a1 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 78a88aec0fe444e..55548917c458e57 100644 --- a/include/zephyr/net/net_context.h +++ b/include/zephyr/net/net_context.h @@ -300,34 +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; @@ -342,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); @@ -359,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); @@ -669,39 +710,157 @@ static inline void net_context_set_iface(struct net_context *context, context->iface = net_if_get_by_iface(iface); } +/** + * @brief Bind network interface to this context. + * + * @details This function binds network interface to this context. + * + * @param context Network context. + * @param iface Network interface. + */ +static inline void net_context_bind_iface(struct net_context *context, + struct net_if *iface) +{ + NET_ASSERT(iface); + + context->flags |= NET_CONTEXT_BOUND_TO_IFACE; + 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) @@ -709,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; @@ -1071,16 +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_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 34856aec6af3645..b717c2eec457772 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 82a1447b4f93a61..d849451d0c2bf1c 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; @@ -106,7 +117,7 @@ struct net_if_mcast_addr { /** * @brief Network Interface IPv6 prefixes * - * Stores the multicast IP addresses assigned to this network interface. + * Stores the IPV6 prefixes assigned to this network interface. */ struct net_if_ipv6_prefix { /** Prefix lifetime */ @@ -212,6 +223,9 @@ enum net_if_flag { /** IPv6 Multicast Listener Discovery disabled. */ NET_IF_IPV6_NO_MLD, + /** Mutex locking on TX data path disabled on the interface. */ + NET_IF_NO_TX_LOCK, + /** @cond INTERNAL_HIDDEN */ /* Total number of flags - must be at the end of the enum */ NET_IF_NUM_FLAGS @@ -276,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) @@ -366,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) @@ -613,6 +633,7 @@ struct net_if { #endif struct k_mutex lock; + struct k_mutex tx_lock; }; static inline void net_if_lock(struct net_if *iface) @@ -629,6 +650,31 @@ static inline void net_if_unlock(struct net_if *iface) k_mutex_unlock(&iface->lock); } +static inline bool net_if_flag_is_set(struct net_if *iface, + enum net_if_flag value); + +static inline void net_if_tx_lock(struct net_if *iface) +{ + NET_ASSERT(iface); + + if (net_if_flag_is_set(iface, NET_IF_NO_TX_LOCK)) { + return; + } + + (void)k_mutex_lock(&iface->tx_lock, K_FOREVER); +} + +static inline void net_if_tx_unlock(struct net_if *iface) +{ + NET_ASSERT(iface); + + if (net_if_flag_is_set(iface, NET_IF_NO_TX_LOCK)) { + return; + } + + k_mutex_unlock(&iface->tx_lock); +} + /** * @brief Set a value in network interface flags * @@ -1354,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, @@ -1409,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); @@ -1632,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 @@ -1876,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. * @@ -2188,6 +2279,15 @@ struct in_addr *net_if_ipv4_get_ll(struct net_if *iface, struct in_addr *net_if_ipv4_get_global_addr(struct net_if *iface, enum net_addr_state addr_state); +/** + * @brief Get IPv4 netmask of an interface. + * + * @param iface Interface to use. + * + * @return The netmask set on the interface, unspecified address if not found. + */ +struct in_addr net_if_ipv4_get_netmask(struct net_if *iface); + /** * @brief Set IPv4 netmask for an interface. * @@ -2708,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 @@ -2993,6 +3092,20 @@ struct net_if_api { #define NET_DEVICE_DT_INST_OFFLOAD_DEFINE(inst, ...) \ NET_DEVICE_DT_OFFLOAD_DEFINE(DT_DRV_INST(inst), __VA_ARGS__) +/** + * @brief Count the number of network interfaces. + * + * @param[out] _dst Pointer to location where result is written. + */ +#define NET_IFACE_COUNT(_dst) \ + do { \ + extern struct net_if _net_if_list_start[]; \ + extern struct net_if _net_if_list_end[]; \ + *(_dst) = ((uintptr_t)_net_if_list_end - \ + (uintptr_t)_net_if_list_start) / \ + sizeof(struct net_if); \ + } while (0) + #ifdef __cplusplus } #endif diff --git a/include/zephyr/net/net_ip.h b/include/zephyr/net/net_ip.h index 6c78428c1c7b5a8..75f75aa1f426d24 100644 --- a/include/zephyr/net/net_ip.h +++ b/include/zephyr/net/net_ip.h @@ -423,11 +423,11 @@ enum net_priority { NET_PRIORITY_BK = 1, /**< Background (lowest) */ NET_PRIORITY_BE = 0, /**< Best effort (default) */ NET_PRIORITY_EE = 2, /**< Excellent effort */ - NET_PRIORITY_CA = 3, /**< Critical applications (highest) */ + NET_PRIORITY_CA = 3, /**< Critical applications */ NET_PRIORITY_VI = 4, /**< Video, < 100 ms latency and jitter */ NET_PRIORITY_VO = 5, /**< Voice, < 10 ms latency and jitter */ NET_PRIORITY_IC = 6, /**< Internetwork control */ - NET_PRIORITY_NC = 7 /**< Network control */ + NET_PRIORITY_NC = 7 /**< Network control (highest) */ } __packed; #define NET_MAX_PRIORITIES 8 /* How many priority values there are */ @@ -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. * @@ -1239,6 +1264,39 @@ static inline void net_ipv6_addr_create_ll_allrouters_mcast(struct in6_addr *add net_ipv6_addr_create(addr, 0xff02, 0, 0, 0, 0, 0, 0, 0x0002); } +/** + * @brief Create IPv4 mapped IPv6 address + * + * @param addr4 IPv4 address + * @param addr6 IPv6 address to be created + */ +static inline void net_ipv6_addr_create_v4_mapped(const struct in_addr *addr4, + struct in6_addr *addr6) +{ + net_ipv6_addr_create(addr6, 0, 0, 0, 0, 0, 0xffff, + ntohs(addr4->s4_addr16[0]), + ntohs(addr4->s4_addr16[1])); +} + +/** + * @brief Is the IPv6 address an IPv4 mapped one. The v4 mapped addresses + * look like \::ffff:a.b.c.d + * + * @param addr IPv6 address + * + * @return True if IPv6 address is a IPv4 mapped address, False otherwise. + */ +static inline bool net_ipv6_addr_is_v4_mapped(const struct in6_addr *addr) +{ + if (UNALIGNED_GET(&addr->s6_addr32[0]) == 0 && + UNALIGNED_GET(&addr->s6_addr32[1]) == 0 && + UNALIGNED_GET(&addr->s6_addr16[5]) == 0xffff) { + return true; + } + + return false; +} + /** * @brief Create IPv6 address interface identifier * diff --git a/include/zephyr/net/net_mgmt.h b/include/zephyr/net/net_mgmt.h index 8d8710edd26e0f7..f90bc8e18364646 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 4931f95009d5ec8..c5878213a0293e2 100644 --- a/include/zephyr/net/net_pkt.h +++ b/include/zephyr/net/net_pkt.h @@ -194,7 +194,12 @@ struct net_pkt { uint8_t l2_processed : 1; /* Set to 1 if this packet has already been * processed by the L2 */ - + uint8_t chksum_done : 1; /* Checksum has already been computed for + * the packet. + */ +#if defined(CONFIG_NET_IP_FRAGMENT) + uint8_t ip_reassembled : 1; /* Packet is a reassembled IP packet. */ +#endif /* bitfield byte alignment boundary */ #if defined(CONFIG_NET_IP) @@ -219,7 +224,7 @@ struct net_pkt { #endif }; -#if defined(CONFIG_NET_IPV4_FRAGMENT) || defined(CONFIG_NET_IPV6_FRAGMENT) +#if defined(CONFIG_NET_IP_FRAGMENT) union { #if defined(CONFIG_NET_IPV4_FRAGMENT) struct { @@ -235,7 +240,7 @@ struct net_pkt { } ipv6_fragment; #endif /* CONFIG_NET_IPV6_FRAGMENT */ }; -#endif /* CONFIG_NET_IPV4_FRAGMENT || CONFIG_NET_IPV6_FRAGMENT */ +#endif /* CONFIG_NET_IP_FRAGMENT */ #if defined(CONFIG_NET_IPV6) /* Where is the start of the last header before payload data @@ -398,6 +403,17 @@ static inline void net_pkt_set_l2_processed(struct net_pkt *pkt, pkt->l2_processed = is_l2_processed; } +static inline bool net_pkt_is_chksum_done(struct net_pkt *pkt) +{ + return !!(pkt->chksum_done); +} + +static inline void net_pkt_set_chksum_done(struct net_pkt *pkt, + bool is_chksum_done) +{ + pkt->chksum_done = is_chksum_done; +} + static inline uint8_t net_pkt_ip_hdr_len(struct net_pkt *pkt) { #if defined(CONFIG_NET_IP) @@ -822,6 +838,33 @@ static inline void net_pkt_set_ipv6_fragment_id(struct net_pkt *pkt, } #endif /* CONFIG_NET_IPV6_FRAGMENT */ +#if defined(CONFIG_NET_IP_FRAGMENT) +static inline bool net_pkt_is_ip_reassembled(struct net_pkt *pkt) +{ + return !!(pkt->ip_reassembled); +} + +static inline void net_pkt_set_ip_reassembled(struct net_pkt *pkt, + bool reassembled) +{ + pkt->ip_reassembled = reassembled; +} +#else /* CONFIG_NET_IP_FRAGMENT */ +static inline bool net_pkt_is_ip_reassembled(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return false; +} + +static inline void net_pkt_set_ip_reassembled(struct net_pkt *pkt, + bool reassembled) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(reassembled); +} +#endif /* CONFIG_NET_IP_FRAGMENT */ + static inline uint8_t net_pkt_priority(struct net_pkt *pkt) { return pkt->priority; @@ -1664,6 +1707,13 @@ int net_pkt_alloc_buffer_debug(struct net_pkt *pkt, net_pkt_alloc_buffer_debug(_pkt, _size, _proto, _timeout, \ __func__, __LINE__) +int net_pkt_alloc_buffer_raw_debug(struct net_pkt *pkt, size_t size, + k_timeout_t timeout, + const char *caller, int line); +#define net_pkt_alloc_buffer_raw(_pkt, _size, _timeout) \ + net_pkt_alloc_buffer_raw_debug(_pkt, _size, _timeout, \ + __func__, __LINE__) + struct net_pkt *net_pkt_alloc_with_buffer_debug(struct net_if *iface, size_t size, sa_family_t family, @@ -1778,6 +1828,24 @@ int net_pkt_alloc_buffer(struct net_pkt *pkt, k_timeout_t timeout); #endif +/** + * @brief Allocate buffer for a net_pkt, of specified size, w/o any additional + * preconditions + * + * @details: The actual buffer size may be larger than requested one if fixed + * size buffers are in use. + * + * @param pkt The network packet requiring buffer to be allocated. + * @param size The size of buffer being requested. + * @param timeout Maximum time to wait for an allocation. + * + * @return 0 on success, negative errno code otherwise. + */ +#if !defined(NET_PKT_DEBUG_ENABLED) +int net_pkt_alloc_buffer_raw(struct net_pkt *pkt, size_t size, + k_timeout_t timeout); +#endif + /** * @brief Allocate a network packet and buffer at once * diff --git a/include/zephyr/net/phy.h b/include/zephyr/net/phy.h index 40de7137276a193..38c6d1f5bbe715c 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 a72d4f1feac579e..36c6bf64eebf311 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 cb83675a3cdbf7d..c03c3a11206144e 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 f12622e5df5023a..bdbbd3b19e584ba 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -35,16 +35,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 @@ -54,9 +63,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 */ @@ -65,7 +82,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. @@ -76,16 +98,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 @@ -134,11 +161,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 @@ -200,48 +232,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 */ }; /** @@ -466,6 +515,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 * @@ -653,6 +716,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 */ @@ -667,6 +734,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 @@ -712,6 +780,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. */ @@ -729,6 +801,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 @@ -748,6 +821,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 */ @@ -811,6 +890,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. @@ -827,7 +907,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; @@ -862,6 +944,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) { @@ -925,6 +1013,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 */ @@ -959,6 +1048,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 */ @@ -993,8 +1084,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 @@ -1003,98 +1100,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; +}; + +/** 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 -/** listen: The maximum backlog queue length (ignored, for compatibility) */ +/** + * @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 */ /** @@ -1105,6 +1311,12 @@ struct net_socket_register { bool is_offloaded; bool (*is_supported)(int family, int type, int proto); int (*handler)(int family, int type, int proto); +#if defined(CONFIG_NET_SOCKETS_OBJ_CORE) + /* Store also the name of the socket type in order to be able to + * print it later. + */ + const char * const name; +#endif }; #define NET_SOCKET_DEFAULT_PRIO CONFIG_NET_SOCKETS_PRIORITY_DEFAULT @@ -1112,6 +1324,15 @@ struct net_socket_register { #define NET_SOCKET_GET_NAME(socket_name, prio) \ __net_socket_register_##prio##_##socket_name +#if defined(CONFIG_NET_SOCKETS_OBJ_CORE) +#define K_OBJ_TYPE_SOCK K_OBJ_TYPE_ID_GEN("SOCK") + +#define NET_SOCKET_REGISTER_NAME(_name) \ + .name = STRINGIFY(_name), +#else +#define NET_SOCKET_REGISTER_NAME(_name) +#endif + #define _NET_SOCKET_REGISTER(socket_name, prio, _family, _is_supported, _handler, _is_offloaded) \ static const STRUCT_SECTION_ITERABLE(net_socket_register, \ NET_SOCKET_GET_NAME(socket_name, prio)) = { \ @@ -1119,6 +1340,7 @@ struct net_socket_register { .is_offloaded = _is_offloaded, \ .is_supported = _is_supported, \ .handler = _handler, \ + NET_SOCKET_REGISTER_NAME(socket_name) \ } #define NET_SOCKET_REGISTER(socket_name, prio, _family, _is_supported, _handler) \ diff --git a/include/zephyr/net/socket_service.h b/include/zephyr/net/socket_service.h new file mode 100644 index 000000000000000..a4e21f00a333540 --- /dev/null +++ b/include/zephyr/net/socket_service.h @@ -0,0 +1,246 @@ +/** + * @file + * @brief BSD Socket service API + * + * API can be used to install a k_work that is called + * if there is data received to a socket. + */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_NET_SOCKET_SERVICE_H_ +#define ZEPHYR_INCLUDE_NET_SOCKET_SERVICE_H_ + +/** + * @brief BSD socket service API + * @defgroup bsd_socket_service BSD socket service API + * @ingroup networking + * @{ + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This struct contains information which socket triggered + * calls to the callback function. + */ +struct net_socket_service_event { + /** k_work that is done when there is desired activity in file descriptor. */ + struct k_work work; + /** Callback to be called for desired socket activity */ + k_work_handler_t callback; + /** Socket information that triggered this event. */ + struct zsock_pollfd event; + /** User data */ + void *user_data; + /** Service back pointer */ + struct net_socket_service_desc *svc; +}; + +/** + * Main structure holding socket service configuration information. + * The k_work item is created so that when there is data coming + * to those fds, the k_work callback is then called. + * The workqueue can be set NULL in which case system workqueue is used. + * The service descriptor should be created at built time, and then used + * as a parameter to register the sockets to be monitored. + * User should create needed sockets and then setup the poll struct and + * then register the sockets to be monitored at runtime. + */ +struct net_socket_service_desc { +#if CONFIG_NET_SOCKETS_LOG_LEVEL >= LOG_LEVEL_DBG + /** + * Owner name. This can be used in debugging to see who has + * registered this service. + */ + const char *owner; +#endif + /** Workqueue where the work is submitted. */ + struct k_work_q *work_q; + /** Pointer to the list of services that we are listening */ + struct net_socket_service_event *pev; + /** Length of the pollable socket array for this service. */ + int pev_len; + /** Where are my pollfd entries in the global list */ + int *idx; +}; + +#define __z_net_socket_svc_get_name(_svc_id) __z_net_socket_service_##_svc_id +#define __z_net_socket_svc_get_idx(_svc_id) __z_net_socket_service_idx_##_svc_id +#define __z_net_socket_svc_get_owner __FILE__ ":" STRINGIFY(__LINE__) + +extern void net_socket_service_callback(struct k_work *work); + +#if CONFIG_NET_SOCKETS_LOG_LEVEL >= LOG_LEVEL_DBG +#define NET_SOCKET_SERVICE_OWNER .owner = __z_net_socket_svc_get_owner, +#else +#define NET_SOCKET_SERVICE_OWNER +#endif + +#define NET_SOCKET_SERVICE_CALLBACK_MODE(_flag) \ + IF_ENABLED(_flag, \ + (.work = Z_WORK_INITIALIZER(net_socket_service_callback),)) + +#define __z_net_socket_service_define(_name, _work_q, _cb, _count, _async, ...) \ + static int __z_net_socket_svc_get_idx(_name); \ + static struct net_socket_service_event \ + __z_net_socket_svc_get_name(_name)[_count] = { \ + [0 ... ((_count) - 1)] = { \ + .event.fd = -1, /* Invalid socket */ \ + NET_SOCKET_SERVICE_CALLBACK_MODE(_async) \ + .callback = _cb, \ + } \ + }; \ + COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (), __VA_ARGS__) \ + const STRUCT_SECTION_ITERABLE(net_socket_service_desc, _name) = { \ + NET_SOCKET_SERVICE_OWNER \ + .work_q = (_work_q), \ + .pev = __z_net_socket_svc_get_name(_name), \ + .pev_len = (_count), \ + .idx = &__z_net_socket_svc_get_idx(_name), \ + } + +/** + * @brief Statically define a network socket service. + * The user callback is called asynchronously for this service meaning that + * the service API will not wait until the user callback returns before continuing + * with next socket service. + * + * The socket service can be accessed outside the module where it is defined using: + * + * @code extern struct net_socket_service_desc ; @endcode + * + * @note This macro cannot be used together with a static keyword. + * If such a use-case is desired, use NET_SOCKET_SERVICE_ASYNC_DEFINE_STATIC + * instead. + * + * @param name Name of the service. + * @param work_q Pointer to workqueue where the work is done. Can be null in which case + * system workqueue is used. + * @param cb Callback function that is called for socket activity. + * @param count How many pollable sockets is needed for this service. + */ +#define NET_SOCKET_SERVICE_ASYNC_DEFINE(name, work_q, cb, count) \ + __z_net_socket_service_define(name, work_q, cb, count, 1) + +/** + * @brief Statically define a network socket service in a private (static) scope. + * The user callback is called asynchronously for this service meaning that + * the service API will not wait until the user callback returns before continuing + * with next socket service. + * + * @param name Name of the service. + * @param work_q Pointer to workqueue where the work is done. Can be null in which case + * system workqueue is used. + * @param cb Callback function that is called for socket activity. + * @param count How many pollable sockets is needed for this service. + */ +#define NET_SOCKET_SERVICE_ASYNC_DEFINE_STATIC(name, work_q, cb, count) \ + __z_net_socket_service_define(name, work_q, cb, count, 1, static) + +/** + * @brief Statically define a network socket service. + * The user callback is called synchronously for this service meaning that + * the service API will wait until the user callback returns before continuing + * with next socket service. + * + * The socket service can be accessed outside the module where it is defined using: + * + * @code extern struct net_socket_service_desc ; @endcode + * + * @note This macro cannot be used together with a static keyword. + * If such a use-case is desired, use NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC + * instead. + * + * @param name Name of the service. + * @param work_q Pointer to workqueue where the work is done. Can be null in which case + * system workqueue is used. + * @param cb Callback function that is called for socket activity. + * @param count How many pollable sockets is needed for this service. + */ +#define NET_SOCKET_SERVICE_SYNC_DEFINE(name, work_q, cb, count) \ + __z_net_socket_service_define(name, work_q, cb, count, 0) + +/** + * @brief Statically define a network socket service in a private (static) scope. + * The user callback is called synchronously for this service meaning that + * the service API will wait until the user callback returns before continuing + * with next socket service. + * + * @param name Name of the service. + * @param work_q Pointer to workqueue where the work is done. Can be null in which case + * system workqueue is used. + * @param cb Callback function that is called for socket activity. + * @param count How many pollable sockets is needed for this service. + */ +#define NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(name, work_q, cb, count) \ + __z_net_socket_service_define(name, work_q, cb, count, 0, static) + +/** + * @brief Register pollable sockets. + * + * @param service Pointer to a service description. + * @param fds Socket array to poll. + * @param len Length of the socket array. + * @param user_data User specific data. + * + * @retval 0 No error + * @retval -ENOENT Service is not found. + * @retval -ENINVAL Invalid parameter. + */ +__syscall int net_socket_service_register(const struct net_socket_service_desc *service, + struct zsock_pollfd *fds, int len, void *user_data); + +/** + * @brief Unregister pollable sockets. + * + * @param service Pointer to a service description. + * + * @retval 0 No error + * @retval -ENOENT Service is not found. + * @retval -ENINVAL Invalid parameter. + */ +static inline int net_socket_service_unregister(const struct net_socket_service_desc *service) +{ + return net_socket_service_register(service, NULL, 0, NULL); +} + +/** + * @typedef net_socket_service_cb_t + * @brief Callback used while iterating over socket services. + * + * @param svc Pointer to current socket service. + * @param user_data A valid pointer to user data or NULL + */ +typedef void (*net_socket_service_cb_t)(const struct net_socket_service_desc *svc, + void *user_data); + +/** + * @brief Go through all the socket services and call callback for each service. + * + * @param cb User-supplied callback function to call + * @param user_data User specified data + */ +void net_socket_service_foreach(net_socket_service_cb_t cb, void *user_data); + +#ifdef __cplusplus +} +#endif + +#include + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_NET_SOCKET_SERVICE_H_ */ diff --git a/include/zephyr/net/socketcan.h b/include/zephyr/net/socketcan.h index 29ec5b3638dbca9..c4916487d9971b1 100644 --- a/include/zephyr/net/socketcan.h +++ b/include/zephyr/net/socketcan.h @@ -49,7 +49,7 @@ enum { #define CAN_MTU (sizeof(struct socketcan_frame)) #endif /* !CONFIG_CAN_FD_MODE */ -/* CAN-FD specific flags from Linux Kernel (include/uapi/linux/can.h) */ +/* CAN FD specific flags from Linux Kernel (include/uapi/linux/can.h) */ #define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */ #define CANFD_ESI 0x02 /* error state indicator of the transmitting node */ #define CANFD_FDF 0x04 /* mark CAN FD for dual use of struct canfd_frame */ diff --git a/include/zephyr/net/socketcan_utils.h b/include/zephyr/net/socketcan_utils.h index 22364cd328baa29..7db287ff84726af 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/tls_credentials.h b/include/zephyr/net/tls_credentials.h index 8436774ec65e6a0..77e2a2308527a1c 100644 --- a/include/zephyr/net/tls_credentials.h +++ b/include/zephyr/net/tls_credentials.h @@ -66,6 +66,8 @@ enum tls_credential_type { * - TLS_CREDENTIAL_PSK with TLS_CREDENTIAL_PSK_ID. * Such pairs of credentials must be assigned the same secure tag to be * correctly handled in the system. + * + * @note Negative values are reserved for internal use. */ typedef int sec_tag_t; diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index 75cf4cf5f9267a5..0f19d7c4c1869c9 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 * @{ */ @@ -56,7 +56,7 @@ enum wifi_security_type { }; /** Helper function to get user-friendly security type name. */ -const char * const wifi_security_txt(enum wifi_security_type security); +const char *wifi_security_txt(enum wifi_security_type security); /** IEEE 802.11w - Management frame protection. */ enum wifi_mfp_options { @@ -73,7 +73,7 @@ enum wifi_mfp_options { }; /** Helper function to get user-friendly MFP name.*/ -const char * const wifi_mfp_txt(enum wifi_mfp_options mfp); +const char *wifi_mfp_txt(enum wifi_mfp_options mfp); /** * @brief IEEE 802.11 operational frequency bands (not exhaustive). @@ -95,7 +95,7 @@ enum wifi_frequency_bands { }; /** Helper function to get user-friendly frequency band name. */ -const char * const wifi_band_txt(enum wifi_frequency_bands band); +const char *wifi_band_txt(enum wifi_frequency_bands band); #define WIFI_SSID_MAX_LEN 32 #define WIFI_PSK_MIN_LEN 8 @@ -139,7 +139,7 @@ enum wifi_iface_state { }; /** Helper function to get user-friendly interface state name. */ -const char * const wifi_state_txt(enum wifi_iface_state state); +const char *wifi_state_txt(enum wifi_iface_state state); /** Wi-Fi interface modes. * @@ -165,7 +165,7 @@ enum wifi_iface_mode { }; /** Helper function to get user-friendly interface mode name. */ -const char * const wifi_mode_txt(enum wifi_iface_mode mode); +const char *wifi_mode_txt(enum wifi_iface_mode mode); /** Wi-Fi link operating modes * @@ -197,7 +197,7 @@ enum wifi_link_mode { }; /** Helper function to get user-friendly link mode name. */ -const char * const wifi_link_mode_txt(enum wifi_link_mode link_mode); +const char *wifi_link_mode_txt(enum wifi_link_mode link_mode); /** Wi-Fi scanning types. */ enum wifi_scan_type { @@ -216,7 +216,7 @@ enum wifi_ps { }; /** Helper function to get user-friendly ps name. */ -const char * const wifi_ps_txt(enum wifi_ps ps_name); +const char *wifi_ps_txt(enum wifi_ps ps_name); /** Wi-Fi power save modes. */ enum wifi_ps_mode { @@ -230,7 +230,7 @@ enum wifi_ps_mode { }; /** Helper function to get user-friendly ps mode name. */ -const char * const wifi_ps_mode_txt(enum wifi_ps_mode ps_mode); +const char *wifi_ps_mode_txt(enum wifi_ps_mode ps_mode); /* Interface index Min and Max values */ #define WIFI_INTERFACE_INDEX_MIN 1 @@ -273,7 +273,7 @@ enum wifi_twt_operation { }; /** Helper function to get user-friendly twt operation name. */ -const char * const wifi_twt_operation_txt(enum wifi_twt_operation twt_operation); +const char *wifi_twt_operation_txt(enum wifi_twt_operation twt_operation); /** Wi-Fi Target Wake Time (TWT) negotiation types. */ enum wifi_twt_negotiation_type { @@ -286,7 +286,7 @@ enum wifi_twt_negotiation_type { }; /** Helper function to get user-friendly twt negotiation type name. */ -const char * const wifi_twt_negotiation_type_txt(enum wifi_twt_negotiation_type twt_negotiation); +const char *wifi_twt_negotiation_type_txt(enum wifi_twt_negotiation_type twt_negotiation); /** Wi-Fi Target Wake Time (TWT) setup commands. */ enum wifi_twt_setup_cmd { @@ -309,7 +309,7 @@ enum wifi_twt_setup_cmd { }; /** Helper function to get user-friendly twt setup cmd name. */ -const char * const wifi_twt_setup_cmd_txt(enum wifi_twt_setup_cmd twt_setup); +const char *wifi_twt_setup_cmd_txt(enum wifi_twt_setup_cmd twt_setup); /** Wi-Fi Target Wake Time (TWT) negotiation status. */ enum wifi_twt_setup_resp_status { @@ -345,6 +345,14 @@ enum wifi_twt_fail_reason { WIFI_TWT_FAIL_FLOW_ALREADY_EXISTS, }; +/** Wi-Fi Target Wake Time (TWT) teradown status. */ +enum wifi_twt_teardown_status { + /** TWT teardown success */ + WIFI_TWT_TEARDOWN_SUCCESS = 0, + /** TWT teardown failure */ + WIFI_TWT_TEARDOWN_FAILED, +}; + /** @cond INTERNAL_HIDDEN */ static const char * const wifi_twt_err_code_tbl[] = { [WIFI_TWT_FAIL_UNSPECIFIED] = "Unspecified", @@ -401,7 +409,7 @@ enum wifi_ps_wakeup_mode { }; /** Helper function to get user-friendly ps wakeup mode name. */ -const char * const wifi_ps_wakeup_mode_txt(enum wifi_ps_wakeup_mode ps_wakeup_mode); +const char *wifi_ps_wakeup_mode_txt(enum wifi_ps_wakeup_mode ps_wakeup_mode); /** Wi-Fi power save error codes. */ enum wifi_config_ps_param_fail_reason { diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index ae5bf27370d4d2d..e0930d2f106be7e 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -81,6 +81,10 @@ enum net_request_wifi_cmd { NET_REQUEST_WIFI_CMD_PACKET_FILTER, /** Set or get Wi-Fi channel for Monitor or TX-Injection mode */ 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 }; @@ -158,6 +162,16 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_PACKET_FILTER); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_CHANNEL); +#define NET_REQUEST_WIFI_AP_STA_DISCONNECT \ + (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_AP_STA_DISCONNECT) + +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 */ @@ -180,6 +194,14 @@ enum net_event_wifi_cmd { NET_EVENT_WIFI_CMD_RAW_SCAN_RESULT, /** Disconnect complete */ NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE, + /** AP mode enable result */ + NET_EVENT_WIFI_CMD_AP_ENABLE_RESULT, + /** AP mode disable result */ + NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT, + /** STA connected to AP */ + NET_EVENT_WIFI_CMD_AP_STA_CONNECTED, + /** STA disconnected from AP */ + NET_EVENT_WIFI_CMD_AP_STA_DISCONNECTED, }; #define NET_EVENT_WIFI_SCAN_RESULT \ @@ -209,6 +231,26 @@ enum net_event_wifi_cmd { #define NET_EVENT_WIFI_DISCONNECT_COMPLETE \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE) +#define NET_EVENT_WIFI_AP_ENABLE_RESULT \ + (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_ENABLE_RESULT) + +#define NET_EVENT_WIFI_AP_DISABLE_RESULT \ + (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT) + +#define NET_EVENT_WIFI_AP_STA_CONNECTED \ + (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_STA_CONNECTED) + +#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 */ @@ -302,11 +344,11 @@ struct wifi_connect_req_params { /** SSID length */ uint8_t ssid_length; /* Max 32 */ /** Pre-shared key */ - uint8_t *psk; + const uint8_t *psk; /** Pre-shared key length */ uint8_t psk_length; /* Min 8 - Max 64 */ /** SAE password (same as PSK but with no length restrictions), optional */ - uint8_t *sae_password; + const uint8_t *sae_password; /** SAE password length */ uint8_t sae_password_length; /* No length restrictions */ /** Frequency band */ @@ -321,9 +363,66 @@ struct wifi_connect_req_params { int timeout; }; +/** Wi-Fi connect result codes. To be overlaid on top of \ref wifi_status + * in the connect result event for detailed status. + */ +enum wifi_conn_status { + /** Connection successful */ + WIFI_STATUS_CONN_SUCCESS = 0, + /** Connection failed - generic failure */ + WIFI_STATUS_CONN_FAIL, + /** Connection failed - wrong password */ + WIFI_STATUS_CONN_WRONG_PASSWORD, + /** Connection timed out */ + WIFI_STATUS_CONN_TIMEOUT, + /** Connection failed - AP not found */ + WIFI_STATUS_CONN_AP_NOT_FOUND, +}; + +/** Wi-Fi disconnect reason codes. To be overlaid on top of \ref wifi_status + * in the disconnect result event for detailed reason. + */ +enum wifi_disconn_reason { + /** Unspecified reason */ + WIFI_REASON_DISCONN_UNSPECIFIED = 0, + /** Disconnected due to user request */ + WIFI_REASON_DISCONN_USER_REQUEST, + /** Disconnected due to AP leaving */ + WIFI_REASON_DISCONN_AP_LEAVING, + /** Disconnected due to inactivity */ + WIFI_REASON_DISCONN_INACTIVITY, +}; + +/** Wi-Fi AP mode result codes. To be overlaid on top of \ref wifi_status + * in the AP mode enable or disable result event for detailed status. + */ +enum wifi_ap_status { + /** AP mode enable or disable successful */ + WIFI_STATUS_AP_SUCCESS = 0, + /** AP mode enable or disable failed - generic failure */ + WIFI_STATUS_AP_FAIL, + /** AP mode enable failed - channel not supported */ + WIFI_STATUS_AP_CHANNEL_NOT_SUPPORTED, + /** AP mode enable failed - channel not allowed */ + WIFI_STATUS_AP_CHANNEL_NOT_ALLOWED, + /** AP mode enable failed - SSID not allowed */ + WIFI_STATUS_AP_SSID_NOT_ALLOWED, + /** AP mode enable failed - authentication type not supported */ + WIFI_STATUS_AP_AUTH_TYPE_NOT_SUPPORTED, + /** AP mode enable failed - operation not supported */ + WIFI_STATUS_AP_OP_NOT_SUPPORTED, + /** AP mode enable failed - operation not permitted */ + WIFI_STATUS_AP_OP_NOT_PERMITTED, +}; + /** Generic Wi-Fi status for commands and events */ struct wifi_status { - int status; + union { + int status; + enum wifi_conn_status conn_status; + enum wifi_disconn_reason disconn_reason; + enum wifi_ap_status ap_status; + }; }; /** Wi-Fi interface status */ @@ -393,6 +492,8 @@ struct wifi_twt_params { enum wifi_twt_setup_cmd setup_cmd; /** TWT setup response status, see enum wifi_twt_setup_resp_status */ enum wifi_twt_setup_resp_status resp_status; + /** TWT teardown cmd status, see enum wifi_twt_teardown_status */ + enum wifi_twt_teardown_status teardown_status; /** Dialog token, used to map requests to responses */ uint8_t dialog_token; /** Flow ID, used to map setup with teardown */ @@ -412,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 { @@ -428,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 { @@ -449,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 */ @@ -469,6 +579,22 @@ enum wifi_mgmt_op { WIFI_MGMT_SET = 1, }; +#define MAX_REG_CHAN_NUM 42 + +/** Per-channel regulatory attributes */ +struct wifi_reg_chan_info { + /** Center frequency in MHz */ + unsigned short center_frequency; + /** Maximum transmission power (in dBm) */ + unsigned short max_power:8; + /** Is channel supported or not */ + unsigned short supported:1; + /** Passive transmissions only */ + unsigned short passive_only:1; + /** Is a DFS channel */ + unsigned short dfs:1; +} __packed; + /** Regulatory domain information or configuration */ struct wifi_reg_domain { /* Regulatory domain operation */ @@ -477,6 +603,10 @@ struct wifi_reg_domain { bool force; /** Country code: ISO/IEC 3166-1 alpha-2 */ uint8_t country_code[WIFI_COUNTRY_CODE_LEN]; + /** Number of channels supported */ + unsigned int num_channels; + /** Channels information */ + struct wifi_reg_chan_info *chan_info; }; /** Wi-Fi TWT sleep states */ @@ -501,6 +631,18 @@ struct wifi_raw_scan_result { }; #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ +/** AP mode - connected STA details */ +struct wifi_ap_sta_info { + /** Link mode, see enum wifi_link_mode */ + enum wifi_link_mode link_mode; + /** MAC address */ + uint8_t mac[WIFI_MAC_ADDR_LEN]; + /** MAC address length */ + uint8_t mac_length; + /** is TWT capable ? */ + bool twt_capable; +}; + /* for use in max info size calculations */ union wifi_mgmt_events { struct wifi_scan_result scan_result; @@ -510,6 +652,7 @@ union wifi_mgmt_events { struct wifi_raw_scan_result raw_scan_result; #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ struct wifi_twt_params twt_params; + struct wifi_ap_sta_info ap_sta_info; }; /** Wi-Fi mode setup */ @@ -614,6 +757,14 @@ struct wifi_mgmt_ops { * @return 0 if ok, < 0 if error */ int (*ap_disable)(const struct device *dev); + /** Disconnect a STA from AP + * + * @param dev Pointer to the device structure for the driver instance. + * @param mac MAC address of the STA to disconnect + * + * @return 0 if ok, < 0 if error + */ + int (*ap_sta_disconnect)(const struct device *dev, const uint8_t *mac); /** Get interface status * * @param dev Pointer to the device structure for the driver instance. @@ -688,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 */ @@ -707,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). */ @@ -768,6 +943,35 @@ void wifi_mgmt_raise_raw_scan_result_event(struct net_if *iface, */ void wifi_mgmt_raise_disconnect_complete_event(struct net_if *iface, int status); +/** Wi-Fi management AP mode enable result event + * + * @param iface Network interface + * @param status AP mode enable result status + */ +void wifi_mgmt_raise_ap_enable_result_event(struct net_if *iface, enum wifi_ap_status status); + +/** Wi-Fi management AP mode disable result event + * + * @param iface Network interface + * @param status AP mode disable result status + */ +void wifi_mgmt_raise_ap_disable_result_event(struct net_if *iface, enum wifi_ap_status status); + +/** Wi-Fi management AP mode STA connected event + * + * @param iface Network interface + * @param sta_info STA information + */ +void wifi_mgmt_raise_ap_sta_connected_event(struct net_if *iface, + struct wifi_ap_sta_info *sta_info); + +/** Wi-Fi management AP mode STA disconnected event + * @param iface Network interface + * @param sta_info STA information + */ +void wifi_mgmt_raise_ap_sta_disconnected_event(struct net_if *iface, + struct wifi_ap_sta_info *sta_info); + /** * @} */ diff --git a/include/zephyr/net/wifi_utils.h b/include/zephyr/net/wifi_utils.h index c16eef0e5b27d1c..537db787648281a 100644 --- a/include/zephyr/net/wifi_utils.h +++ b/include/zephyr/net/wifi_utils.h @@ -103,6 +103,49 @@ int wifi_utils_parse_scan_chan(char *scan_chan_str, struct wifi_band_channel *chan, uint8_t max_channels); + +/** + * @brief Validate a channel against a band. + * + * @param band Band to validate the channel against. + * @param chan Channel to validate. + * + * @retval true if the channel is valid for the band. + * @retval false if the channel is not valid for the band. + */ +bool wifi_utils_validate_chan(uint8_t band, + uint16_t chan); + +/** + * @brief Validate a channel against the 2.4 GHz band. + * + * @param chan Channel to validate. + * + * @retval true if the channel is valid for the band. + * @retval false if the channel is not valid for the band. + */ +bool wifi_utils_validate_chan_2g(uint16_t chan); + +/** + * @brief Validate a channel against the 5 GHz band. + * + * @param chan Channel to validate. + * + * @retval true if the channel is valid for the band. + * @retval false if the channel is not valid for the band. + */ +bool wifi_utils_validate_chan_5g(uint16_t chan); + +/** + * @brief Validate a channel against the 6 GHz band. + * + * @param chan Channel to validate. + * + * @retval true if the channel is valid for the band. + * @retval false if the channel is not valid for the band. + */ +bool wifi_utils_validate_chan_6g(uint16_t chan); + /** * @} */ diff --git a/include/zephyr/pm/device.h b/include/zephyr/pm/device.h index cbfbf6f5f46df67..ab54fd677fe7091 100644 --- a/include/zephyr/pm/device.h +++ b/include/zephyr/pm/device.h @@ -220,7 +220,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 diff --git a/include/zephyr/pm/device_runtime.h b/include/zephyr/pm/device_runtime.h index 09bf0c04278e47c..3510a910f3ae237 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/pm/state.h b/include/zephyr/pm/state.h index 1d21ffd997a91aa..cc3878794113d43 100644 --- a/include/zephyr/pm/state.h +++ b/include/zephyr/pm/state.h @@ -329,6 +329,7 @@ struct pm_state_info { } +#if defined(CONFIG_PM) || defined(__DOXYGEN__) /** * Obtain information about all supported states by a CPU. * @@ -343,6 +344,18 @@ uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states); * @} */ +#else /* CONFIG_PM */ + +static inline uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states) +{ + ARG_UNUSED(cpu); + ARG_UNUSED(states); + + return 0; +} + +#endif /* CONFIG_PM */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/posix/dirent.h b/include/zephyr/posix/dirent.h index 31c2a2cee4c178a..43c68983ebb73ef 100644 --- a/include/zephyr/posix/dirent.h +++ b/include/zephyr/posix/dirent.h @@ -24,9 +24,9 @@ struct dirent { }; /* Directory related operations */ -extern DIR *opendir(const char *dirname); -extern int closedir(DIR *dirp); -extern struct dirent *readdir(DIR *dirp); +DIR *opendir(const char *dirname); +int closedir(DIR *dirp); +struct dirent *readdir(DIR *dirp); #ifdef __cplusplus } diff --git a/include/zephyr/posix/mqueue.h b/include/zephyr/posix/mqueue.h index 29f67607e2c6868..dbaa6d42a537d54 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 ed56e78c225efbb..52621656569be8f 100644 --- a/include/zephyr/posix/posix_types.h +++ b/include/zephyr/posix/posix_types.h @@ -7,7 +7,7 @@ #ifndef ZEPHYR_INCLUDE_POSIX_TYPES_H_ #define ZEPHYR_INCLUDE_POSIX_TYPES_H_ -#ifndef CONFIG_ARCH_POSIX +#if !(defined(CONFIG_ARCH_POSIX) && defined(CONFIG_EXTERNAL_LIBC)) #include #endif @@ -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 45940123cf5d698..4cf6dcbe3d4e75c 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 + * @brief Declare a rwlock as initialized * - * 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. - * - * @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); @@ -442,7 +429,9 @@ int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize); int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize); +#ifdef CONFIG_PTHREAD_IPC int pthread_once(pthread_once_t *once, void (*initFunc)(void)); +#endif void pthread_exit(void *retval); int pthread_join(pthread_t thread, void **status); int pthread_cancel(pthread_t pthread); @@ -450,6 +439,7 @@ 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); int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *schedparam); int pthread_setschedparam(pthread_t pthread, int policy, @@ -471,6 +461,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 6b89c8f9818eb70..000000000000000 --- 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 10cfc666c66d206..03b568fadea66d8 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,8 @@ #include +#include "posix_types.h" + #ifdef __cplusplus extern "C" { #endif @@ -46,6 +48,12 @@ 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); + #ifdef __cplusplus } #endif diff --git a/include/zephyr/posix/semaphore.h b/include/zephyr/posix/semaphore.h index 943218ee08e82a6..3b0f53b07123c0a 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 b31147306c26305..3bbdee7317aca77 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 000000000000000..9474c36edb2c037 --- /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 0fd2b5de9e691d2..4420b69eabae193 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/sys/stat.h b/include/zephyr/posix/sys/stat.h index 01251c65ace08d1..2d19df29700a623 100644 --- a/include/zephyr/posix/sys/stat.h +++ b/include/zephyr/posix/sys/stat.h @@ -114,7 +114,7 @@ struct stat { #define st_mtime st_mtim.tv_sec #define st_ctime st_ctim.tv_sec #if defined(__linux) && defined(__x86_64__) - __uint64_t __glibc_reserved[3]; + uint64_t __glibc_reserved[3]; #endif #else #if defined(__rtems__) diff --git a/include/zephyr/posix/time.h b/include/zephyr/posix/time.h index 85cb7f8ae4226ae..417923c4377b042 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 ec8bf7e6adb1bac..36918c563654783 100644 --- a/include/zephyr/posix/unistd.h +++ b/include/zephyr/posix/unistd.h @@ -11,28 +11,231 @@ #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 */ -extern int close(int file); -extern ssize_t write(int file, const void *buffer, size_t count); -extern ssize_t read(int file, void *buffer, size_t count); -extern off_t lseek(int file, off_t offset, int whence); +int close(int file); +ssize_t write(int file, const void *buffer, size_t count); +ssize_t read(int file, void *buffer, size_t count); +off_t lseek(int file, off_t offset, int whence); /* File System related operations */ -extern int rename(const char *old, const char *newp); -extern int unlink(const char *path); -extern int stat(const char *path, struct stat *buf); -extern int mkdir(const char *path, mode_t mode); +int rename(const char *old, const char *newp); +int unlink(const char *path); +int stat(const char *path, struct stat *buf); +int mkdir(const char *path, mode_t mode); FUNC_NORETURN void _exit(int status); @@ -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 8ad07281ceef329..fe0f5b72c97bf0b 100644 --- a/include/zephyr/rtio/rtio.h +++ b/include/zephyr/rtio/rtio.h @@ -674,6 +674,13 @@ static inline int rtio_block_pool_alloc(struct rtio *r, size_t min_sz, const uint32_t block_size = rtio_mempool_block_size(r); uint32_t bytes = max_sz; + /* Not every context has a block pool and the block size may return 0 in + * that case + */ + if (block_size == 0) { + return -ENOMEM; + } + do { size_t num_blks = DIV_ROUND_UP(bytes, block_size); int rc = sys_mem_blocks_alloc_contiguous(r->block_pool, num_blks, (void **)buf); diff --git a/include/zephyr/sd/sd.h b/include/zephyr/sd/sd.h index a93aec5f012983b..b23fa2c260ca8ce 100644 --- a/include/zephyr/sd/sd.h +++ b/include/zephyr/sd/sd.h @@ -39,6 +39,19 @@ enum card_type { CARD_MMC = 3, /*!< MMC memory card */ }; +/** + * @brief SDIO function definition + * + * SDIO function definition. Used to store function information + * per each SDIO function + */ +struct sdio_func { + enum sdio_func_num num; /*!< Function number */ + struct sd_card *card; /*!< Card this function is present on */ + struct sdio_cis cis; /*!< CIS tuple data for this function */ + uint16_t block_size; /*!< Current block size for this function */ +}; + /** * @brief SD card structure @@ -65,8 +78,16 @@ struct sd_card { enum card_type type; /*!< Card type */ uint16_t flags; /*!< Card flags */ 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/sd/sd_spec.h b/include/zephyr/sd/sd_spec.h index ed0426766ec788b..ed61932e65516a2 100644 --- a/include/zephyr/sd/sd_spec.h +++ b/include/zephyr/sd/sd_spec.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 NXP + * Copyright 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -54,6 +54,8 @@ enum sd_opcode { SD_ERASE_BLOCK_START = 32, SD_ERASE_BLOCK_END = 33, SD_ERASE_BLOCK_OPERATION = 38, + SDIO_RW_DIRECT = 52, + SDIO_RW_EXTENDED = 53, SD_APP_CMD = 55, SD_SPI_READ_OCR = 58, /* SPI mode only */ SD_SPI_CRC_ON_OFF = 59, /* SPI mode only */ @@ -244,6 +246,7 @@ enum sd_support_flag { SD_3000MV_FLAG = BIT(6), SD_CMD23_FLAG = BIT(7), SD_SPEED_CLASS_CONTROL_FLAG = BIT(8), + SD_MEM_PRESENT_FLAG = BIT(9), }; @@ -298,9 +301,9 @@ enum mmc_ocr_flag { MMC_OCR_PWR_BUSY_FLAG = BIT(31) }; -#define SDIO_OCR_IO_NUMBER_SHIFT (28U) +#define SDIO_OCR_IO_NUMBER_SHIFT 28 /* Lower 24 bits hold SDIO I/O OCR */ -#define SDIO_IO_OCR_MASK (0xFFFFFFU) +#define SDIO_IO_OCR_MASK 0xFFFFFF /** * @brief SDIO OCR bit flags @@ -491,7 +494,7 @@ struct sd_switch_caps { }; -#define SD_PRODUCT_NAME_BYTES (5U) +#define SD_PRODUCT_NAME_BYTES 5 /** * @brief SD card identification register @@ -754,8 +757,158 @@ enum sd_spec_version { }; -#define SDMMC_DEFAULT_BLOCK_SIZE (512U) +#define SDMMC_DEFAULT_BLOCK_SIZE 512 #define MMC_EXT_CSD_BYTES 512 +/** + * @brief SDIO function number + * + * SDIO function number used to select function when performing I/O on SDIO card + */ +enum sdio_func_num { + SDIO_FUNC_NUM_0 = 0, + SDIO_FUNC_NUM_1 = 1, + SDIO_FUNC_NUM_2 = 2, + SDIO_FUNC_NUM_3 = 3, + SDIO_FUNC_NUM_4 = 4, + SDIO_FUNC_NUM_5 = 5, + SDIO_FUNC_NUM_6 = 6, + SDIO_FUNC_NUM_7 = 7, + SDIO_FUNC_MEMORY = 8, +}; + +/** + * @brief SDIO I/O direction + * + * SDIO I/O direction (read or write) + */ +enum sdio_io_dir { + SDIO_IO_READ = 0, + SDIO_IO_WRITE = 1, +}; + +#define SDIO_CMD_ARG_RW_SHIFT 31 /*!< read/write flag shift */ +#define SDIO_CMD_ARG_FUNC_NUM_SHIFT 28 /*!< function number shift */ +#define SDIO_DIRECT_CMD_ARG_RAW_SHIFT 27 /*!< direct raw flag shift */ +#define SDIO_CMD_ARG_REG_ADDR_SHIFT 9 /*!< direct reg addr shift */ +#define SDIO_CMD_ARG_REG_ADDR_MASK 0x1FFFF /*!< direct reg addr mask */ +#define SDIO_DIRECT_CMD_DATA_MASK 0xFF /*!< data mask */ + +#define SDIO_EXTEND_CMD_ARG_BLK_SHIFT 27 /*!< extended write block mode */ +#define SDIO_EXTEND_CMD_ARG_OP_CODE_SHIFT 26 /*!< op code (increment address) */ + +/** + * @brief Card common control register definitions + * + * Card common control registers, present on all SDIO cards + */ +#define SDIO_CCCR_CCCR 0x00 /*!< SDIO CCCR revision register */ +#define SDIO_CCCR_CCCR_REV_MASK 0x0F +#define SDIO_CCCR_CCCR_REV_SHIFT 0x0 +#define SDIO_CCCR_CCCR_REV_1_00 0x0 /*!< CCCR/FBR Version 1.00 */ +#define SDIO_CCCR_CCCR_REV_1_10 0x1 /*!< CCCR/FBR Version 1.10 */ +#define SDIO_CCCR_CCCR_REV_2_00 0x2 /*!< CCCR/FBR Version 2.00 */ +#define SDIO_CCCR_CCCR_REV_3_00 0x3 /*!< CCCR/FBR Version 3.00 */ + +#define SDIO_CCCR_SD 0x01 /*!< SD spec version register */ +#define SDIO_CCCR_SD_SPEC_MASK 0x0F +#define SDIO_CCCR_SD_SPEC_SHIFT 0x0 + +#define SDIO_CCCR_IO_EN 0x02 /*!< SDIO IO Enable register */ + +#define SDIO_CCCR_IO_RD 0x03 /*!< SDIO IO Ready register */ + +#define SDIO_CCCR_INT_EN 0x04 /*!< SDIO Interrupt enable register */ + +#define SDIO_CCCR_INT_P 0x05 /*!< SDIO Interrupt pending register */ + +#define SDIO_CCCR_ABORT 0x06 /*!< SDIO IO abort register */ + +#define SDIO_CCCR_BUS_IF 0x07 /*!< SDIO bus interface control register */ +#define SDIO_CCCR_BUS_IF_WIDTH_MASK 0x3 /*!< SDIO bus width setting mask */ +#define SDIO_CCCR_BUS_IF_WIDTH_1_BIT 0x00 /*!< 1 bit SDIO bus setting */ +#define SDIO_CCCR_BUS_IF_WIDTH_4_BIT 0x02 /*!< 4 bit SDIO bus setting */ +#define SDIO_CCCR_BUS_IF_WIDTH_8_BIT 0x03 /*!< 8 bit SDIO bus setting */ + +#define SDIO_CCCR_CAPS 0x08 /*!< SDIO card capabilities */ +#define SDIO_CCCR_CAPS_SDC BIT(0) /*!< support CMD52 while data transfer */ +#define SDIO_CCCR_CAPS_SMB BIT(1) /*!< support multiple block transfer */ +#define SDIO_CCCR_CAPS_SRW BIT(2) /*!< support read wait control */ +#define SDIO_CCCR_CAPS_SBS BIT(3) /*!< support bus control */ +#define SDIO_CCCR_CAPS_S4MI BIT(4) /*!< support block gap interrupt */ +#define SDIO_CCCR_CAPS_E4MI BIT(5) /*!< enable block gap interrupt */ +#define SDIO_CCCR_CAPS_LSC BIT(6) /*!< low speed card */ +#define SDIO_CCCR_CAPS_BLS BIT(7) /*!< low speed card with 4 bit support */ + +#define SDIO_CCCR_CIS 0x09 /*!< SDIO CIS tuples pointer */ + +#define SDIO_CCCR_SPEED 0x13 /*!< SDIO bus speed select */ +#define SDIO_CCCR_SPEED_SHS BIT(0) /*!< high speed support */ +#define SDIO_CCCR_SPEED_MASK 0xE /*!< bus speed select mask*/ +#define SDIO_CCCR_SPEED_SHIFT 0x1 /*!< bus speed select shift */ +#define SDIO_CCCR_SPEED_SDR12 0x0 /*!< select SDR12 */ +#define SDIO_CCCR_SPEED_HS 0x1 /*!< select High speed mode */ +#define SDIO_CCCR_SPEED_SDR25 0x1 /*!< select SDR25 */ +#define SDIO_CCCR_SPEED_SDR50 0x2 /*!< select SDR50 */ +#define SDIO_CCCR_SPEED_SDR104 0x3 /*!< select SDR104 */ +#define SDIO_CCCR_SPEED_DDR50 0x4 /*!< select DDR50 */ + +#define SDIO_CCCR_UHS 0x14 /*!< SDIO UHS support */ +#define SDIO_CCCR_UHS_SDR50 BIT(0) /*!< SDR50 support */ +#define SDIO_CCCR_UHS_SDR104 BIT(1) /*!< SDR104 support */ +#define SDIO_CCCR_UHS_DDR50 BIT(2) /*!< DDR50 support */ + +#define SDIO_CCCR_DRIVE_STRENGTH 0x15 /*!< SDIO drive strength */ +#define SDIO_CCCR_DRIVE_STRENGTH_A BIT(0) /*!< drive type A */ +#define SDIO_CCCR_DRIVE_STRENGTH_C BIT(1) /*!< drive type C */ +#define SDIO_CCCR_DRIVE_STRENGTH_D BIT(2) /*!< drive type D */ + +#define SDIO_FBR_BASE(n) ((n) * 0x100) /*!< Get function base register addr */ + +#define SDIO_FBR_CIS 0x09 /*!< SDIO function base register CIS pointer */ +#define SDIO_FBR_CSA 0x0C /*!< SDIO function base register CSA pointer */ +#define SDIO_FBR_BLK_SIZE 0x10 /*!< SDIO function base register block size */ + + +#define SDIO_MAX_IO_NUMS 7 /*!< Maximum number of I/O functions for SDIO */ + +#define SDIO_TPL_CODE_NULL 0x00 /*!< NULL CIS tuple code */ +#define SDIO_TPL_CODE_MANIFID 0x20 /*!< manufacturer ID CIS tuple code */ +#define SDIO_TPL_CODE_FUNCID 0x21 /*!< function ID CIS tuple code */ +#define SDIO_TPL_CODE_FUNCE 0x22 /*!< function extension CIS tuple code */ +#define SDIO_TPL_CODE_END 0xFF /*!< End CIS tuple code */ + +/** + * @brief Card common control register flags + * + * flags to indicate capabilities supported by an SDIO card, read from the CCCR + * registers + */ +enum sdio_cccr_flags { + SDIO_SUPPORT_HS = BIT(0), + SDIO_SUPPORT_SDR50 = BIT(1), + SDIO_SUPPORT_SDR104 = BIT(2), + SDIO_SUPPORT_DDR50 = BIT(3), + SDIO_SUPPORT_4BIT_LS_BUS = BIT(4), + SDIO_SUPPORT_MULTIBLOCK = BIT(5), +}; + +/** + * @brief SDIO common CIS tuple properties + * + * CIS tuple properties. Note that additional properties exist for + * functions 1-7, but we do not read this data as the stack does not utilize it. + */ +struct sdio_cis { + /* Manufacturer ID string tuple */ + uint16_t manf_id; /*!< manufacturer ID */ + uint16_t manf_code; /*!< manufacturer code */ + /* Function identification tuple */ + uint8_t func_id; /*!< sdio device class function id */ + /* Function extension table */ + uint16_t max_blk_size; /*!< Max transfer block size */ + uint8_t max_speed; /*!< Max transfer speed */ + uint16_t rdy_timeout; /*!< I/O ready timeout */ +}; #ifdef __cplusplus } diff --git a/include/zephyr/sd/sdio.h b/include/zephyr/sd/sdio.h new file mode 100644 index 000000000000000..546a68d2bbbb225 --- /dev/null +++ b/include/zephyr/sd/sdio.h @@ -0,0 +1,212 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public API for SDIO subsystem + */ + +#ifndef ZEPHYR_INCLUDE_SD_SDIO_H_ +#define ZEPHYR_INCLUDE_SD_SDIO_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize SDIO function. + * + * Initializes SDIO card function. The card function will not be enabled, + * but after this call returns the SDIO function structure can be used to read + * and write data from the card. + * @param func: function structure to initialize + * @param card: SD card to enable function on + * @param num: function number to initialize + * @retval 0 function was initialized successfully + * @retval -EIO: I/O error + */ +int sdio_init_func(struct sd_card *card, struct sdio_func *func, + enum sdio_func_num num); + +/** + * @brief Enable SDIO function + * + * Enables SDIO card function. @ref sdio_init_func must be called to + * initialized the function structure before enabling it in the card. + * @param func: function to enable + * @retval 0 function was enabled successfully + * @retval -ETIMEDOUT: card I/O timed out + * @retval -EIO: I/O error + */ +int sdio_enable_func(struct sdio_func *func); + +/** + * @brief Set block size of SDIO function + * + * Set desired block size for SDIO function, used by block transfers + * to SDIO registers. + * @param func: function to set block size for + * @param bsize: block size + * @retval 0 block size was set + * @retval -EINVAL: unsupported/invalid block size + * @retval -EIO: I/O error + */ +int sdio_set_block_size(struct sdio_func *func, uint16_t bsize); + +/** + * @brief Read byte from SDIO register + * + * Reads byte from SDIO register + * @param func: function to read from + * @param reg: register address to read from + * @param val: filled with byte value read from register + * @retval 0 read succeeded + * @retval -EBUSY: card is busy with another request + * @retval -ETIMEDOUT: card read timed out + * @retval -EIO: I/O error + */ +int sdio_read_byte(struct sdio_func *func, uint32_t reg, uint8_t *val); + +/** + * @brief Write byte to SDIO register + * + * Writes byte to SDIO register + * @param func: function to write to + * @param reg: register address to write to + * @param write_val: value to write to register + * @retval 0 write succeeded + * @retval -EBUSY: card is busy with another request + * @retval -ETIMEDOUT: card write timed out + * @retval -EIO: I/O error + */ +int sdio_write_byte(struct sdio_func *func, uint32_t reg, uint8_t write_val); + +/** + * @brief Write byte to SDIO register, and read result + * + * Writes byte to SDIO register, and reads the register after write + * @param func: function to write to + * @param reg: register address to write to + * @param write_val: value to write to register + * @param read_val: filled with value read from register + * @retval 0 write succeeded + * @retval -EBUSY: card is busy with another request + * @retval -ETIMEDOUT: card write timed out + * @retval -EIO: I/O error + */ +int sdio_rw_byte(struct sdio_func *func, uint32_t reg, uint8_t write_val, + uint8_t *read_val); + +/** + * @brief Read bytes from SDIO fifo + * + * Reads bytes from SDIO register, treating it as a fifo. Reads will + * all be done from same address. + * @param func: function to read from + * @param reg: register address of fifo + * @param data: filled with data read from fifo + * @param len: length of data to read from card + * @retval 0 read succeeded + * @retval -EBUSY: card is busy with another request + * @retval -ETIMEDOUT: card read timed out + * @retval -EIO: I/O error + */ +int sdio_read_fifo(struct sdio_func *func, uint32_t reg, uint8_t *data, + uint32_t len); + +/** + * @brief Write bytes to SDIO fifo + * + * Writes bytes to SDIO register, treating it as a fifo. Writes will + * all be done to same address. + * @param func: function to write to + * @param reg: register address of fifo + * @param data: data to write to fifo + * @param len: length of data to write to card + * @retval 0 write succeeded + * @retval -EBUSY: card is busy with another request + * @retval -ETIMEDOUT: card write timed out + * @retval -EIO: I/O error + */ +int sdio_write_fifo(struct sdio_func *func, uint32_t reg, uint8_t *data, + uint32_t len); + +/** + * @brief Read blocks from SDIO fifo + * + * Reads blocks from SDIO register, treating it as a fifo. Reads will + * all be done from same address. + * @param func: function to read from + * @param reg: register address of fifo + * @param data: filled with data read from fifo + * @param blocks: number of blocks to read from fifo + * @retval 0 read succeeded + * @retval -EBUSY: card is busy with another request + * @retval -ETIMEDOUT: card read timed out + * @retval -EIO: I/O error + */ +int sdio_read_blocks_fifo(struct sdio_func *func, uint32_t reg, uint8_t *data, + uint32_t blocks); + +/** + * @brief Write blocks to SDIO fifo + * + * Writes blocks from SDIO register, treating it as a fifo. Writes will + * all be done to same address. + * @param func: function to write to + * @param reg: register address of fifo + * @param data: data to write to fifo + * @param blocks: number of blocks to write to fifo + * @retval 0 write succeeded + * @retval -EBUSY: card is busy with another request + * @retval -ETIMEDOUT: card write timed out + * @retval -EIO: I/O error + */ +int sdio_write_blocks_fifo(struct sdio_func *func, uint32_t reg, uint8_t *data, + uint32_t blocks); + +/** + * @brief Copy bytes from an SDIO card + * + * Copies bytes from an SDIO card, starting from provided address. + * @param func: function to read from + * @param reg: register address to start copy at + * @param data: buffer to copy data into + * @param len: length of data to read + * @retval 0 read succeeded + * @retval -EBUSY: card is busy with another request + * @retval -ETIMEDOUT: card read timed out + * @retval -EIO: I/O error + */ +int sdio_read_addr(struct sdio_func *func, uint32_t reg, uint8_t *data, + uint32_t len); + +/** + * @brief Copy bytes to an SDIO card + * + * Copies bytes to an SDIO card, starting from provided address. + * + * @param func: function to write to + * @param reg: register address to start copy at + * @param data: buffer to copy data from + * @param len: length of data to write + * @retval 0 write succeeded + * @retval -EBUSY: card is busy with another request + * @retval -ETIMEDOUT: card write timed out + * @retval -EIO: I/O error + */ +int sdio_write_addr(struct sdio_func *func, uint32_t reg, uint8_t *data, + uint32_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_SD_SDMMC_H_ */ diff --git a/include/zephyr/sensing/sensing.h b/include/zephyr/sensing/sensing.h index e29b1aa76247145..4491874fc84e7e5 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 3549aab4bdb692f..a5abcc3c8f826e1 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 8c9e0c83811d0a3..434c13b90525182 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/shell/shell.h b/include/zephyr/shell/shell.h index d75814e08b9a377..0bcb831c90dcb1f 100644 --- a/include/zephyr/shell/shell.h +++ b/include/zephyr/shell/shell.h @@ -350,8 +350,8 @@ struct shell_static_entry { SHELL_EXPR_CMD_ARG(1, _syntax, _subcmd, _help, \ _handler, _mand, _opt)\ ), \ - (static shell_cmd_handler dummy_##syntax##_handler __unused = _handler;\ - static const union shell_cmd_entry dummy_subcmd_##syntax __unused = { \ + (static shell_cmd_handler dummy_handler_##_syntax __unused = _handler;\ + static const union shell_cmd_entry dummy_subcmd_##_syntax __unused = { \ .entry = (const struct shell_static_entry *)_subcmd\ } \ ) \ @@ -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; @@ -863,7 +867,7 @@ struct shell { LOG_INSTANCE_PTR_DECLARE(log); - const char *thread_name; + const char *name; struct k_thread *thread; k_thread_stack_t *stack; }; @@ -910,7 +914,7 @@ extern void z_shell_print_stream(const void *user_ctx, const char *data, .stats = Z_SHELL_STATS_PTR(_name), \ .log_backend = Z_SHELL_LOG_BACKEND_PTR(_name), \ LOG_INSTANCE_PTR_INIT(log, shell, _name) \ - .thread_name = STRINGIFY(_name), \ + .name = STRINGIFY(_name), \ .thread = &_name##_thread, \ .stack = _name##_stack \ } diff --git a/include/zephyr/shell/shell_backend.h b/include/zephyr/shell/shell_backend.h new file mode 100644 index 000000000000000..ae8f8a5afc31d14 --- /dev/null +++ b/include/zephyr/shell/shell_backend.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SHELL_BACKEND_H__ +#define SHELL_BACKEND_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Get backend. + * + * @param[in] idx Pointer to the backend instance. + * + * @return Pointer to the backend instance. + */ +static inline const struct shell *shell_backend_get(uint32_t idx) +{ + const struct shell *backend; + + STRUCT_SECTION_GET(shell, idx, &backend); + + return backend; +} + +/** + * @brief Get number of backends. + * + * @return Number of backends. + */ +static inline int shell_backend_count_get(void) +{ + int cnt; + + STRUCT_SECTION_COUNT(shell, &cnt); + + return cnt; +} + +/** + * @brief Get backend by name. + * + * @param[in] backend_name Name of the backend as defined by the SHELL_DEFINE. + * + * @retval Pointer to the backend instance if found, NULL if backend is not found. + */ +const struct shell *shell_backend_get_by_name(const char *backend_name); + +#ifdef __cplusplus +} +#endif + +#endif /* SHELL_BACKEND_H__ */ diff --git a/include/zephyr/shell/shell_uart.h b/include/zephyr/shell/shell_uart.h index adf8a4044aa08dd..e424a1857680be6 100644 --- a/include/zephyr/shell/shell_uart.h +++ b/include/zephyr/shell/shell_uart.h @@ -7,10 +7,9 @@ #ifndef SHELL_UART_H__ #define SHELL_UART_H__ -#include -#include -#include +#include #include +#include #ifdef __cplusplus extern "C" { @@ -18,77 +17,100 @@ extern "C" { extern const struct shell_transport_api shell_uart_transport_api; -/** @brief Shell UART transport instance control block (RW data). */ -struct shell_uart_ctrl_blk { +#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; - atomic_t tx_busy; bool blocking_tx; #ifdef CONFIG_MCUMGR_TRANSPORT_SHELL struct smp_shell_data smp; #endif /* CONFIG_MCUMGR_TRANSPORT_SHELL */ }; -#ifdef CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN -#define Z_UART_SHELL_TX_RINGBUF_DECLARE(_name, _size) \ - RING_BUF_DECLARE(_name##_tx_ringbuf, _size) - -#define Z_UART_SHELL_RX_TIMER_DECLARE(_name) /* Empty */ -#define Z_UART_SHELL_TX_RINGBUF_PTR(_name) (&_name##_tx_ringbuf) - -#define Z_UART_SHELL_RX_TIMER_PTR(_name) NULL - -#define Z_UART_SHELL_DTR_TIMER_DECLARE(_name) static struct k_timer _name##_dtr_timer -#define Z_UART_SHELL_DTR_TIMER_PTR(_name) (&_name##_dtr_timer) - -#else /* CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN */ -#define Z_UART_SHELL_TX_RINGBUF_DECLARE(_name, _size) /* Empty */ -#define Z_UART_SHELL_RX_TIMER_DECLARE(_name) static struct k_timer _name##_timer -#define Z_UART_SHELL_TX_RINGBUF_PTR(_name) NULL -#define Z_UART_SHELL_RX_TIMER_PTR(_name) (&_name##_timer) -#define Z_UART_SHELL_DTR_TIMER_DECLARE(_name) /* Empty */ -#define Z_UART_SHELL_DTR_TIMER_PTR(_name) NULL -#endif /* CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN */ - -/** @brief Shell UART transport instance structure. */ -struct shell_uart { - struct shell_uart_ctrl_blk *ctrl_blk; - struct k_timer *timer; - struct k_timer *dtr_timer; - struct ring_buf *tx_ringbuf; - struct ring_buf *rx_ringbuf; +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; }; -/** @brief Macro for creating shell UART transport instance. */ -#define SHELL_UART_DEFINE(_name, _tx_ringbuf_size, _rx_ringbuf_size) \ - static struct shell_uart_ctrl_blk _name##_ctrl_blk; \ - Z_UART_SHELL_RX_TIMER_DECLARE(_name); \ - Z_UART_SHELL_DTR_TIMER_DECLARE(_name); \ - Z_UART_SHELL_TX_RINGBUF_DECLARE(_name, _tx_ringbuf_size); \ - RING_BUF_DECLARE(_name##_rx_ringbuf, _rx_ringbuf_size); \ - static const struct shell_uart _name##_shell_uart = { \ - .ctrl_blk = &_name##_ctrl_blk, \ - .timer = Z_UART_SHELL_RX_TIMER_PTR(_name), \ - .dtr_timer = Z_UART_SHELL_DTR_TIMER_PTR(_name), \ - .tx_ringbuf = Z_UART_SHELL_TX_RINGBUF_PTR(_name), \ - .rx_ringbuf = &_name##_rx_ringbuf, \ - }; \ - struct shell_transport _name = { \ - .api = &shell_uart_transport_api, \ - .ctx = (struct shell_uart *)&_name##_shell_uart \ +#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 shell uart backend instance. + * @brief This function provides pointer to the shell UART backend instance. * - * Function returns pointer to the shell uart instance. This instance can be + * Function returns pointer to the shell UART instance. This instance can be * next used with shell_execute_cmd function in order to test commands behavior. * * @returns Pointer to the shell instance. */ const struct shell *shell_backend_uart_get_ptr(void); +/** + * @brief This function provides pointer to the smp shell data of the UART shell transport. + * + * @returns Pointer to the smp shell data. + */ +struct smp_shell_data *shell_uart_smp_shell_data_get_ptr(void); + #ifdef __cplusplus } #endif diff --git a/include/zephyr/spinlock.h b/include/zephyr/spinlock.h index 823ff7eea68f489..51c160b0f8599d5 100644 --- a/include/zephyr/spinlock.h +++ b/include/zephyr/spinlock.h @@ -43,9 +43,28 @@ struct z_spinlock_key { * application code. */ struct k_spinlock { +/** + * @cond INTERNAL_HIDDEN + */ #ifdef CONFIG_SMP +#ifdef CONFIG_TICKET_SPINLOCKS + /* + * Ticket spinlocks are conceptually two atomic variables, + * one indicating the current FIFO head (spinlock owner), + * and the other indicating the current FIFO tail. + * Spinlock is acquired in the following manner: + * - current FIFO tail value is atomically incremented while it's + * original value is saved as a "ticket" + * - we spin until the FIFO head becomes equal to the ticket value + * + * Spinlock is released by atomic increment of the FIFO head + */ + atomic_t owner; + atomic_t tail; +#else atomic_t locked; -#endif +#endif /* CONFIG_TICKET_SPINLOCKS */ +#endif /* CONFIG_SMP */ #ifdef CONFIG_SPIN_VALIDATE /* Stores the thread that holds the lock with the locking CPU @@ -76,6 +95,9 @@ struct k_spinlock { */ char dummy; #endif +/** + * INTERNAL_HIDDEN @endcond + */ }; /* There's a spinlock validation framework available when asserts are @@ -170,10 +192,22 @@ static ALWAYS_INLINE k_spinlock_key_t k_spin_lock(struct k_spinlock *l) z_spinlock_validate_pre(l); #ifdef CONFIG_SMP +#ifdef CONFIG_TICKET_SPINLOCKS + /* + * Enqueue ourselves to the end of a spinlock waiters queue + * receiving a ticket + */ + atomic_val_t ticket = atomic_inc(&l->tail); + /* Spin until our ticket is served */ + while (atomic_get(&l->owner) != ticket) { + arch_spin_relax(); + } +#else while (!atomic_cas(&l->locked, 0, 1)) { arch_spin_relax(); } -#endif +#endif /* CONFIG_TICKET_SPINLOCKS */ +#endif /* CONFIG_SMP */ z_spinlock_validate_post(l); return k; @@ -199,16 +233,47 @@ static ALWAYS_INLINE int k_spin_trylock(struct k_spinlock *l, k_spinlock_key_t * z_spinlock_validate_pre(l); #ifdef CONFIG_SMP +#ifdef CONFIG_TICKET_SPINLOCKS + /* + * atomic_get and atomic_cas operations below are not executed + * simultaneously. + * So in theory k_spin_trylock can lock an already locked spinlock. + * To reproduce this the following conditions should be met after we + * executed atomic_get and before we executed atomic_cas: + * + * - spinlock needs to be taken 0xffff_..._ffff + 1 times + * (which requires 0xffff_..._ffff number of CPUs, as k_spin_lock call + * is blocking) or + * - spinlock needs to be taken and released 0xffff_..._ffff times and + * then taken again + * + * In real-life systems this is considered non-reproducible given that + * required actions need to be done during this tiny window of several + * CPU instructions (which execute with interrupt locked, + * so no preemption can happen here) + */ + atomic_val_t ticket_val = atomic_get(&l->owner); + + if (!atomic_cas(&l->tail, ticket_val, ticket_val + 1)) { + goto busy; + } +#else if (!atomic_cas(&l->locked, 0, 1)) { - arch_irq_unlock(key); - return -EBUSY; + goto busy; } -#endif +#endif /* CONFIG_TICKET_SPINLOCKS */ +#endif /* CONFIG_SMP */ z_spinlock_validate_post(l); k->key = key; return 0; + +#ifdef CONFIG_SMP +busy: + arch_irq_unlock(key); + return -EBUSY; +#endif /* CONFIG_SMP */ } /** @@ -249,6 +314,10 @@ static ALWAYS_INLINE void k_spin_unlock(struct k_spinlock *l, #endif /* CONFIG_SPIN_VALIDATE */ #ifdef CONFIG_SMP +#ifdef CONFIG_TICKET_SPINLOCKS + /* Give the spinlock to the next CPU in a FIFO */ + atomic_inc(&l->owner); +#else /* Strictly we don't need atomic_clear() here (which is an * exchange operation that returns the old value). We are always * setting a zero and (because we hold the lock) know the existing @@ -257,7 +326,8 @@ static ALWAYS_INLINE void k_spin_unlock(struct k_spinlock *l, * Zephyr framework for that. */ atomic_clear(&l->locked); -#endif +#endif /* CONFIG_TICKET_SPINLOCKS */ +#endif /* CONFIG_SMP */ arch_irq_unlock(key.key); } @@ -275,9 +345,15 @@ static ALWAYS_INLINE void k_spin_unlock(struct k_spinlock *l, */ static ALWAYS_INLINE bool z_spin_is_locked(struct k_spinlock *l) { +#ifdef CONFIG_TICKET_SPINLOCKS + atomic_val_t ticket_val = atomic_get(&l->owner); + + return !atomic_cas(&l->tail, ticket_val, ticket_val); +#else return l->locked; +#endif /* CONFIG_TICKET_SPINLOCKS */ } -#endif +#endif /* defined(CONFIG_SMP) && defined(CONFIG_TEST) */ /* Internal function: releases the lock, but leaves local interrupts disabled */ static ALWAYS_INLINE void k_spin_release(struct k_spinlock *l) @@ -287,8 +363,12 @@ static ALWAYS_INLINE void k_spin_release(struct k_spinlock *l) __ASSERT(z_spin_unlock_valid(l), "Not my spinlock %p", l); #endif #ifdef CONFIG_SMP +#ifdef CONFIG_TICKET_SPINLOCKS + atomic_inc(&l->owner); +#else atomic_clear(&l->locked); -#endif +#endif /* CONFIG_TICKET_SPINLOCKS */ +#endif /* CONFIG_SMP */ } #if defined(CONFIG_SPIN_VALIDATE) && defined(__GNUC__) diff --git a/include/zephyr/sw_isr_table.h b/include/zephyr/sw_isr_table.h index 9508e60e24c651c..f43efafad492be5 100644 --- a/include/zephyr/sw_isr_table.h +++ b/include/zephyr/sw_isr_table.h @@ -15,6 +15,7 @@ #define ZEPHYR_INCLUDE_SW_ISR_TABLE_H_ #if !defined(_ASMLANGUAGE) +#include #include #include @@ -23,10 +24,10 @@ extern "C" { #endif /* Default vector for the IRQ vector table */ -extern void _isr_wrapper(void); +void _isr_wrapper(void); /* Spurious interrupt handler. Throws an error if called */ -extern void z_irq_spurious(const void *unused); +void z_irq_spurious(const void *unused); /* * Note the order: arg first, then ISR. This allows a table entry to be @@ -43,6 +44,12 @@ struct _isr_table_entry { */ extern struct _isr_table_entry _sw_isr_table[]; +struct _irq_parent_entry { + const struct device *dev; + unsigned int irq; + unsigned int offset; +}; + /* * Data structure created in a special binary .intlist section for each * configured interrupt. gen_irq_tables.py pulls this out of the binary and @@ -77,16 +84,6 @@ void z_shared_isr(const void *data); extern struct z_shared_isr_table_entry z_shared_sw_isr_table[]; #endif /* CONFIG_SHARED_INTERRUPTS */ -/** - * @brief Helper function used to compute the index in _sw_isr_table - * based on passed IRQ. - * - * @param irq IRQ number in its zephyr format - * - * @return corresponding index in _sw_isr_table - */ -unsigned int z_get_sw_isr_table_idx(unsigned int irq); - /** This interrupt gets put directly in the vector table */ #define ISR_FLAG_DIRECT BIT(0) diff --git a/include/zephyr/sys/arch_interface.h b/include/zephyr/sys/arch_interface.h index e350b1436c163f3..0ffc95c663bc455 100644 --- a/include/zephyr/sys/arch_interface.h +++ b/include/zephyr/sys/arch_interface.h @@ -6,6 +6,7 @@ /** * @defgroup arch-interface Architecture Interface + * @ingroup internal_api * @brief Internal kernel APIs with public scope * * Any public kernel APIs that are implemented as inline functions and need to @@ -215,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 @@ -494,6 +495,9 @@ static inline uint32_t arch_proc_id(void); */ void arch_sched_ipi(void); + +int arch_smp_init(void); + #endif /* CONFIG_SMP */ /** @@ -516,6 +520,8 @@ static inline unsigned int arch_num_cpus(void); */ #ifdef CONFIG_USERSPACE +#include + /** * Invoke a system call with 0 arguments. * @@ -797,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: * @@ -1054,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. + * * @{ */ @@ -1098,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() @@ -1118,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 bcb122bf38aca7d..3982e42803812b2 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 fad339bf93312dc..1225a2e097077e3 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,43 +8,46 @@ #ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_ARCH_H_ #define ZEPHYR_INCLUDE_SYS_ATOMIC_ARCH_H_ +#include +#include + /* Included from */ /* Arch specific atomic primitives */ -extern bool atomic_cas(atomic_t *target, atomic_val_t old_value, +bool atomic_cas(atomic_t *target, atomic_val_t old_value, atomic_val_t new_value); -extern bool atomic_ptr_cas(atomic_ptr_t *target, void *old_value, +bool atomic_ptr_cas(atomic_ptr_t *target, void *old_value, void *new_value); -extern atomic_val_t atomic_add(atomic_t *target, atomic_val_t value); +atomic_val_t atomic_add(atomic_t *target, atomic_val_t value); -extern atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value); +atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value); -extern atomic_val_t atomic_inc(atomic_t *target); +atomic_val_t atomic_inc(atomic_t *target); -extern atomic_val_t atomic_dec(atomic_t *target); +atomic_val_t atomic_dec(atomic_t *target); -extern atomic_val_t atomic_get(const atomic_t *target); +atomic_val_t atomic_get(const atomic_t *target); -extern void *atomic_ptr_get(const atomic_ptr_t *target); +void *atomic_ptr_get(const atomic_ptr_t *target); -extern atomic_val_t atomic_set(atomic_t *target, atomic_val_t value); +atomic_val_t atomic_set(atomic_t *target, atomic_val_t value); -extern void *atomic_ptr_set(atomic_ptr_t *target, void *value); +void *atomic_ptr_set(atomic_ptr_t *target, void *value); -extern atomic_val_t atomic_clear(atomic_t *target); +atomic_val_t atomic_clear(atomic_t *target); -extern void *atomic_ptr_clear(atomic_ptr_t *target); +void *atomic_ptr_clear(atomic_ptr_t *target); -extern atomic_val_t atomic_or(atomic_t *target, atomic_val_t value); +atomic_val_t atomic_or(atomic_t *target, atomic_val_t value); -extern atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value); +atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value); -extern atomic_val_t atomic_and(atomic_t *target, atomic_val_t value); +atomic_val_t atomic_and(atomic_t *target, atomic_val_t value); -extern atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value); +atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value); #endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_ARCH_H_ */ diff --git a/include/zephyr/sys/atomic_builtin.h b/include/zephyr/sys/atomic_builtin.h index 43b40e8bed48df6..5b81a76f05045fd 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 ee368c28f42845f..f1e23caf3625c57 100644 --- a/include/zephyr/sys/atomic_c.h +++ b/include/zephyr/sys/atomic_c.h @@ -39,9 +39,9 @@ static inline atomic_val_t atomic_dec(atomic_t *target) } -extern atomic_val_t atomic_get(const atomic_t *target); +atomic_val_t atomic_get(const atomic_t *target); -extern atomic_ptr_val_t atomic_ptr_get(const atomic_ptr_t *target); +atomic_ptr_val_t atomic_ptr_get(const atomic_ptr_t *target); __syscall atomic_val_t atomic_set(atomic_t *target, atomic_val_t value); @@ -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 000000000000000..33935971f50bdc1 --- /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 978255fd02dab56..d1f839f5188309f 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 a1e8c9632856c76..1930e18b7d40653 100644 --- a/include/zephyr/sys/cbprintf_cxx.h +++ b/include/zephyr/sys/cbprintf_cxx.h @@ -88,6 +88,166 @@ static inline int z_cbprintf_cxx_is_pchar(T arg, bool const_as_fixed) _Pragma("GCC diagnostic pop") } +/* C++ version for determining if variable type is numeric and fits in 32 bit word. */ +static inline int z_cbprintf_cxx_is_word_num(char) +{ + return 1; +} + +static inline int z_cbprintf_cxx_is_word_num(unsigned char) +{ + return 1; +} + +static inline int z_cbprintf_cxx_is_word_num(short) +{ + return 1; +} + +static inline int z_cbprintf_cxx_is_word_num(unsigned short) +{ + return 1; +} + +static inline int z_cbprintf_cxx_is_word_num(int) +{ + return 1; +} + +static inline int z_cbprintf_cxx_is_word_num(unsigned int) +{ + return 1; +} + +static inline int z_cbprintf_cxx_is_word_num(long) +{ + return (sizeof(long) <= sizeof(uint32_t)) ? 1 : 0; +} + +static inline int z_cbprintf_cxx_is_word_num(unsigned long) +{ + return (sizeof(long) <= sizeof(uint32_t)) ? 1 : 0; +} + +template < typename T > +static inline int z_cbprintf_cxx_is_word_num(T arg) +{ + ARG_UNUSED(arg); + _Pragma("GCC diagnostic push") + _Pragma("GCC diagnostic ignored \"-Wpointer-arith\"") + return 0; + _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 61bd250a30c8423..51b99494b962b7f 100644 --- a/include/zephyr/sys/cbprintf_internal.h +++ b/include/zephyr/sys/cbprintf_internal.h @@ -113,6 +113,381 @@ extern "C" { 0) #endif +/** @brief Check if argument fits in 32 bit word. + * + * @param x Input argument. + * + * @retval 1 if variable is of type that fits in 32 bit word. + * @retval 0 if variable is of different type. + */ +#ifdef __cplusplus +#define Z_CBPRINTF_IS_WORD_NUM(x) \ + z_cbprintf_cxx_is_word_num(x) +#else +#define Z_CBPRINTF_IS_WORD_NUM(x) \ + _Generic(x, \ + char : 1, \ + unsigned char : 1, \ + short : 1, \ + unsigned short : 1, \ + int : 1, \ + unsigned int : 1, \ + long : sizeof(long) <= 4, \ + unsigned long : sizeof(long) <= 4, \ + default : \ + 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/device_mmio.h b/include/zephyr/sys/device_mmio.h index 4358e246339d6c1..c50a12782eef22a 100644 --- a/include/zephyr/sys/device_mmio.h +++ b/include/zephyr/sys/device_mmio.h @@ -2,15 +2,6 @@ * Copyright (c) 2020 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 - * - * Definitions and helper macros for managing driver memory-mapped - * input/output (MMIO) regions appropriately in either RAM or ROM. - * - * In most cases drivers will just want to include device.h, but - * including this separately may be needed for arch-level driver code - * which uses the DEVICE_MMIO_TOPLEVEL variants and including the - * main device.h would introduce header dependency loops due to that - * header's reliance on kernel.h. */ #ifndef ZEPHYR_INCLUDE_SYS_DEVICE_MMIO_H #define ZEPHYR_INCLUDE_SYS_DEVICE_MMIO_H @@ -21,6 +12,16 @@ /** * @defgroup device-mmio Device memory-mapped IO management * @ingroup device_model + * + * Definitions and helper macros for managing driver memory-mapped + * input/output (MMIO) regions appropriately in either RAM or ROM. + * + * In most cases drivers will just want to include device.h, but + * including this separately may be needed for arch-level driver code + * which uses the DEVICE_MMIO_TOPLEVEL variants and including the + * main device.h would introduce header dependency loops due to that + * header's reliance on kernel.h. + * * @{ */ @@ -44,7 +45,7 @@ #ifndef _ASMLANGUAGE #include #include -#include +#include #include #ifdef DEVICE_MMIO_IS_IN_RAM @@ -85,12 +86,12 @@ struct z_device_mmio_rom { * * @see k_map() * - * @param virt_addr [out] Output linear address storage location, most - * users will want some DEVICE_MMIO_RAM_PTR() value - * @param phys_addr Physical address base of the MMIO region - * @param size Size of the MMIO region - * @param flags Caching mode and access flags, see K_MEM_CACHE_* and - * K_MEM_PERM_* macros + * @param[out] virt_addr Output linear address storage location, most + * users will want some DEVICE_MMIO_RAM_PTR() value + * @param[in] phys_addr Physical address base of the MMIO region + * @param[in] size Size of the MMIO region + * @param[in] flags Caching mode and access flags, see K_MEM_CACHE_* and + * K_MEM_PERM_* macros */ __boot_func static inline void device_map(mm_reg_t *virt_addr, uintptr_t phys_addr, @@ -161,12 +162,16 @@ struct z_device_mmio_rom { * * Example for a driver named "foo": * + * @code{.c} + * * struct foo_driver_data { * DEVICE_MMIO_RAM; * int wibble; * ... * } * + * @endcode + * * No build-time initialization of this memory is necessary; it * will be set up in the init function by DEVICE_MMIO_MAP(). * @@ -210,12 +215,16 @@ struct z_device_mmio_rom { * * Example for a driver named "foo": * + * @code{.c} + * * struct foo_config { * DEVICE_MMIO_ROM; * int baz; * ... * } * + * @endcode + * * @see DEVICE_MMIO_ROM_INIT() */ #define DEVICE_MMIO_ROM struct z_device_mmio_rom _mmio @@ -240,12 +249,16 @@ struct z_device_mmio_rom { * * Example for a driver belonging to the "foo" subsystem: * + * @code{.c} + * * struct foo_config my_config = { * DEVICE_MMIO_ROM_INIT(DT_DRV_INST(...)), * .baz = 2; * ... * } * + * @endcode + * * @see DEVICE_MMIO_ROM() * * @param node_id DTS node_id @@ -332,6 +345,8 @@ struct z_device_mmio_rom { * * Example for a driver named "foo": * + * @code{.c} + * * struct foo_driver_data { * int blarg; * DEVICE_MMIO_NAMED_RAM(corge); @@ -340,6 +355,8 @@ struct z_device_mmio_rom { * ... * } * + * @endcode + * * No build-time initialization of this memory is necessary; it * will be set up in the init function by DEVICE_MMIO_NAMED_MAP(). * @@ -385,6 +402,8 @@ struct z_device_mmio_rom { * * Example for a driver named "foo": * + * @code{.c} + * * struct foo_config { * int bar; * DEVICE_MMIO_NAMED_ROM(corge); @@ -393,6 +412,8 @@ struct z_device_mmio_rom { * ... * } * + * @endcode + * * @see DEVICE_MMIO_NAMED_ROM_INIT() * * @param name Member name to store within config @@ -422,6 +443,8 @@ struct z_device_mmio_rom { * Example for an instance of a driver belonging to the "foo" subsystem * that will have two regions named 'corge' and 'grault': * + * @code{.c} + * * struct foo_config my_config = { * bar = 7; * DEVICE_MMIO_NAMED_ROM_INIT(corge, DT_DRV_INST(...)); @@ -430,6 +453,8 @@ struct z_device_mmio_rom { * ... * } * + * @endcode + * * @see DEVICE_MMIO_NAMED_ROM() * * @param name Member name within config for the MMIO region diff --git a/include/zephyr/sys/dlist.h b/include/zephyr/sys/dlist.h index 4c330c8f04e41cb..03f2a5e94c802ef 100644 --- a/include/zephyr/sys/dlist.h +++ b/include/zephyr/sys/dlist.h @@ -165,7 +165,7 @@ typedef struct _dnode sys_dnode_t; * } * * @param __dl A pointer on a sys_dlist_t to iterate on - * @param __cn A pointer to peek each entry of the list + * @param __cn A container struct type pointer to peek each entry of the list * @param __n The field name of sys_dnode_t within the container struct */ #define SYS_DLIST_FOR_EACH_CONTAINER(__dl, __cn, __n) \ @@ -184,8 +184,8 @@ typedef struct _dnode sys_dnode_t; * } * * @param __dl A pointer on a sys_dlist_t to iterate on - * @param __cn A pointer to peek each entry of the list - * @param __cns A pointer for the loop to run safely + * @param __cn A container struct type pointer to peek each entry of the list + * @param __cns A container struct type pointer for the loop to run safely * @param __n The field name of sys_dnode_t within the container struct */ #define SYS_DLIST_FOR_EACH_CONTAINER_SAFE(__dl, __cn, __cns, __n) \ diff --git a/include/zephyr/sys/heap_listener.h b/include/zephyr/sys/heap_listener.h index 5923d5e26351a74..a2f49d2a7ed86dc 100644 --- a/include/zephyr/sys/heap_listener.h +++ b/include/zephyr/sys/heap_listener.h @@ -195,7 +195,7 @@ void heap_listener_notify_resize(uintptr_t heap_id, void *old_heap_end, void *ne * @code * void on_heap_alloc(uintptr_t heap_id, void *mem, size_t bytes) * { - * LOG_INF("Memory allocated at %p, size %ld", heap_id, mem, bytes); + * LOG_INF("Memory allocated at %p, size %ld", mem, bytes); * } * * HEAP_LISTENER_ALLOC_DEFINE(my_listener, HEAP_ID_LIBC, on_heap_alloc); @@ -221,7 +221,7 @@ void heap_listener_notify_resize(uintptr_t heap_id, void *old_heap_end, void *ne * @code * void on_heap_free(uintptr_t heap_id, void *mem, size_t bytes) * { - * LOG_INF("Memory freed at %p, size %ld", heap_id, mem, bytes); + * LOG_INF("Memory freed at %p, size %ld", mem, bytes); * } * * HEAP_LISTENER_FREE_DEFINE(my_listener, HEAP_ID_LIBC, on_heap_free); diff --git a/include/zephyr/sys/internal/kobject_internal.h b/include/zephyr/sys/internal/kobject_internal.h new file mode 100644 index 000000000000000..ea19d0f9a8daa28 --- /dev/null +++ b/include/zephyr/sys/internal/kobject_internal.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_SYS_INTERNAL_KOBJECT_INTERNAL_H +#define ZEPHYR_INCLUDE_SYS_INTERNAL_KOBJECT_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup usermode_internal_apis User Mode Internal APIs + * @ingroup internal_api + * @{ + */ + +#if defined(CONFIG_USERSPACE) || defined(__DOXYGEN__) +#if defined(CONFIG_GEN_PRIV_STACKS) || defined(__DOXYGEN__) +/* Metadata struct for K_OBJ_THREAD_STACK_ELEMENT */ +struct z_stack_data { + /* Size of the entire stack object, including reserved areas */ + size_t size; + + /* Stack buffer for privilege mode elevations */ + uint8_t *priv; +}; +#endif /* CONFIG_GEN_PRIV_STACKS */ + +/* Object extra data. Only some objects use this, determined by object type */ +union k_object_data { + /* Backing mutex for K_OBJ_SYS_MUTEX */ + struct k_mutex *mutex; + + /* Numerical thread ID for K_OBJ_THREAD */ + unsigned int thread_id; + +#if defined(CONFIG_GEN_PRIV_STACKS) || defined(__DOXYGEN__) + /* Metadata for K_OBJ_THREAD_STACK_ELEMENT */ + const struct z_stack_data *stack_data; +#else + /* Stack buffer size for K_OBJ_THREAD_STACK_ELEMENT */ + size_t stack_size; +#endif /* CONFIG_GEN_PRIV_STACKS */ + + /* Futex wait queue and spinlock for K_OBJ_FUTEX */ + struct z_futex_data *futex_data; + + /* All other objects */ + int unused; +}; + +/** + * @brief Table generated by gperf, these objects are retrieved via + * k_object_find(). + * + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +struct k_object { + void *name; + uint8_t perms[CONFIG_MAX_THREAD_BYTES]; + uint8_t type; + uint8_t flags; + union k_object_data data; +} __packed __aligned(4); + +struct k_object_assignment { + struct k_thread *thread; + void * const *objects; +}; + + +/** + * Lookup a kernel object and init its metadata if it exists + * + * Calling this on an object will make it usable from userspace. + * Intended to be called as the last statement in kernel object init + * functions. + * + * @param obj Address of the kernel object + * + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +void k_object_init(const void *obj); + + +#else +/* LCOV_EXCL_START */ +static inline void k_object_init(const void *obj) +{ + ARG_UNUSED(obj); +} +/* LCOV_EXCL_STOP */ +#endif /* !CONFIG_USERSPACE */ + +#ifdef CONFIG_DYNAMIC_OBJECTS +/** + * Allocate memory and install as a generic kernel object + * + * This is a low-level function to allocate some memory, and register that + * allocated memory in the kernel object lookup tables with type K_OBJ_ANY. + * Initialization state and thread permissions will be cleared. The + * returned k_object's data value will be uninitialized. + * + * Most users will want to use k_object_alloc() instead. + * + * Memory allocated will be drawn from the calling thread's reasource pool + * and may be freed later by passing the actual object pointer (found + * in the returned k_object's 'name' member) to k_object_free(). + * + * @param align Required memory alignment for the allocated object + * @param size Size of the allocated object + * @return NULL on insufficient memory + * @return A pointer to the associated k_object that is installed in the + * kernel object tables + * + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +struct k_object *k_object_create_dynamic_aligned(size_t align, size_t size); + +/** + * Allocate memory and install as a generic kernel object + * + * This is a low-level function to allocate some memory, and register that + * allocated memory in the kernel object lookup tables with type K_OBJ_ANY. + * Initialization state and thread permissions will be cleared. The + * returned k_object's data value will be uninitialized. + * + * Most users will want to use k_object_alloc() instead. + * + * Memory allocated will be drawn from the calling thread's reasource pool + * and may be freed later by passing the actual object pointer (found + * in the returned k_object's 'name' member) to k_object_free(). + * + * @param size Size of the allocated object + * @return NULL on insufficient memory + * @return A pointer to the associated k_object that is installed in the + * kernel object tables + * + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +static inline struct k_object *k_object_create_dynamic(size_t size) +{ + return k_object_create_dynamic_aligned(0, size); +} + +#else + +/* LCOV_EXCL_START */ +static inline struct k_object *k_object_create_dynamic_aligned(size_t align, + size_t size) +{ + ARG_UNUSED(align); + ARG_UNUSED(size); + + return NULL; +} + +static inline struct k_object *k_object_create_dynamic(size_t size) +{ + ARG_UNUSED(size); + + return NULL; +} + +/* LCOV_EXCL_STOP */ +#endif /* CONFIG_DYNAMIC_OBJECTS */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/zephyr/sys/iterable_sections.h b/include/zephyr/sys/iterable_sections.h index fe1976363ca7aed..3ec4af5e9a089d1 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 c423a7496acad0d..50577ac7c02d369 100644 --- a/include/zephyr/sys/kobject.h +++ b/include/zephyr/sys/kobject.h @@ -10,6 +10,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -48,54 +49,6 @@ enum k_objects { */ #ifdef CONFIG_USERSPACE -#ifdef CONFIG_GEN_PRIV_STACKS -/* Metadata struct for K_OBJ_THREAD_STACK_ELEMENT */ -struct z_stack_data { - /* Size of the entire stack object, including reserved areas */ - size_t size; - - /* Stack buffer for privilege mode elevations */ - uint8_t *priv; -}; -#endif /* CONFIG_GEN_PRIV_STACKS */ - -/* Object extra data. Only some objects use this, determined by object type */ -union z_object_data { - /* Backing mutex for K_OBJ_SYS_MUTEX */ - struct k_mutex *mutex; - - /* Numerical thread ID for K_OBJ_THREAD */ - unsigned int thread_id; - -#ifdef CONFIG_GEN_PRIV_STACKS - /* Metadata for K_OBJ_THREAD_STACK_ELEMENT */ - const struct z_stack_data *stack_data; -#else - /* Stack buffer size for K_OBJ_THREAD_STACK_ELEMENT */ - size_t stack_size; -#endif /* CONFIG_GEN_PRIV_STACKS */ - - /* Futex wait queue and spinlock for K_OBJ_FUTEX */ - struct z_futex_data *futex_data; - - /* All other objects */ - int unused; -}; - -/* Table generated by gperf, these objects are retrieved via - * z_object_find() */ -struct z_object { - void *name; - uint8_t perms[CONFIG_MAX_THREAD_BYTES]; - uint8_t type; - uint8_t flags; - union z_object_data data; -} __packed __aligned(4); - -struct z_object_assignment { - struct k_thread *thread; - void * const *objects; -}; /** * @brief Grant a static thread access to a list of kernel objects @@ -112,7 +65,7 @@ struct z_object_assignment { #define K_THREAD_ACCESS_GRANT(name_, ...) \ static void * const _CONCAT(_object_list_, name_)[] = \ { __VA_ARGS__, NULL }; \ - static const STRUCT_SECTION_ITERABLE(z_object_assignment, \ + static const STRUCT_SECTION_ITERABLE(k_object_assignment, \ _CONCAT(_object_access_, name_)) = \ { (&_k_thread_obj_ ## name_), \ (_CONCAT(_object_list_, name_)) } @@ -126,17 +79,6 @@ struct z_object_assignment { /** Driver Object */ #define K_OBJ_FLAG_DRIVER BIT(3) -/** - * Lookup a kernel object and init its metadata if it exists - * - * Calling this on an object will make it usable from userspace. - * Intended to be called as the last statement in kernel object init - * functions. - * - * @param obj Address of the kernel object - */ -void z_object_init(const void *obj); - /** * Grant a thread access to a kernel object * @@ -209,14 +151,6 @@ bool k_object_is_valid(const void *obj, enum k_objects otype); /* LCOV_EXCL_START */ #define K_THREAD_ACCESS_GRANT(thread, ...) -/** - * @internal - */ -static inline void z_object_init(const void *obj) -{ - ARG_UNUSED(obj); -} - /** * @internal */ @@ -261,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 * @@ -270,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. * @@ -290,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 @@ -297,52 +237,6 @@ __syscall void *k_object_alloc(enum k_objects otype); */ __syscall void *k_object_alloc_size(enum k_objects otype, size_t size); -/** - * Allocate memory and install as a generic kernel object - * - * This is a low-level function to allocate some memory, and register that - * allocated memory in the kernel object lookup tables with type K_OBJ_ANY. - * Initialization state and thread permissions will be cleared. The - * returned z_object's data value will be uninitialized. - * - * Most users will want to use k_object_alloc() instead. - * - * Memory allocated will be drawn from the calling thread's reasource pool - * and may be freed later by passing the actual object pointer (found - * in the returned z_object's 'name' member) to k_object_free(). - * - * @param align Required memory alignment for the allocated object - * @param size Size of the allocated object - * @return NULL on insufficient memory - * @return A pointer to the associated z_object that is installed in the - * kernel object tables - */ -struct z_object *z_dynamic_object_aligned_create(size_t align, size_t size); - -/** - * Allocate memory and install as a generic kernel object - * - * This is a low-level function to allocate some memory, and register that - * allocated memory in the kernel object lookup tables with type K_OBJ_ANY. - * Initialization state and thread permissions will be cleared. The - * returned z_object's data value will be uninitialized. - * - * Most users will want to use k_object_alloc() instead. - * - * Memory allocated will be drawn from the calling thread's reasource pool - * and may be freed later by passing the actual object pointer (found - * in the returned z_object's 'name' member) to k_object_free(). - * - * @param size Size of the allocated object - * @return NULL on insufficient memory - * @return A pointer to the associated z_object that is installed in the - * kernel object tables - */ -static inline struct z_object *z_dynamic_object_create(size_t size) -{ - return z_dynamic_object_aligned_create(0, size); -} - /** * Free a kernel object previously allocated with k_object_alloc() * @@ -350,6 +244,9 @@ static inline struct z_object *z_dynamic_object_create(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); @@ -372,22 +269,6 @@ static inline void *z_impl_k_object_alloc_size(enum k_objects otype, return NULL; } -static inline struct z_object *z_dynamic_object_aligned_create(size_t align, - size_t size) -{ - ARG_UNUSED(align); - ARG_UNUSED(size); - - return NULL; -} - -static inline struct z_object *z_dynamic_object_create(size_t size) -{ - ARG_UNUSED(size); - - return NULL; -} - /** * @brief Free an object * diff --git a/include/zephyr/sys/mem_manage.h b/include/zephyr/sys/mem_manage.h index 1dfbabcc3b0c811..a05b72d3886eccf 100644 --- a/include/zephyr/sys/mem_manage.h +++ b/include/zephyr/sys/mem_manage.h @@ -7,679 +7,56 @@ #ifndef ZEPHYR_INCLUDE_SYS_MEM_MANAGE_H #define ZEPHYR_INCLUDE_SYS_MEM_MANAGE_H -#include -#include -#if defined(CONFIG_ARM_MMU) && defined(CONFIG_ARM64) -#include -#endif - /** * @brief Memory Management * @defgroup memory_management Memory Management * @ingroup os_services * @{ - * @} - */ - -/* - * Caching mode definitions. These are mutually exclusive. - */ - -/** No caching. Most drivers want this. */ -#define K_MEM_CACHE_NONE 2 - -/** Write-through caching. Used by certain drivers. */ -#define K_MEM_CACHE_WT 1 - -/** Full write-back caching. Any RAM mapped wants this. */ -#define K_MEM_CACHE_WB 0 - -/* - * ARM64 Specific flags are defined in arch/arm64/arm_mem.h, - * pay attention to be not conflicted when updating these flags. - */ - -/** Reserved bits for cache modes in k_map() flags argument */ -#define K_MEM_CACHE_MASK (BIT(3) - 1) - -/* - * Region permission attributes. Default is read-only, no user, no exec */ -/** Region will have read/write access (and not read-only) */ -#define K_MEM_PERM_RW BIT(3) - -/** Region will be executable (normally forbidden) */ -#define K_MEM_PERM_EXEC BIT(4) - -/** Region will be accessible to user mode (normally supervisor-only) */ -#define K_MEM_PERM_USER BIT(5) - -/* - * Region mapping behaviour attributes - */ - -/** Region will be mapped to 1:1 virtual and physical address */ -#define K_MEM_DIRECT_MAP BIT(6) - -/* - * This is the offset to subtract from a virtual address mapped in the - * kernel's permanent mapping of RAM, to obtain its physical address. - * - * virt_addr = phys_addr + Z_MEM_VM_OFFSET - * - * This only works for virtual addresses within the interval - * [CONFIG_KERNEL_VM_BASE, CONFIG_KERNEL_VM_BASE + (CONFIG_SRAM_SIZE * 1024)). - * - * These macros are intended for assembly, linker code, and static initializers. - * Use with care. - * - * Note that when demand paging is active, these will only work with page - * frames that are pinned to their virtual mapping at boot. - * - * TODO: This will likely need to move to an arch API or need additional - * constraints defined. - */ -#ifdef CONFIG_MMU -#define Z_MEM_VM_OFFSET ((CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_OFFSET) - \ - (CONFIG_SRAM_BASE_ADDRESS + CONFIG_SRAM_OFFSET)) -#else -#define Z_MEM_VM_OFFSET 0 -#endif - -#define Z_MEM_PHYS_ADDR(virt) ((virt) - Z_MEM_VM_OFFSET) -#define Z_MEM_VIRT_ADDR(phys) ((phys) + Z_MEM_VM_OFFSET) - -#if Z_MEM_VM_OFFSET != 0 -#define Z_VM_KERNEL 1 -#ifdef CONFIG_XIP -#error "XIP and a virtual memory kernel are not allowed" -#endif -#endif - #ifndef _ASMLANGUAGE +#include #include -#include -#include -#include - -struct k_mem_paging_stats_t { -#ifdef CONFIG_DEMAND_PAGING_STATS - struct { - /** Number of page faults */ - unsigned long cnt; - - /** Number of page faults with IRQ locked */ - unsigned long irq_locked; - - /** Number of page faults with IRQ unlocked */ - unsigned long irq_unlocked; - -#ifndef CONFIG_DEMAND_PAGING_ALLOW_IRQ - /** Number of page faults while in ISR */ - unsigned long in_isr; -#endif - } pagefaults; - - struct { - /** Number of clean pages selected for eviction */ - unsigned long clean; - - /** Number of dirty pages selected for eviction */ - unsigned long dirty; - } eviction; -#endif /* CONFIG_DEMAND_PAGING_STATS */ -}; - -struct k_mem_paging_histogram_t { -#ifdef CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM - /* Counts for each bin in timing histogram */ - unsigned long counts[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; - - /* Bounds for the bins in timing histogram, - * excluding the first and last (hence, NUM_SLOTS - 1). - */ - unsigned long bounds[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS]; -#endif /* CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM */ -}; - -/* Just like Z_MEM_PHYS_ADDR() but with type safety and assertions */ -static inline uintptr_t z_mem_phys_addr(void *virt) -{ - uintptr_t addr = (uintptr_t)virt; - -#ifdef CONFIG_MMU - __ASSERT( -#if CONFIG_KERNEL_VM_BASE != 0 - (addr >= CONFIG_KERNEL_VM_BASE) && -#endif - (addr < (CONFIG_KERNEL_VM_BASE + - (CONFIG_KERNEL_VM_SIZE))), - "address %p not in permanent mappings", virt); -#else - /* Should be identity-mapped */ - __ASSERT( -#if CONFIG_SRAM_BASE_ADDRESS != 0 - (addr >= CONFIG_SRAM_BASE_ADDRESS) && -#endif - (addr < (CONFIG_SRAM_BASE_ADDRESS + - (CONFIG_SRAM_SIZE * 1024UL))), - "physical address 0x%lx not in RAM", - (unsigned long)addr); -#endif /* CONFIG_MMU */ - - /* TODO add assertion that this page is pinned to boot mapping, - * the above checks won't be sufficient with demand paging - */ - - return Z_MEM_PHYS_ADDR(addr); -} - -/* Just like Z_MEM_VIRT_ADDR() but with type safety and assertions */ -static inline void *z_mem_virt_addr(uintptr_t phys) -{ - __ASSERT( -#if CONFIG_SRAM_BASE_ADDRESS != 0 - (phys >= CONFIG_SRAM_BASE_ADDRESS) && -#endif - (phys < (CONFIG_SRAM_BASE_ADDRESS + - (CONFIG_SRAM_SIZE * 1024UL))), - "physical address 0x%lx not in RAM", (unsigned long)phys); - - /* TODO add assertion that this page frame is pinned to boot mapping, - * the above check won't be sufficient with demand paging - */ - - return (void *)Z_MEM_VIRT_ADDR(phys); -} - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Map a physical memory region into the kernel's virtual address space - * - * This function is intended for mapping memory-mapped I/O regions into - * the virtual address space. Given a physical address and a size, return a - * linear address representing the base of where the physical region is mapped - * in the virtual address space for the Zephyr kernel. - * - * This function alters the active page tables in the area reserved - * for the kernel. This function will choose the virtual address - * and return it to the caller. - * - * Portable code should never assume that phys_addr and linear_addr will - * be equal. - * - * Caching and access properties are controlled by the 'flags' parameter. - * Unused bits in 'flags' are reserved for future expansion. - * A caching mode must be selected. By default, the region is read-only - * with user access and code execution forbidden. This policy is changed - * by passing K_MEM_CACHE_* and K_MEM_PERM_* macros into the 'flags' parameter. - * - * If there is insufficient virtual address space for the mapping this will - * generate a kernel panic. - * - * This API is only available if CONFIG_MMU is enabled. - * - * It is highly discouraged to use this function to map system RAM page - * frames. It may conflict with anonymous memory mappings and demand paging - * and produce undefined behavior. Do not use this for RAM unless you know - * exactly what you are doing. If you need a chunk of memory, use k_mem_map(). - * If you need a contiguous buffer of physical memory, statically declare it - * and pin it at build time, it will be mapped when the system boots. - * - * 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 - */ -void z_phys_map(uint8_t **virt_ptr, uintptr_t phys, size_t size, - uint32_t flags); - -/** - * Unmap a virtual memory region from kernel's virtual address space. - * - * This function is intended to be used by drivers and early boot routines - * where temporary memory mappings need to be made. This allows these - * memory mappings to be discarded once they are no longer needed. - * - * This function alters the active page tables in the area reserved - * for the kernel. - * - * This will align the input parameters to page boundaries so that - * this can be used with the virtual address as returned by - * z_phys_map(). - * - * This API is only available if CONFIG_MMU is enabled. - * - * It is highly discouraged to use this function to unmap memory mappings. - * It may conflict with anonymous memory mappings and demand paging and - * produce undefined behavior. Do not use this unless you know exactly - * what you are doing. - * - * This API is part of infrastructure still under development and may - * change. - * - * @param virt Starting address of the virtual address region to be unmapped. - * @param size Size of the virtual address region - */ -void z_phys_unmap(uint8_t *virt, size_t size); - -/* - * k_mem_map() control flags - */ - -/** - * @brief The mapped region is not guaranteed to be zeroed. - * - * This may improve performance. The associated page frames may contain - * indeterminate data, zeroes, or even sensitive information. - * - * This may not be used with K_MEM_PERM_USER as there are no circumstances - * where this is safe. - */ -#define K_MEM_MAP_UNINIT BIT(16) /** - * Region will be pinned in memory and never paged + * @brief Check if a physical address is within range of physical memory. * - * Such memory is guaranteed to never produce a page fault due to page-outs - * or copy-on-write once the mapping call has returned. Physical page frames - * will be pre-fetched as necessary and pinned. - */ -#define K_MEM_MAP_LOCK BIT(17) - -/** - * Return the amount of free memory available + * This checks if the physical address (@p virt) is within + * permissible range, e.g. between + * :kconfig:option:`CONFIG_SRAM_BASE_ADDRESS` and + * (:kconfig:option:`CONFIG_SRAM_BASE_ADDRESS` + + * :kconfig:option:`CONFIG_SRAM_SIZE`). * - * The returned value will reflect how many free RAM page frames are available. - * If demand paging is enabled, it may still be possible to allocate more. + * @note Only used if + * :kconfig:option:`CONFIG_KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK` + * is enabled. * - * The information reported by this function may go stale immediately if - * concurrent memory mappings or page-ins take place. + * @param phys Physical address to be checked. * - * @return Free physical RAM, in bytes + * @return True if physical address is within range, false if not. */ -size_t k_mem_free_get(void); +bool sys_mm_is_phys_addr_in_range(uintptr_t phys); /** - * Map anonymous memory into Zephyr's address space - * - * This function effectively increases the data space available to Zephyr. - * The kernel will choose a base virtual address and return it to the caller. - * The memory will have access permissions for all contexts set per the - * provided flags argument. - * - * If user thread access control needs to be managed in any way, do not enable - * K_MEM_PERM_USER flags here; instead manage the region's permissions - * with memory domain APIs after the mapping has been established. Setting - * K_MEM_PERM_USER here will allow all user threads to access this memory - * which is usually undesirable. - * - * Unless K_MEM_MAP_UNINIT is used, the returned memory will be zeroed. - * - * The mapped region is not guaranteed to be physically contiguous in memory. - * Physically contiguous buffers should be allocated statically and pinned - * at build time. - * - * Pages mapped in this way have write-back cache settings. - * - * The returned virtual memory pointer will be page-aligned. The size - * parameter, and any base address for re-mapping purposes must be page- - * aligned. - * - * Note that the allocation includes two guard pages immediately before - * and after the requested region. The total size of the allocation will be - * the requested size plus the size of these two guard pages. - * - * Many K_MEM_MAP_* flags have been implemented to alter the behavior of this - * function, with details in the documentation for these flags. - * - * @param size Size of the memory mapping. This must be page-aligned. - * @param flags K_MEM_PERM_*, K_MEM_MAP_* control flags. - * @return The mapped memory location, or NULL if insufficient virtual address - * space, insufficient physical memory to establish the mapping, - * or insufficient memory for paging structures. - */ -void *k_mem_map(size_t size, uint32_t flags); - -/** - * Un-map mapped memory - * - * This removes a memory mapping for the provided page-aligned region. - * Associated page frames will be free and the kernel may re-use the associated - * virtual address region. Any paged out data pages may be discarded. - * - * Calling this function on a region which was not mapped to begin with is - * undefined behavior. - * - * @param addr Page-aligned memory region base virtual address - * @param size Page-aligned memory region size - */ -void k_mem_unmap(void *addr, size_t size); - -/** - * Given an arbitrary region, provide a aligned region that covers it - * - * 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 - * @retval offset between aligned_addr and addr - */ -size_t k_mem_region_align(uintptr_t *aligned_addr, size_t *aligned_size, - uintptr_t addr, size_t size, size_t align); - -/** - * @defgroup demand_paging Demand Paging - * @ingroup memory_management - */ -/** - * @defgroup mem-demand-paging Demand Paging APIs - * @ingroup demand_paging - * @{ - */ - -/** - * Evict a page-aligned virtual memory region to the backing store - * - * Useful if it is known that a memory region will not be used for some time. - * All the data pages within the specified region will be evicted to the - * backing store if they weren't already, with their associated page frames - * marked as available for mappings or page-ins. + * @brief Check if a virtual address is within range of virtual memory. * - * None of the associated page frames mapped to the provided region should - * be pinned. + * This checks if the virtual address (@p virt) is within + * permissible range, e.g. between + * :kconfig:option:`CONFIG_KERNEL_VM_BASE` and + * (:kconfig:option:`CONFIG_KERNEL_VM_BASE` + + * :kconfig:option:`CONFIG_KERNEL_VM_SIZE`). * - * Note that there are no guarantees how long these pages will be evicted, - * they could take page faults immediately. + * @note Only used if + * :kconfig:option:`CONFIG_KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK` + * is enabled. * - * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be - * called by ISRs as the backing store may be in-use. + * @param virt Virtual address to be checked. * - * @param addr Base page-aligned virtual address - * @param size Page-aligned data region size - * @retval 0 Success - * @retval -ENOMEM Insufficient space in backing store to satisfy request. - * The region may be partially paged out. + * @return True if virtual address is within range, false if not. */ -int k_mem_page_out(void *addr, size_t size); - -/** - * Load a virtual data region into memory - * - * After the function completes, all the page frames associated with this - * function will be paged in. However, they are not guaranteed to stay there. - * This is useful if the region is known to be used soon. - * - * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be - * called by ISRs as the backing store may be in-use. - * - * @param addr Base page-aligned virtual address - * @param size Page-aligned data region size - */ -void k_mem_page_in(void *addr, size_t size); - -/** - * Pin an aligned virtual data region, paging in as necessary - * - * After the function completes, all the page frames associated with this - * region will be resident in memory and pinned such that they stay that way. - * This is a stronger version of z_mem_page_in(). - * - * If CONFIG_DEMAND_PAGING_ALLOW_IRQ is enabled, this function may not be - * called by ISRs as the backing store may be in-use. - * - * @param addr Base page-aligned virtual address - * @param size Page-aligned data region size - */ -void k_mem_pin(void *addr, size_t size); - -/** - * Un-pin an aligned virtual data region - * - * After the function completes, all the page frames associated with this - * region will be no longer marked as pinned. This does not evict the region, - * follow this with z_mem_page_out() if you need that. - * - * @param addr Base page-aligned virtual address - * @param size Page-aligned data region size - */ -void k_mem_unpin(void *addr, size_t size); - -/** - * Get the paging statistics since system startup - * - * This populates the paging statistics struct being passed in - * as argument. - * - * @param[in,out] stats Paging statistics struct to be filled. - */ -__syscall void k_mem_paging_stats_get(struct k_mem_paging_stats_t *stats); - -struct k_thread; -/** - * Get the paging statistics since system startup for a thread - * - * This populates the paging statistics struct being passed in - * as argument for a particular thread. - * - * @param[in] thread Thread - * @param[in,out] stats Paging statistics struct to be filled. - */ -__syscall -void k_mem_paging_thread_stats_get(struct k_thread *thread, - struct k_mem_paging_stats_t *stats); - -/** - * Get the eviction timing histogram - * - * This populates the timing histogram struct being passed in - * as argument. - * - * @param[in,out] hist Timing histogram struct to be filled. - */ -__syscall void k_mem_paging_histogram_eviction_get( - struct k_mem_paging_histogram_t *hist); - -/** - * Get the backing store page-in timing histogram - * - * This populates the timing histogram struct being passed in - * as argument. - * - * @param[in,out] hist Timing histogram struct to be filled. - */ -__syscall void k_mem_paging_histogram_backing_store_page_in_get( - struct k_mem_paging_histogram_t *hist); - -/** - * Get the backing store page-out timing histogram - * - * This populates the timing histogram struct being passed in - * as argument. - * - * @param[in,out] hist Timing histogram struct to be filled. - */ -__syscall void k_mem_paging_histogram_backing_store_page_out_get( - struct k_mem_paging_histogram_t *hist); - -#include +bool sys_mm_is_virt_addr_in_range(void *virt); /** @} */ -/** - * Eviction algorithm APIs - * - * @defgroup mem-demand-paging-eviction Eviction Algorithm APIs - * @ingroup demand_paging - * @{ - */ - -/** - * Select a page frame for eviction - * - * The kernel will invoke this to choose a page frame to evict if there - * are no free page frames. - * - * This function will never be called before the initial - * k_mem_paging_eviction_init(). - * - * This function is invoked with interrupts locked. - * - * @param [out] dirty Whether the page to evict is dirty - * @return The page frame to evict - */ -struct z_page_frame *k_mem_paging_eviction_select(bool *dirty); - -/** - * Initialization function - * - * Called at POST_KERNEL to perform any necessary initialization tasks for the - * eviction algorithm. k_mem_paging_eviction_select() is guaranteed to never be - * called until this has returned, and this will only be called once. - */ -void k_mem_paging_eviction_init(void); - -/** @} */ - -/** - * Backing store APIs - * - * @defgroup mem-demand-paging-backing-store Backing Store APIs - * @ingroup demand_paging - * @{ - */ - -/** - * Reserve or fetch a storage location for a data page loaded into a page frame - * - * The returned location token must be unique to the mapped virtual address. - * This location will be used in the backing store to page out data page - * contents for later retrieval. The location value must be page-aligned. - * - * This function may be called multiple times on the same data page. If its - * page frame has its Z_PAGE_FRAME_BACKED bit set, it is expected to return - * the previous backing store location for the data page containing a cached - * clean copy. This clean copy may be updated on page-out, or used to - * discard clean pages without needing to write out their contents. - * - * If the backing store is full, some other backing store location which caches - * a loaded data page may be selected, in which case its associated page frame - * will have the Z_PAGE_FRAME_BACKED bit cleared (as it is no longer cached). - * - * pf->addr will indicate the virtual address the page is currently mapped to. - * Large, sparse backing stores which can contain the entire address space - * may simply generate location tokens purely as a function of pf->addr with no - * other management necessary. - * - * This function distinguishes whether it was called on behalf of a page - * fault. A free backing store location must always be reserved in order for - * page faults to succeed. If the page_fault parameter is not set, this - * function should return -ENOMEM even if one location is available. - * - * This function is invoked with interrupts locked. - * - * @param pf Virtual address to obtain a storage location - * @param [out] location storage location token - * @param page_fault Whether this request was for a page fault - * @return 0 Success - * @return -ENOMEM Backing store is full - */ -int k_mem_paging_backing_store_location_get(struct z_page_frame *pf, - uintptr_t *location, - bool page_fault); - -/** - * Free a backing store location - * - * Any stored data may be discarded, and the location token associated with - * this address may be re-used for some other data page. - * - * This function is invoked with interrupts locked. - * - * @param location Location token to free - */ -void k_mem_paging_backing_store_location_free(uintptr_t location); - -/** - * Copy a data page from Z_SCRATCH_PAGE to the specified location - * - * Immediately before this is called, Z_SCRATCH_PAGE will be mapped read-write - * to the intended source page frame for the calling context. - * - * Calls to this and k_mem_paging_backing_store_page_in() will always be - * serialized, but interrupts may be enabled. - * - * @param location Location token for the data page, for later retrieval - */ -void k_mem_paging_backing_store_page_out(uintptr_t location); - -/** - * Copy a data page from the provided location to Z_SCRATCH_PAGE. - * - * Immediately before this is called, Z_SCRATCH_PAGE will be mapped read-write - * to the intended destination page frame for the calling context. - * - * Calls to this and k_mem_paging_backing_store_page_out() will always be - * serialized, but interrupts may be enabled. - * - * @param location Location token for the data page - */ -void k_mem_paging_backing_store_page_in(uintptr_t location); - -/** - * Update internal accounting after a page-in - * - * This is invoked after k_mem_paging_backing_store_page_in() and interrupts - * have been* re-locked, making it safe to access the z_page_frame data. - * The location value will be the same passed to - * k_mem_paging_backing_store_page_in(). - * - * The primary use-case for this is to update custom fields for the backing - * store in the page frame, to reflect where the data should be evicted to - * if it is paged out again. This may be a no-op in some implementations. - * - * If the backing store caches paged-in data pages, this is the appropriate - * time to set the Z_PAGE_FRAME_BACKED bit. The kernel only skips paging - * out clean data pages if they are noted as clean in the page tables and the - * Z_PAGE_FRAME_BACKED bit is set in their associated page frame. - * - * @param pf Page frame that was loaded in - * @param location Location of where the loaded data page was retrieved - */ -void k_mem_paging_backing_store_page_finalize(struct z_page_frame *pf, - uintptr_t location); - -/** - * Backing store initialization function. - * - * The implementation may expect to receive page in/out calls as soon as this - * returns, but not before that. Called at POST_KERNEL. - * - * This function is expected to do two things: - * - Initialize any internal data structures and accounting for the backing - * store. - * - If the backing store already contains all or some loaded kernel data pages - * at boot time, Z_PAGE_FRAME_BACKED should be appropriately set for their - * associated page frames, and any internal accounting set up appropriately. - */ -void k_mem_paging_backing_store_init(void); - -/** @} */ - -#ifdef __cplusplus -} -#endif - #endif /* !_ASMLANGUAGE */ #endif /* ZEPHYR_INCLUDE_SYS_MEM_MANAGE_H */ diff --git a/include/zephyr/sys/mpsc_pbuf.h b/include/zephyr/sys/mpsc_pbuf.h index a80cc2db4646428..72f6e99515b89ee 100644 --- a/include/zephyr/sys/mpsc_pbuf.h +++ b/include/zephyr/sys/mpsc_pbuf.h @@ -19,7 +19,7 @@ extern "C" { /** * @brief Multi producer, single consumer packet buffer API * @defgroup mpsc_buf MPSC (Multi producer, single consumer) packet buffer API - * @ingroup kernel_apis + * @ingroup datastructure_apis * @{ */ diff --git a/include/zephyr/sys/multi_heap.h b/include/zephyr/sys/multi_heap.h index 1eebc1c150ee09f..0b8c56bdbe0bd8f 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/printk.h b/include/zephyr/sys/printk.h index b5821ed971e0c19..795018ae4f886da 100644 --- a/include/zephyr/sys/printk.h +++ b/include/zephyr/sys/printk.h @@ -44,8 +44,8 @@ extern "C" { */ #ifdef CONFIG_PRINTK -extern __printf_like(1, 2) void printk(const char *fmt, ...); -extern __printf_like(1, 0) void vprintk(const char *fmt, va_list ap); +__printf_like(1, 2) void printk(const char *fmt, ...); +__printf_like(1, 0) void vprintk(const char *fmt, va_list ap); #else static inline __printf_like(1, 2) void printk(const char *fmt, ...) @@ -69,9 +69,9 @@ static inline __printf_like(1, 0) void vprintk(const char *fmt, va_list ap) #else -extern __printf_like(3, 4) int snprintk(char *str, size_t size, +__printf_like(3, 4) int snprintk(char *str, size_t size, const char *fmt, ...); -extern __printf_like(3, 0) int vsnprintk(char *str, size_t size, +__printf_like(3, 0) int vsnprintk(char *str, size_t size, const char *fmt, va_list ap); #endif diff --git a/include/zephyr/sys/reboot.h b/include/zephyr/sys/reboot.h index 50d688706831350..293a5875451c2bf 100644 --- a/include/zephyr/sys/reboot.h +++ b/include/zephyr/sys/reboot.h @@ -32,7 +32,7 @@ extern "C" { * * When successful, this routine does not return. */ -extern FUNC_NORETURN void sys_reboot(int type); +FUNC_NORETURN void sys_reboot(int type); #ifdef __cplusplus } diff --git a/include/zephyr/sys/spsc_pbuf.h b/include/zephyr/sys/spsc_pbuf.h index 682d610e34b4fef..0e7f018fa63cccf 100644 --- a/include/zephyr/sys/spsc_pbuf.h +++ b/include/zephyr/sys/spsc_pbuf.h @@ -16,11 +16,12 @@ extern "C" { /** * @brief Single producer, single consumer packet buffer API - * @ingroup kernel_apis + * @defgroup spsc_buf SPSC (Single producer, single consumer) packet buffer API + * @ingroup datastructure_apis * @{ */ -/**@defgroup SPSC_PBUF_FLAGS MPSC packet buffer flags +/**@defgroup SPSC_PBUF_FLAGS SPSC packet buffer flags * @{ */ diff --git a/include/zephyr/sys/time_units.h b/include/zephyr/sys/time_units.h index 7f2db1a1f5552fa..62c199bc488d9c8 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 b3cbb917b46e8b6..71ed1f7f45d7095 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 * @@ -250,6 +268,20 @@ extern "C" { ((type *)(((char *)(ptr)) - offsetof(type, field))); \ }) +/** + * @brief Concatenate input arguments + * + * 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(...) \ + 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. */ @@ -630,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 2cde08332e23996..d3adca606403864 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 ff64e7b1ef98680..8c71edd16f363cf 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 02d0e9885a6b0e3..81df23f9150bf62 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/syscall_handler.h b/include/zephyr/syscall_handler.h deleted file mode 100644 index 7e06c5a7a548a79..000000000000000 --- a/include/zephyr/syscall_handler.h +++ /dev/null @@ -1,552 +0,0 @@ -/* - * Copyright (c) 2017, Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef ZEPHYR_INCLUDE_SYSCALL_HANDLER_H_ -#define ZEPHYR_INCLUDE_SYSCALL_HANDLER_H_ - -#ifdef CONFIG_USERSPACE - -#ifndef _ASMLANGUAGE -#include -#include -#include -#include -#include - -extern const _k_syscall_handler_t _k_syscall_table[K_SYSCALL_LIMIT]; - -enum _obj_init_check { - _OBJ_INIT_TRUE = 0, - _OBJ_INIT_FALSE = -1, - _OBJ_INIT_ANY = 1 -}; - -/** - * Return true if we are currently handling a system call from user mode - * - * Inside z_vrfy functions, we always know that we are handling - * a system call invoked from user context. - * - * However, some checks that are only relevant to user mode must - * instead be placed deeper within the implementation. This - * API is useful to conditionally make these checks. - * - * For performance reasons, whenever possible, checks should be placed - * in the relevant z_vrfy function since these are completely skipped - * when a syscall is invoked. - * - * This will return true only if we are handling a syscall for a - * user thread. If the system call was invoked from supervisor mode, - * or we are not handling a system call, this will return false. - * - * @return whether the current context is handling a syscall for a user - * mode thread - */ -static inline bool z_is_in_user_syscall(void) -{ - /* This gets set on entry to the syscall's generasted z_mrsh - * function and then cleared on exit. This code path is only - * encountered when a syscall is made from user mode, system - * calls from supervisor mode bypass everything directly to - * the implementation function. - */ - return !k_is_in_isr() && _current->syscall_frame != NULL; -} - -/** - * Ensure a system object is a valid object of the expected type - * - * Searches for the object and ensures that it is indeed an object - * of the expected type, that the caller has the right permissions on it, - * and that the object has been initialized. - * - * This function is intended to be called on the kernel-side system - * call handlers to validate kernel object pointers passed in from - * userspace. - * - * @param ko Kernel object metadata pointer, or NULL - * @param otype Expected type of the kernel object, or K_OBJ_ANY if type - * doesn't matter - * @param init Indicate whether the object needs to already be in initialized - * or uninitialized state, or that we don't care - * @return 0 If the object is valid - * -EBADF if not a valid object of the specified type - * -EPERM If the caller does not have permissions - * -EINVAL Object is not initialized - */ -int z_object_validate(struct z_object *ko, enum k_objects otype, - enum _obj_init_check init); - -/** - * Dump out error information on failed z_object_validate() call - * - * @param retval Return value from z_object_validate() - * @param obj Kernel object we were trying to verify - * @param ko If retval=-EPERM, struct z_object * that was looked up, or NULL - * @param otype Expected type of the kernel object - */ -extern void z_dump_object_error(int retval, const void *obj, - struct z_object *ko, enum k_objects otype); - -/** - * Kernel object validation function - * - * Retrieve metadata for a kernel object. This function is implemented in - * the gperf script footer, see gen_kobject_list.py - * - * @param obj Address of kernel object to get metadata - * @return Kernel object's metadata, or NULL if the parameter wasn't the - * memory address of a kernel object - */ -extern struct z_object *z_object_find(const void *obj); - -typedef void (*_wordlist_cb_func_t)(struct z_object *ko, void *context); - -/** - * Iterate over all the kernel object metadata in the system - * - * @param func function to run on each struct z_object - * @param context Context pointer to pass to each invocation - */ -extern void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context); - -/** - * Copy all kernel object permissions from the parent to the child - * - * @param parent Parent thread, to get permissions from - * @param child Child thread, to copy permissions to - */ -extern void z_thread_perms_inherit(struct k_thread *parent, - struct k_thread *child); - -/** - * Grant a thread permission to a kernel object - * - * @param ko Kernel object metadata to update - * @param thread The thread to grant permission - */ -extern void z_thread_perms_set(struct z_object *ko, struct k_thread *thread); - -/** - * Revoke a thread's permission to a kernel object - * - * @param ko Kernel object metadata to update - * @param thread The thread to grant permission - */ -extern void z_thread_perms_clear(struct z_object *ko, struct k_thread *thread); - -/* - * Revoke access to all objects for the provided thread - * - * NOTE: Unlike z_thread_perms_clear(), this function will not clear - * permissions on public objects. - * - * @param thread Thread object to revoke access - */ -extern void z_thread_perms_all_clear(struct k_thread *thread); - -/** - * Clear initialization state of a kernel object - * - * Intended for thread objects upon thread exit, or for other kernel objects - * that were released back to an object pool. - * - * @param object Address of the kernel object - */ -void z_object_uninit(const void *obj); - -/** - * Initialize and reset permissions to only access by the caller - * - * Intended for scenarios where objects are fetched from slab pools - * and may have had different permissions set during prior usage. - * - * This is only intended for pools of objects, where such objects are - * acquired and released to the pool. If an object has already been used, - * we do not want stale permission information hanging around, the object - * should only have permissions on the caller. Objects which are not - * managed by a pool-like mechanism should not use this API. - * - * The object will be marked as initialized and the calling thread - * granted access to it. - * - * @param object Address of the kernel object - */ -void z_object_recycle(const void *obj); - -/** - * @brief Obtain the size of a C string passed from user mode - * - * Given a C string pointer and a maximum size, obtain the true - * size of the string (not including the trailing NULL byte) just as - * if calling strnlen() on it, with the same semantics of strnlen() with - * respect to the return value and the maxlen parameter. - * - * Any memory protection faults triggered by the examination of the string - * will be safely handled and an error code returned. - * - * NOTE: Doesn't guarantee that user mode has actual access to this - * string, you will need to still do a Z_SYSCALL_MEMORY_READ() - * with the obtained size value to guarantee this. - * - * @param src String to measure size of - * @param maxlen Maximum number of characters to examine - * @param err Pointer to int, filled in with -1 on memory error, 0 on - * success - * @return undefined on error, or strlen(src) if that is less than maxlen, or - * maxlen if there were no NULL terminating characters within the - * first maxlen bytes. - */ -static inline size_t z_user_string_nlen(const char *src, size_t maxlen, - int *err) -{ - return arch_user_string_nlen(src, maxlen, err); -} - -/** - * @brief Copy data from userspace into a resource pool allocation - * - * Given a pointer and a size, allocate a similarly sized buffer in the - * caller's resource pool and copy all the data within it to the newly - * allocated buffer. This will need to be freed later with k_free(). - * - * Checks are done to ensure that the current thread would have read - * access to the provided buffer. - * - * @param src Source memory address - * @param size Size of the memory buffer - * @return An allocated buffer with the data copied within it, or NULL - * if some error condition occurred - */ -extern void *z_user_alloc_from_copy(const void *src, size_t size); - -/** - * @brief Copy data from user mode - * - * Given a userspace pointer and a size, copies data from it into a provided - * destination buffer, performing checks to ensure that the caller would have - * appropriate access when in user mode. - * - * @param dst Destination memory buffer - * @param src Source memory buffer, in userspace - * @param size Number of bytes to copy - * @retval 0 On success - * @retval EFAULT On memory access error - */ -extern int z_user_from_copy(void *dst, const void *src, size_t size); - -/** - * @brief Copy data to user mode - * - * Given a userspace pointer and a size, copies data to it from a provided - * source buffer, performing checks to ensure that the caller would have - * appropriate access when in user mode. - * - * @param dst Destination memory buffer, in userspace - * @param src Source memory buffer - * @param size Number of bytes to copy - * @retval 0 On success - * @retval EFAULT On memory access error - */ -extern int z_user_to_copy(void *dst, const void *src, size_t size); - -/** - * @brief Copy a C string from userspace into a resource pool allocation - * - * Given a C string and maximum length, duplicate the string using an - * allocation from the calling thread's resource pool. This will need to be - * freed later with k_free(). - * - * Checks are performed to ensure that the string is valid memory and that - * the caller has access to it in user mode. - * - * @param src Source string pointer, in userspace - * @param maxlen Maximum size of the string including trailing NULL - * @return The duplicated string, or NULL if an error occurred. - */ -extern char *z_user_string_alloc_copy(const char *src, size_t maxlen); - -/** - * @brief Copy a C string from userspace into a provided buffer - * - * Given a C string and maximum length, copy the string into a buffer. - * - * Checks are performed to ensure that the string is valid memory and that - * the caller has access to it in user mode. - * - * @param dst Destination buffer - * @param src Source string pointer, in userspace - * @param maxlen Maximum size of the string including trailing NULL - * @retval 0 on success - * @retval EINVAL if the source string is too long with respect - * to maxlen - * @retval EFAULT On memory access error - */ -extern int z_user_string_copy(char *dst, const char *src, size_t maxlen); - -#define Z_OOPS(expr) \ - do { \ - if (expr) { \ - arch_syscall_oops(_current->syscall_frame); \ - } \ - } while (false) - -/** - * @brief Runtime expression check for system call arguments - * - * Used in handler functions to perform various runtime checks on arguments, - * and generate a kernel oops if anything is not expected, printing a custom - * message. - * - * @param expr Boolean expression to verify, a false result will trigger an - * oops - * @param fmt Printf-style format string (followed by appropriate variadic - * arguments) to print on verification failure - * @return False on success, True on failure - */ -#define Z_SYSCALL_VERIFY_MSG(expr, fmt, ...) ({ \ - bool expr_copy = !(expr); \ - if (expr_copy) { \ - TOOLCHAIN_IGNORE_WSHADOW_BEGIN \ - LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); \ - TOOLCHAIN_IGNORE_WSHADOW_END \ - LOG_ERR("syscall %s failed check: " fmt, \ - __func__, ##__VA_ARGS__); \ - } \ - expr_copy; }) - -/** - * @brief Runtime expression check for system call arguments - * - * Used in handler functions to perform various runtime checks on arguments, - * and generate a kernel oops if anything is not expected. - * - * @param expr Boolean expression to verify, a false result will trigger an - * oops. A stringified version of this expression will be printed. - * @return 0 on success, nonzero on failure - */ -#define Z_SYSCALL_VERIFY(expr) Z_SYSCALL_VERIFY_MSG(expr, #expr) - -/** - * @brief Runtime check that a user thread has read and/or write permission to - * a memory area - * - * Checks that the particular memory area is readable and/or writeable by the - * currently running thread if the CPU was in user mode, and generates a kernel - * oops if it wasn't. Prevents userspace from getting the kernel to read and/or - * modify memory the thread does not have access to, or passing in garbage - * pointers that would crash/pagefault the kernel if dereferenced. - * - * @param ptr Memory area to examine - * @param size Size of the memory area - * @param write If the thread should be able to write to this memory, not just - * read it - * @return 0 on success, nonzero on failure - */ -#define Z_SYSCALL_MEMORY(ptr, size, write) \ - Z_SYSCALL_VERIFY_MSG(arch_buffer_validate((void *)ptr, size, write) \ - == 0, \ - "Memory region %p (size %zu) %s access denied", \ - (void *)(ptr), (size_t)(size), \ - write ? "write" : "read") - -/** - * @brief Runtime check that a user thread has read permission to a memory area - * - * Checks that the particular memory area is readable by the currently running - * thread if the CPU was in user mode, and generates a kernel oops if it - * wasn't. Prevents userspace from getting the kernel to read memory the thread - * does not have access to, or passing in garbage pointers that would - * crash/pagefault the kernel if dereferenced. - * - * @param ptr Memory area to examine - * @param size Size of the memory area - * @return 0 on success, nonzero on failure - */ -#define Z_SYSCALL_MEMORY_READ(ptr, size) \ - Z_SYSCALL_MEMORY(ptr, size, 0) - -/** - * @brief Runtime check that a user thread has write permission to a memory area - * - * Checks that the particular memory area is readable and writable by the - * currently running thread if the CPU was in user mode, and generates a kernel - * oops if it wasn't. Prevents userspace from getting the kernel to read or - * modify memory the thread does not have access to, or passing in garbage - * pointers that would crash/pagefault the kernel if dereferenced. - * - * @param ptr Memory area to examine - * @param size Size of the memory area - * @param 0 on success, nonzero on failure - */ -#define Z_SYSCALL_MEMORY_WRITE(ptr, size) \ - Z_SYSCALL_MEMORY(ptr, size, 1) - -#define Z_SYSCALL_MEMORY_ARRAY(ptr, nmemb, size, write) \ - ({ \ - size_t product; \ - Z_SYSCALL_VERIFY_MSG(!size_mul_overflow((size_t)(nmemb), \ - (size_t)(size), \ - &product), \ - "%zux%zu array is too large", \ - (size_t)(nmemb), (size_t)(size)) || \ - Z_SYSCALL_MEMORY(ptr, product, write); \ - }) - -/** - * @brief Validate user thread has read permission for sized array - * - * Used when the memory region is expressed in terms of number of elements and - * each element size, handles any overflow issues with computing the total - * array bounds. Otherwise see _SYSCALL_MEMORY_READ. - * - * @param ptr Memory area to examine - * @param nmemb Number of elements in the array - * @param size Size of each array element - * @return 0 on success, nonzero on failure - */ -#define Z_SYSCALL_MEMORY_ARRAY_READ(ptr, nmemb, size) \ - Z_SYSCALL_MEMORY_ARRAY(ptr, nmemb, size, 0) - -/** - * @brief Validate user thread has read/write permission for sized array - * - * Used when the memory region is expressed in terms of number of elements and - * each element size, handles any overflow issues with computing the total - * array bounds. Otherwise see _SYSCALL_MEMORY_WRITE. - * - * @param ptr Memory area to examine - * @param nmemb Number of elements in the array - * @param size Size of each array element - * @return 0 on success, nonzero on failure - */ -#define Z_SYSCALL_MEMORY_ARRAY_WRITE(ptr, nmemb, size) \ - Z_SYSCALL_MEMORY_ARRAY(ptr, nmemb, size, 1) - -static inline int z_obj_validation_check(struct z_object *ko, - const void *obj, - enum k_objects otype, - enum _obj_init_check init) -{ - int ret; - - ret = z_object_validate(ko, otype, init); - -#ifdef CONFIG_LOG - if (ret != 0) { - z_dump_object_error(ret, obj, ko, otype); - } -#else - ARG_UNUSED(obj); -#endif - - return ret; -} - -#define Z_SYSCALL_IS_OBJ(ptr, type, init) \ - Z_SYSCALL_VERIFY_MSG(z_obj_validation_check( \ - z_object_find((const void *)ptr), \ - (const void *)ptr, \ - type, init) == 0, "access denied") - -/** - * @brief Runtime check driver object pointer for presence of operation - * - * Validates if the driver object is capable of performing a certain operation. - * - * @param ptr Untrusted device instance object pointer - * @param api_struct Name of the driver API struct (e.g. gpio_driver_api) - * @param op Driver operation (e.g. manage_callback) - * @return 0 on success, nonzero on failure - */ -#define Z_SYSCALL_DRIVER_OP(ptr, api_name, op) \ - ({ \ - struct api_name *__device__ = (struct api_name *) \ - ((const struct device *)ptr)->api; \ - Z_SYSCALL_VERIFY_MSG(__device__->op != NULL, \ - "Operation %s not defined for driver " \ - "instance %p", \ - # op, __device__); \ - }) - -/** - * @brief Runtime check that device object is of a specific driver type - * - * Checks that the driver object passed in is initialized, the caller has - * correct permissions, and that it belongs to the specified driver - * subsystems. Additionally, all devices store a structure pointer of the - * driver's API. If this doesn't match the value provided, the check will fail. - * - * This provides an easy way to determine if a device object not only - * belongs to a particular subsystem, but is of a specific device driver - * implementation. Useful for defining out-of-subsystem system calls - * which are implemented for only one driver. - * - * @param _device Untrusted device pointer - * @param _dtype Expected kernel object type for the provided device pointer - * @param _api Expected driver API structure memory address - * @return 0 on success, nonzero on failure - */ -#define Z_SYSCALL_SPECIFIC_DRIVER(_device, _dtype, _api) \ - ({ \ - const struct device *_dev = (const struct device *)_device; \ - Z_SYSCALL_OBJ(_dev, _dtype) || \ - Z_SYSCALL_VERIFY_MSG(_dev->api == _api, \ - "API structure mismatch"); \ - }) - -/** - * @brief Runtime check kernel object pointer for non-init functions - * - * Calls z_object_validate and triggers a kernel oops if the check fails. - * For use in system call handlers which are not init functions; a fatal - * error will occur if the object is not initialized. - * - * @param ptr Untrusted kernel object pointer - * @param type Expected kernel object type - * @return 0 on success, nonzero on failure - */ -#define Z_SYSCALL_OBJ(ptr, type) \ - Z_SYSCALL_IS_OBJ(ptr, type, _OBJ_INIT_TRUE) - -/** - * @brief Runtime check kernel object pointer for non-init functions - * - * See description of _SYSCALL_IS_OBJ. No initialization checks are done. - * Intended for init functions where objects may be re-initialized at will. - * - * @param ptr Untrusted kernel object pointer - * @param type Expected kernel object type - * @return 0 on success, nonzero on failure - */ - -#define Z_SYSCALL_OBJ_INIT(ptr, type) \ - Z_SYSCALL_IS_OBJ(ptr, type, _OBJ_INIT_ANY) - -/** - * @brief Runtime check kernel object pointer for non-init functions - * - * See description of _SYSCALL_IS_OBJ. Triggers a fatal error if the object is - * initialized. Intended for init functions where objects, once initialized, - * can only be re-used when their initialization state expires due to some - * other mechanism. - * - * @param ptr Untrusted kernel object pointer - * @param type Expected kernel object type - * @return 0 on success, nonzero on failure - */ - -#define Z_SYSCALL_OBJ_NEVER_INIT(ptr, type) \ - Z_SYSCALL_IS_OBJ(ptr, type, _OBJ_INIT_FALSE) - -#include - -#endif /* _ASMLANGUAGE */ - -#endif /* CONFIG_USERSPACE */ - -#endif /* ZEPHYR_INCLUDE_SYSCALL_HANDLER_H_ */ diff --git a/include/zephyr/timing/timing.h b/include/zephyr/timing/timing.h index bf9ee9033e96a01..a0c4a644abb82f9 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 a0e325cfa2885e2..e086c644e879654 100644 --- a/include/zephyr/toolchain/gcc.h +++ b/include/zephyr/toolchain/gcc.h @@ -200,8 +200,13 @@ do { \ #if !defined(CONFIG_XIP) #define __ramfunc #elif defined(CONFIG_ARCH_HAS_RAMFUNC_SUPPORT) +#if defined(CONFIG_ARM) #define __ramfunc __attribute__((noinline)) \ __attribute__((long_call, section(".ramfunc"))) +#else +#define __ramfunc __attribute__((noinline)) \ + __attribute__((section(".ramfunc"))) +#endif #endif /* !CONFIG_XIP */ #ifndef __fallthrough @@ -269,6 +274,10 @@ do { \ #define __weak __attribute__((__weak__)) #endif +#ifndef __attribute_nonnull +#define __attribute_nonnull(...) __attribute__((nonnull(__VA_ARGS__))) +#endif + /* Builtins with availability that depend on the compiler version. */ #if __GNUC__ >= 5 #define HAS_BUILTIN___builtin_add_overflow 1 @@ -639,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 baf9632a30d0784..f1bbddeec51436b 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 8cc21e7a573f1f6..8fc380b970e0bbd 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/usbd.h b/include/zephyr/usb/usbd.h index aad53b47550339b..28d27f10723f107 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]; }; @@ -701,37 +701,18 @@ int usbd_device_set_pid(struct usbd_contex *const uds_ctx, const uint16_t pid); /** - * @brief Set USB device descriptor value bDeviceClass + * @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 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 - * - * @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/usb_c/usbc.h b/include/zephyr/usb_c/usbc.h index 0a37b081838e9d9..db3045d03c1fde5 100644 --- a/include/zephyr/usb_c/usbc.h +++ b/include/zephyr/usb_c/usbc.h @@ -350,6 +350,15 @@ int usbc_suspend(const struct device *dev); */ int usbc_request(const struct device *dev, const enum usbc_policy_request_t req); +/** + * @internal + * @brief Bypass the next USB-C stack sleep and execute one more iteration of the state machines. + * Used internally to decrease the response time. + * + * @param dev Runtime device structure + */ +void usbc_bypass_next_sleep(const struct device *dev); + /** * @brief Set pointer to Device Policy Manager (DPM) data * diff --git a/include/zephyr/zbus/zbus.h b/include/zephyr/zbus/zbus.h index 8a4188aa821dec9..2c0c0622aed5da2 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. */ @@ -148,6 +165,14 @@ struct zbus_channel_observation { const struct zbus_observer *const obs; }; +#ifdef __cplusplus +#define _ZBUS_CPP_EXTERN extern +#else +#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 { \ @@ -225,9 +250,9 @@ struct zbus_channel_observation { #define _ZBUS_RUNTIME_OBSERVERS_DECL(_name) #endif /* CONFIG_ZBUS_RUNTIME_OBSERVERS */ -k_timeout_t _zbus_timeout_remainder(uint64_t end_ticks); /** @endcond */ +/* clang-format off */ /** * @brief Add a static channel observervation. * @@ -241,11 +266,15 @@ k_timeout_t _zbus_timeout_remainder(uint64_t end_ticks); */ #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. * @@ -285,6 +314,7 @@ k_timeout_t _zbus_timeout_remainder(uint64_t end_ticks); */ #define ZBUS_OBSERVERS(...) __VA_ARGS__ +/* clang-format off */ /** * @brief Zbus channel definition. * @@ -300,20 +330,29 @@ k_timeout_t _zbus_timeout_remainder(uint64_t end_ticks); * 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)); \ - 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. @@ -329,6 +368,7 @@ k_timeout_t _zbus_timeout_remainder(uint64_t end_ticks); _val, ##__VA_ARGS__ \ } +/* clang-format off */ /** * @brief Define and initialize a subscriber. * @@ -340,13 +380,25 @@ k_timeout_t _zbus_timeout_remainder(uint64_t end_ticks); * @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. * @@ -361,6 +413,7 @@ k_timeout_t _zbus_timeout_remainder(uint64_t end_ticks); #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. * @@ -373,10 +426,20 @@ k_timeout_t _zbus_timeout_remainder(uint64_t end_ticks); * @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. * @@ -389,6 +452,7 @@ k_timeout_t _zbus_timeout_remainder(uint64_t end_ticks); */ #define ZBUS_LISTENER_DEFINE(_name, _cb) ZBUS_LISTENER_DEFINE_WITH_ENABLE(_name, _cb, true) +/* clang-format off */ /** * @brief Define and initialize a message subscriber. * @@ -399,14 +463,21 @@ k_timeout_t _zbus_timeout_remainder(uint64_t end_ticks); * @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. @@ -496,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. */ @@ -514,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. @@ -548,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. @@ -569,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. @@ -680,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. @@ -704,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; } @@ -761,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 e628cfec6693c6d..cd9f39c9558ca1f 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -21,9 +21,15 @@ zephyr_syscall_header_ifdef( zephyr_syscall_header_ifdef( CONFIG_MMU + ${ZEPHYR_BASE}/include/zephyr/kernel/mm.h ${ZEPHYR_BASE}/include/zephyr/sys/mem_manage.h ) +zephyr_syscall_header_ifdef( + CONFIG_DEMAND_PAGING + ${ZEPHYR_BASE}/include/zephyr/kernel/mm/demand_paging.h +) + # If a pre-built static library containing kernel code exists in # this directory, libkernel.a, link it with the application code # instead of building from source. @@ -53,6 +59,7 @@ list(APPEND kernel_files mem_slab.c thread.c version.c + sched.c ) if(CONFIG_MULTITHREADING) @@ -66,7 +73,6 @@ list(APPEND kernel_files stack.c system_work_q.c work.c - sched.c condvar.c ) @@ -111,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 2178b041cfdb63b..1620a3c9aa4c696 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -201,7 +201,7 @@ config THREAD_CUSTOM_DATA config THREAD_USERSPACE_LOCAL_DATA bool depends on USERSPACE - default y if ERRNO && !ERRNO_IN_TLS + default y if ERRNO && !ERRNO_IN_TLS && !LIBC_ERRNO config DYNAMIC_THREAD bool "Support for dynamic threads [EXPERIMENTAL]" @@ -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 @@ -382,6 +396,16 @@ config INIT_STACKS water mark can be easily determined. This applies to the stack areas for threads, as well as to the interrupt stack. +config SKIP_BSS_CLEAR + bool + help + This option disables software .bss section zeroing during Zephyr + initialization. Such boot-time optimization could be used for + platforms where .bss section is zeroed-out externally. + Please pay attention that when this option is enabled + the responsibility for .bss zeroing in all possible scenarios + (mind e.g. SW reset) is delegated to the external SW or HW. + config BOOT_BANNER bool "Boot banner" default y @@ -651,6 +675,7 @@ menu "Work Queue Options" config SYSTEM_WORKQUEUE_STACK_SIZE int "System workqueue stack size" default 4096 if COVERAGE_GCOV + default 2560 if WIFI_NM_WPA_SUPPLICANT default 1024 config SYSTEM_WORKQUEUE_PRIORITY @@ -810,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 @@ -1137,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]" @@ -1193,6 +1234,19 @@ config KERNEL_COHERENCE may fail strangely. Some assertions exist to catch these mistakes, but not all circumstances can be tested. +config TICKET_SPINLOCKS + bool "Ticket spinlocks for lock acquisition fairness [EXPERIMENTAL]" + select EXPERIMENTAL + help + Basic spinlock implementation is based on single + atomic variable and doesn't guarantee locking fairness + across multiple CPUs. It's even possible that single CPU + will win the contention every time which will result + in a live-lock. + Ticket spinlocks provide a FIFO order of lock acquisition + which resolves such unfairness issue at the cost of slightly + increased memory footprint. + endmenu config TICKLESS_KERNEL @@ -1236,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/Kconfig.vm b/kernel/Kconfig.vm index 1845c24c16bcf77..97d6c1f424b3bd2 100644 --- a/kernel/Kconfig.vm +++ b/kernel/Kconfig.vm @@ -198,4 +198,13 @@ config DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS endif # DEMAND_PAGING endif # MMU +config KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK + bool + help + Use custom memory range check functions instead of the generic + checks in z_mem_phys_addr() and z_mem_virt_addr(). + + sys_mm_is_phys_addr_in_range() and + sys_mm_is_virt_addr_in_range() must be implemented. + endmenu # Virtual Memory Support diff --git a/kernel/atomic_c.c b/kernel/atomic_c.c index ef6e759a8b5c919..1790953cb11302a 100644 --- a/kernel/atomic_c.c +++ b/kernel/atomic_c.c @@ -37,12 +37,12 @@ static struct k_spinlock lock; * forbidden. */ #ifdef CONFIG_USERSPACE -#include +#include #define ATOMIC_SYSCALL_HANDLER_TARGET(name) \ static inline atomic_val_t z_vrfy_##name(atomic_t *target) \ { \ - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(target, sizeof(atomic_t))); \ + K_OOPS(K_SYSCALL_MEMORY_WRITE(target, sizeof(atomic_t))); \ return z_impl_##name((atomic_t *)target); \ } @@ -50,7 +50,7 @@ static struct k_spinlock lock; static inline atomic_val_t z_vrfy_##name(atomic_t *target, \ atomic_val_t value) \ { \ - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(target, sizeof(atomic_t))); \ + K_OOPS(K_SYSCALL_MEMORY_WRITE(target, sizeof(atomic_t))); \ return z_impl_##name((atomic_t *)target, value); \ } #else @@ -108,7 +108,7 @@ bool z_impl_atomic_cas(atomic_t *target, atomic_val_t old_value, bool z_vrfy_atomic_cas(atomic_t *target, atomic_val_t old_value, atomic_val_t new_value) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(target, sizeof(atomic_t))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(target, sizeof(atomic_t))); return z_impl_atomic_cas((atomic_t *)target, old_value, new_value); } @@ -138,7 +138,7 @@ static inline bool z_vrfy_atomic_ptr_cas(atomic_ptr_t *target, atomic_ptr_val_t old_value, atomic_ptr_val_t new_value) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(target, sizeof(atomic_ptr_t))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(target, sizeof(atomic_ptr_t))); return z_impl_atomic_ptr_cas(target, old_value, new_value); } @@ -276,7 +276,7 @@ atomic_ptr_val_t z_impl_atomic_ptr_set(atomic_ptr_t *target, static inline atomic_ptr_val_t z_vrfy_atomic_ptr_set(atomic_ptr_t *target, atomic_ptr_val_t value) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(target, sizeof(atomic_ptr_t))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(target, sizeof(atomic_ptr_t))); return z_impl_atomic_ptr_set(target, value); } diff --git a/kernel/busy_wait.c b/kernel/busy_wait.c index 4bb94ca04d59bea..cb7c993437d0aa5 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/condvar.c b/kernel/condvar.c index 21f538c19960673..1aa26e937d34391 100644 --- a/kernel/condvar.c +++ b/kernel/condvar.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #ifdef CONFIG_OBJ_CORE_CONDVAR @@ -21,7 +21,7 @@ static struct k_spinlock lock; int z_impl_k_condvar_init(struct k_condvar *condvar) { z_waitq_init(&condvar->wait_q); - z_object_init(condvar); + k_object_init(condvar); #ifdef CONFIG_OBJ_CORE_CONDVAR k_obj_core_init_and_link(K_OBJ_CORE(condvar), &obj_type_condvar); @@ -35,7 +35,7 @@ int z_impl_k_condvar_init(struct k_condvar *condvar) #ifdef CONFIG_USERSPACE int z_vrfy_k_condvar_init(struct k_condvar *condvar) { - Z_OOPS(Z_SYSCALL_OBJ_INIT(condvar, K_OBJ_CONDVAR)); + K_OOPS(K_SYSCALL_OBJ_INIT(condvar, K_OBJ_CONDVAR)); return z_impl_k_condvar_init(condvar); } #include @@ -67,7 +67,7 @@ int z_impl_k_condvar_signal(struct k_condvar *condvar) #ifdef CONFIG_USERSPACE int z_vrfy_k_condvar_signal(struct k_condvar *condvar) { - Z_OOPS(Z_SYSCALL_OBJ(condvar, K_OBJ_CONDVAR)); + K_OOPS(K_SYSCALL_OBJ(condvar, K_OBJ_CONDVAR)); return z_impl_k_condvar_signal(condvar); } #include @@ -100,7 +100,7 @@ int z_impl_k_condvar_broadcast(struct k_condvar *condvar) #ifdef CONFIG_USERSPACE int z_vrfy_k_condvar_broadcast(struct k_condvar *condvar) { - Z_OOPS(Z_SYSCALL_OBJ(condvar, K_OBJ_CONDVAR)); + K_OOPS(K_SYSCALL_OBJ(condvar, K_OBJ_CONDVAR)); return z_impl_k_condvar_broadcast(condvar); } #include @@ -128,8 +128,8 @@ int z_impl_k_condvar_wait(struct k_condvar *condvar, struct k_mutex *mutex, int z_vrfy_k_condvar_wait(struct k_condvar *condvar, struct k_mutex *mutex, k_timeout_t timeout) { - Z_OOPS(Z_SYSCALL_OBJ(condvar, K_OBJ_CONDVAR)); - Z_OOPS(Z_SYSCALL_OBJ(mutex, K_OBJ_MUTEX)); + K_OOPS(K_SYSCALL_OBJ(condvar, K_OBJ_CONDVAR)); + K_OOPS(K_SYSCALL_OBJ(mutex, K_OBJ_MUTEX)); return z_impl_k_condvar_wait(condvar, mutex, timeout); } #include diff --git a/kernel/device.c b/kernel/device.c index d5ceb615461ae26..6124ada5140f81c 100644 --- a/kernel/device.c +++ b/kernel/device.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include /** @@ -21,7 +21,7 @@ void z_device_state_init(void) { STRUCT_SECTION_FOREACH(device, dev) { - z_object_init(dev); + k_object_init(dev); } } @@ -59,7 +59,7 @@ static inline const struct device *z_vrfy_device_get_binding(const char *name) { char name_copy[Z_DEVICE_MAX_NAME_LEN]; - if (z_user_string_copy(name_copy, (char *)name, sizeof(name_copy)) + if (k_usermode_string_copy(name_copy, (char *)name, sizeof(name_copy)) != 0) { return NULL; } @@ -70,7 +70,7 @@ static inline const struct device *z_vrfy_device_get_binding(const char *name) static inline bool z_vrfy_device_is_ready(const struct device *dev) { - Z_OOPS(Z_SYSCALL_OBJ_INIT(dev, K_OBJ_ANY)); + K_OOPS(K_SYSCALL_OBJ_INIT(dev, K_OBJ_ANY)); return z_impl_device_is_ready(dev); } diff --git a/kernel/dynamic.c b/kernel/dynamic.c index 5215e83fa77ba7d..b9d34cbb52c325d 100644 --- a/kernel/dynamic.c +++ b/kernel/dynamic.c @@ -7,11 +7,12 @@ #include "kernel_internal.h" #include +#include #include #include #include #include -#include +#include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -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; } @@ -152,7 +147,7 @@ int z_impl_k_thread_stack_free(k_thread_stack_t *stack) if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) { #ifdef CONFIG_USERSPACE - if (z_object_find(stack)) { + if (k_object_find(stack)) { k_object_free(stack); } else { k_free(stack); @@ -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/errno.c b/kernel/errno.c index 37866819bf52f9d..645597f02c7efce 100644 --- a/kernel/errno.c +++ b/kernel/errno.c @@ -13,7 +13,7 @@ */ #include -#include +#include /* * Define _k_neg_eagain for use in assembly files as errno.h is diff --git a/kernel/events.c b/kernel/events.c index 654978650bcc468..8cb90dc61601d48 100644 --- a/kernel/events.c +++ b/kernel/events.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include /* private kernel APIs */ @@ -58,7 +58,7 @@ void z_impl_k_event_init(struct k_event *event) z_waitq_init(&event->wait_q); - z_object_init(event); + k_object_init(event); #ifdef CONFIG_OBJ_CORE_EVENT k_obj_core_init_and_link(K_OBJ_CORE(event), &obj_type_event); @@ -68,7 +68,7 @@ void z_impl_k_event_init(struct k_event *event) #ifdef CONFIG_USERSPACE void z_vrfy_k_event_init(struct k_event *event) { - Z_OOPS(Z_SYSCALL_OBJ_NEVER_INIT(event, K_OBJ_EVENT)); + K_OOPS(K_SYSCALL_OBJ_NEVER_INIT(event, K_OBJ_EVENT)); z_impl_k_event_init(event); } #include @@ -187,7 +187,7 @@ uint32_t z_impl_k_event_post(struct k_event *event, uint32_t events) #ifdef CONFIG_USERSPACE uint32_t z_vrfy_k_event_post(struct k_event *event, uint32_t events) { - Z_OOPS(Z_SYSCALL_OBJ(event, K_OBJ_EVENT)); + K_OOPS(K_SYSCALL_OBJ(event, K_OBJ_EVENT)); return z_impl_k_event_post(event, events); } #include @@ -201,7 +201,7 @@ uint32_t z_impl_k_event_set(struct k_event *event, uint32_t events) #ifdef CONFIG_USERSPACE uint32_t z_vrfy_k_event_set(struct k_event *event, uint32_t events) { - Z_OOPS(Z_SYSCALL_OBJ(event, K_OBJ_EVENT)); + K_OOPS(K_SYSCALL_OBJ(event, K_OBJ_EVENT)); return z_impl_k_event_set(event, events); } #include @@ -217,7 +217,7 @@ uint32_t z_impl_k_event_set_masked(struct k_event *event, uint32_t events, uint32_t z_vrfy_k_event_set_masked(struct k_event *event, uint32_t events, uint32_t events_mask) { - Z_OOPS(Z_SYSCALL_OBJ(event, K_OBJ_EVENT)); + K_OOPS(K_SYSCALL_OBJ(event, K_OBJ_EVENT)); return z_impl_k_event_set_masked(event, events, events_mask); } #include @@ -231,7 +231,7 @@ uint32_t z_impl_k_event_clear(struct k_event *event, uint32_t events) #ifdef CONFIG_USERSPACE uint32_t z_vrfy_k_event_clear(struct k_event *event, uint32_t events) { - Z_OOPS(Z_SYSCALL_OBJ(event, K_OBJ_EVENT)); + K_OOPS(K_SYSCALL_OBJ(event, K_OBJ_EVENT)); return z_impl_k_event_clear(event, events); } #include @@ -317,7 +317,7 @@ uint32_t z_impl_k_event_wait(struct k_event *event, uint32_t events, uint32_t z_vrfy_k_event_wait(struct k_event *event, uint32_t events, bool reset, k_timeout_t timeout) { - Z_OOPS(Z_SYSCALL_OBJ(event, K_OBJ_EVENT)); + K_OOPS(K_SYSCALL_OBJ(event, K_OBJ_EVENT)); return z_impl_k_event_wait(event, events, reset, timeout); } #include @@ -339,7 +339,7 @@ uint32_t z_impl_k_event_wait_all(struct k_event *event, uint32_t events, uint32_t z_vrfy_k_event_wait_all(struct k_event *event, uint32_t events, bool reset, k_timeout_t timeout) { - Z_OOPS(Z_SYSCALL_OBJ(event, K_OBJ_EVENT)); + K_OOPS(K_SYSCALL_OBJ(event, K_OBJ_EVENT)); return z_impl_k_event_wait_all(event, events, reset, timeout); } #include diff --git a/kernel/fatal.c b/kernel/fatal.c index 7a3733cbfefaf13..dae2eb60950dbf0 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/futex.c b/kernel/futex.c index 40362045eabfa7b..1354a6314e496d7 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -8,15 +8,15 @@ #include #include #include -#include +#include #include #include static struct z_futex_data *k_futex_find_data(struct k_futex *futex) { - struct z_object *obj; + struct k_object *obj; - obj = z_object_find(futex); + obj = k_object_find(futex); if (obj == NULL || obj->type != K_OBJ_FUTEX) { return NULL; } @@ -54,7 +54,7 @@ int z_impl_k_futex_wake(struct k_futex *futex, bool wake_all) static inline int z_vrfy_k_futex_wake(struct k_futex *futex, bool wake_all) { - if (Z_SYSCALL_MEMORY_WRITE(futex, sizeof(struct k_futex)) != 0) { + if (K_SYSCALL_MEMORY_WRITE(futex, sizeof(struct k_futex)) != 0) { return -EACCES; } @@ -92,7 +92,7 @@ int z_impl_k_futex_wait(struct k_futex *futex, int expected, static inline int z_vrfy_k_futex_wait(struct k_futex *futex, int expected, k_timeout_t timeout) { - if (Z_SYSCALL_MEMORY_WRITE(futex, sizeof(struct k_futex)) != 0) { + if (K_SYSCALL_MEMORY_WRITE(futex, sizeof(struct k_futex)) != 0) { return -EACCES; } diff --git a/kernel/include/kernel_arch_interface.h b/kernel/include/kernel_arch_interface.h index 0173a4ae398c772..5d11521ab8bd16a 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 711313b5ce79696..16efb3b54e8ae0f 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/kswap.h b/kernel/include/kswap.h index fa1e538b8e81d14..01a72744b00801b 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 f51c0adeda0d688..88795560e4cd018 100644 --- a/kernel/include/mmu.h +++ b/kernel/include/mmu.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include /* @@ -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/init.c b/kernel/init.c index c2109499a078fbc..e4637d3aff19aef 100644 --- a/kernel/init.c +++ b/kernel/init.c @@ -165,12 +165,7 @@ void __weak z_early_memcpy(void *dst, const void *src, size_t n) __boot_func void z_bss_zero(void) { - if (IS_ENABLED(CONFIG_ARCH_POSIX)) { - /* native_posix gets its memory cleared on entry by - * the host OS, and in any case the host clang/lld - * doesn't emit the __bss_end symbol this code expects - * to see - */ + if (IS_ENABLED(CONFIG_SKIP_BSS_CLEAR)) { return; } diff --git a/kernel/mem_slab.c b/kernel/mem_slab.c index 7f7853213b91b81..3be1066d2b740e1 100644 --- a/kernel/mem_slab.c +++ b/kernel/mem_slab.c @@ -151,7 +151,7 @@ static int init_mem_slab_obj_core_list(void) if (rc < 0) { goto out; } - z_object_init(slab); + k_object_init(slab); #ifdef CONFIG_OBJ_CORE_MEM_SLAB k_obj_core_init_and_link(K_OBJ_CORE(slab), &obj_type_mem_slab); @@ -198,7 +198,7 @@ int k_mem_slab_init(struct k_mem_slab *slab, void *buffer, #endif z_waitq_init(&slab->wait_q); - z_object_init(slab); + k_object_init(slab); out: SYS_PORT_TRACING_OBJ_INIT(k_mem_slab, slab, rc); diff --git a/kernel/mempool.c b/kernel/mempool.c index 3cbfa201222f659..b3943b527280c8d 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 8f6a811bc4ffa8d..cef9b5c18d29c35 100644 --- a/kernel/mmu.c +++ b/kernel/mmu.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -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), \ @@ -469,7 +475,9 @@ static int virt_to_page_frame(void *virt, uintptr_t *phys) if (z_page_frame_is_mapped(pf)) { if (virt == pf->addr) { ret = 0; - *phys = z_page_frame_to_phys(pf); + if (phys != NULL) { + *phys = z_page_frame_to_phys(pf); + } break; } } @@ -775,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/msg_q.c b/kernel/msg_q.c index 5b0f7cb83bd9d87..e11e9a2527ef852 100644 --- a/kernel/msg_q.c +++ b/kernel/msg_q.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include @@ -59,7 +59,7 @@ void k_msgq_init(struct k_msgq *msgq, char *buffer, size_t msg_size, SYS_PORT_TRACING_OBJ_INIT(k_msgq, msgq); - z_object_init(msgq); + k_object_init(msgq); } int z_impl_k_msgq_alloc_init(struct k_msgq *msgq, size_t msg_size, @@ -93,7 +93,7 @@ int z_impl_k_msgq_alloc_init(struct k_msgq *msgq, size_t msg_size, int z_vrfy_k_msgq_alloc_init(struct k_msgq *msgq, size_t msg_size, uint32_t max_msgs) { - Z_OOPS(Z_SYSCALL_OBJ_NEVER_INIT(msgq, K_OBJ_MSGQ)); + K_OOPS(K_SYSCALL_OBJ_NEVER_INIT(msgq, K_OBJ_MSGQ)); return z_impl_k_msgq_alloc_init(msgq, msg_size, max_msgs); } @@ -187,8 +187,8 @@ int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout static inline int z_vrfy_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout) { - Z_OOPS(Z_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(data, msgq->msg_size)); + K_OOPS(K_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); + K_OOPS(K_SYSCALL_MEMORY_READ(data, msgq->msg_size)); return z_impl_k_msgq_put(msgq, data, timeout); } @@ -206,8 +206,8 @@ void z_impl_k_msgq_get_attrs(struct k_msgq *msgq, struct k_msgq_attrs *attrs) static inline void z_vrfy_k_msgq_get_attrs(struct k_msgq *msgq, struct k_msgq_attrs *attrs) { - Z_OOPS(Z_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(attrs, sizeof(struct k_msgq_attrs))); + K_OOPS(K_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(attrs, sizeof(struct k_msgq_attrs))); z_impl_k_msgq_get_attrs(msgq, attrs); } #include @@ -285,8 +285,8 @@ int z_impl_k_msgq_get(struct k_msgq *msgq, void *data, k_timeout_t timeout) static inline int z_vrfy_k_msgq_get(struct k_msgq *msgq, void *data, k_timeout_t timeout) { - Z_OOPS(Z_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(data, msgq->msg_size)); + K_OOPS(K_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(data, msgq->msg_size)); return z_impl_k_msgq_get(msgq, data, timeout); } @@ -319,8 +319,8 @@ int z_impl_k_msgq_peek(struct k_msgq *msgq, void *data) #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_msgq_peek(struct k_msgq *msgq, void *data) { - Z_OOPS(Z_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(data, msgq->msg_size)); + K_OOPS(K_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(data, msgq->msg_size)); return z_impl_k_msgq_peek(msgq, data); } @@ -365,8 +365,8 @@ int z_impl_k_msgq_peek_at(struct k_msgq *msgq, void *data, uint32_t idx) #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_msgq_peek_at(struct k_msgq *msgq, void *data, uint32_t idx) { - Z_OOPS(Z_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(data, msgq->msg_size)); + K_OOPS(K_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(data, msgq->msg_size)); return z_impl_k_msgq_peek_at(msgq, data, idx); } @@ -397,21 +397,21 @@ void z_impl_k_msgq_purge(struct k_msgq *msgq) #ifdef CONFIG_USERSPACE static inline void z_vrfy_k_msgq_purge(struct k_msgq *msgq) { - Z_OOPS(Z_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); + K_OOPS(K_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); z_impl_k_msgq_purge(msgq); } #include static inline uint32_t z_vrfy_k_msgq_num_free_get(struct k_msgq *msgq) { - Z_OOPS(Z_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); + K_OOPS(K_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); return z_impl_k_msgq_num_free_get(msgq); } #include static inline uint32_t z_vrfy_k_msgq_num_used_get(struct k_msgq *msgq) { - Z_OOPS(Z_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); + K_OOPS(K_SYSCALL_OBJ(msgq, K_OBJ_MSGQ)); return z_impl_k_msgq_num_used_get(msgq); } #include diff --git a/kernel/mutex.c b/kernel/mutex.c index 94084bdcce9d080..622422aef7ba95a 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c @@ -33,10 +33,11 @@ #include #include #include -#include +#include #include #include #include +#include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); /* We use a global spinlock here because some of the synchronization @@ -57,7 +58,7 @@ int z_impl_k_mutex_init(struct k_mutex *mutex) z_waitq_init(&mutex->wait_q); - z_object_init(mutex); + k_object_init(mutex); #ifdef CONFIG_OBJ_CORE_MUTEX k_obj_core_init_and_link(K_OBJ_CORE(mutex), &obj_type_mutex); @@ -71,7 +72,7 @@ int z_impl_k_mutex_init(struct k_mutex *mutex) #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_mutex_init(struct k_mutex *mutex) { - Z_OOPS(Z_SYSCALL_OBJ_INIT(mutex, K_OBJ_MUTEX)); + K_OOPS(K_SYSCALL_OBJ_INIT(mutex, K_OBJ_MUTEX)); return z_impl_k_mutex_init(mutex); } #include @@ -195,12 +196,13 @@ int z_impl_k_mutex_lock(struct k_mutex *mutex, k_timeout_t timeout) return -EAGAIN; } +EXPORT_SYSCALL(k_mutex_lock); #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_mutex_lock(struct k_mutex *mutex, k_timeout_t timeout) { - Z_OOPS(Z_SYSCALL_OBJ(mutex, K_OBJ_MUTEX)); + K_OOPS(K_SYSCALL_OBJ(mutex, K_OBJ_MUTEX)); return z_impl_k_mutex_lock(mutex, timeout); } #include @@ -280,11 +282,12 @@ int z_impl_k_mutex_unlock(struct k_mutex *mutex) return 0; } +EXPORT_SYSCALL(k_mutex_unlock); #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_mutex_unlock(struct k_mutex *mutex) { - Z_OOPS(Z_SYSCALL_OBJ(mutex, K_OBJ_MUTEX)); + K_OOPS(K_SYSCALL_OBJ(mutex, K_OBJ_MUTEX)); return z_impl_k_mutex_unlock(mutex); } #include diff --git a/kernel/paging/statistics.c b/kernel/paging/statistics.c index f1017687f3ea812..06e867cd218b133 100644 --- a/kernel/paging/statistics.c +++ b/kernel/paging/statistics.c @@ -6,9 +6,9 @@ #include #include -#include +#include #include -#include +#include extern struct k_mem_paging_stats_t paging_stats; @@ -102,7 +102,7 @@ void z_impl_k_mem_paging_stats_get(struct k_mem_paging_stats_t *stats) static inline void z_vrfy_k_mem_paging_stats_get(struct k_mem_paging_stats_t *stats) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(stats, sizeof(*stats))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(stats, sizeof(*stats))); z_impl_k_mem_paging_stats_get(stats); } #include @@ -125,8 +125,8 @@ static inline void z_vrfy_k_mem_paging_thread_stats_get(struct k_thread *thread, struct k_mem_paging_stats_t *stats) { - Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(stats, sizeof(*stats))); + K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(stats, sizeof(*stats))); z_impl_k_mem_paging_thread_stats_get(thread, stats); } #include @@ -224,7 +224,7 @@ static inline void z_vrfy_k_mem_paging_histogram_eviction_get( struct k_mem_paging_histogram_t *hist) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(hist, sizeof(*hist))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(hist, sizeof(*hist))); z_impl_k_mem_paging_histogram_eviction_get(hist); } #include @@ -233,7 +233,7 @@ static inline void z_vrfy_k_mem_paging_histogram_backing_store_page_in_get( struct k_mem_paging_histogram_t *hist) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(hist, sizeof(*hist))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(hist, sizeof(*hist))); z_impl_k_mem_paging_histogram_backing_store_page_in_get(hist); } #include @@ -242,7 +242,7 @@ static inline void z_vrfy_k_mem_paging_histogram_backing_store_page_out_get( struct k_mem_paging_histogram_t *hist) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(hist, sizeof(*hist))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(hist, sizeof(*hist))); z_impl_k_mem_paging_histogram_backing_store_page_out_get(hist); } #include diff --git a/kernel/pipes.c b/kernel/pipes.c index e4bb0227901923d..355377c2a79a31d 100644 --- a/kernel/pipes.c +++ b/kernel/pipes.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include @@ -53,7 +53,7 @@ void k_pipe_init(struct k_pipe *pipe, unsigned char *buffer, size_t size) #if defined(CONFIG_POLL) sys_dlist_init(&pipe->poll_events); #endif - z_object_init(pipe); + k_object_init(pipe); #ifdef CONFIG_OBJ_CORE_PIPE k_obj_core_init_and_link(K_OBJ_CORE(pipe), &obj_type_pipe); @@ -89,7 +89,7 @@ int z_impl_k_pipe_alloc_init(struct k_pipe *pipe, size_t size) #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_pipe_alloc_init(struct k_pipe *pipe, size_t size) { - Z_OOPS(Z_SYSCALL_OBJ_NEVER_INIT(pipe, K_OBJ_PIPE)); + K_OOPS(K_SYSCALL_OBJ_NEVER_INIT(pipe, K_OBJ_PIPE)); return z_impl_k_pipe_alloc_init(pipe, size); } @@ -122,7 +122,7 @@ void z_impl_k_pipe_flush(struct k_pipe *pipe) #ifdef CONFIG_USERSPACE void z_vrfy_k_pipe_flush(struct k_pipe *pipe) { - Z_OOPS(Z_SYSCALL_OBJ(pipe, K_OBJ_PIPE)); + K_OOPS(K_SYSCALL_OBJ(pipe, K_OBJ_PIPE)); z_impl_k_pipe_flush(pipe); } @@ -150,7 +150,7 @@ void z_impl_k_pipe_buffer_flush(struct k_pipe *pipe) #ifdef CONFIG_USERSPACE void z_vrfy_k_pipe_buffer_flush(struct k_pipe *pipe) { - Z_OOPS(Z_SYSCALL_OBJ(pipe, K_OBJ_PIPE)); + K_OOPS(K_SYSCALL_OBJ(pipe, K_OBJ_PIPE)); z_impl_k_pipe_buffer_flush(pipe); } @@ -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) { - Z_OOPS(Z_SYSCALL_OBJ(pipe, K_OBJ_PIPE)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(bytes_written, sizeof(*bytes_written))); - Z_OOPS(Z_SYSCALL_MEMORY_READ((void *)data, bytes_to_write)); + 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 @@ -725,9 +725,9 @@ int z_impl_k_pipe_get(struct k_pipe *pipe, void *data, size_t bytes_to_read, int z_vrfy_k_pipe_get(struct k_pipe *pipe, void *data, size_t bytes_to_read, size_t *bytes_read, size_t min_xfer, k_timeout_t timeout) { - Z_OOPS(Z_SYSCALL_OBJ(pipe, K_OBJ_PIPE)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(bytes_read, sizeof(*bytes_read))); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE((void *)data, bytes_to_read)); + K_OOPS(K_SYSCALL_OBJ(pipe, K_OBJ_PIPE)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(bytes_read, sizeof(*bytes_read))); + K_OOPS(K_SYSCALL_MEMORY_WRITE((void *)data, bytes_to_read)); return z_impl_k_pipe_get((struct k_pipe *)pipe, (void *)data, bytes_to_read, bytes_read, min_xfer, @@ -766,7 +766,7 @@ size_t z_impl_k_pipe_read_avail(struct k_pipe *pipe) #ifdef CONFIG_USERSPACE size_t z_vrfy_k_pipe_read_avail(struct k_pipe *pipe) { - Z_OOPS(Z_SYSCALL_OBJ(pipe, K_OBJ_PIPE)); + K_OOPS(K_SYSCALL_OBJ(pipe, K_OBJ_PIPE)); return z_impl_k_pipe_read_avail(pipe); } @@ -803,7 +803,7 @@ size_t z_impl_k_pipe_write_avail(struct k_pipe *pipe) #ifdef CONFIG_USERSPACE size_t z_vrfy_k_pipe_write_avail(struct k_pipe *pipe) { - Z_OOPS(Z_SYSCALL_OBJ(pipe, K_OBJ_PIPE)); + K_OOPS(K_SYSCALL_OBJ(pipe, K_OBJ_PIPE)); return z_impl_k_pipe_write_avail(pipe); } diff --git a/kernel/poll.c b/kernel/poll.c index 67e1e7f76a2daf8..d983af7e20ecf46 100644 --- a/kernel/poll.c +++ b/kernel/poll.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -364,11 +364,11 @@ static inline int z_vrfy_k_poll(struct k_poll_event *events, /* Validate the events buffer and make a copy of it in an * allocated kernel-side buffer. */ - if (Z_SYSCALL_VERIFY(num_events >= 0)) { + if (K_SYSCALL_VERIFY(num_events >= 0)) { ret = -EINVAL; goto out; } - if (Z_SYSCALL_VERIFY_MSG(!u32_mul_overflow(num_events, + if (K_SYSCALL_VERIFY_MSG(!u32_mul_overflow(num_events, sizeof(struct k_poll_event), &bounds), "num_events too large")) { @@ -382,7 +382,7 @@ static inline int z_vrfy_k_poll(struct k_poll_event *events, } key = k_spin_lock(&lock); - if (Z_SYSCALL_MEMORY_WRITE(events, bounds)) { + if (K_SYSCALL_MEMORY_WRITE(events, bounds)) { k_spin_unlock(&lock, key); goto oops_free; } @@ -393,7 +393,7 @@ static inline int z_vrfy_k_poll(struct k_poll_event *events, for (int i = 0; i < num_events; i++) { struct k_poll_event *e = &events_copy[i]; - if (Z_SYSCALL_VERIFY(e->mode == K_POLL_MODE_NOTIFY_ONLY)) { + if (K_SYSCALL_VERIFY(e->mode == K_POLL_MODE_NOTIFY_ONLY)) { ret = -EINVAL; goto out_free; } @@ -402,20 +402,20 @@ static inline int z_vrfy_k_poll(struct k_poll_event *events, case K_POLL_TYPE_IGNORE: break; case K_POLL_TYPE_SIGNAL: - Z_OOPS(Z_SYSCALL_OBJ(e->signal, K_OBJ_POLL_SIGNAL)); + K_OOPS(K_SYSCALL_OBJ(e->signal, K_OBJ_POLL_SIGNAL)); break; case K_POLL_TYPE_SEM_AVAILABLE: - Z_OOPS(Z_SYSCALL_OBJ(e->sem, K_OBJ_SEM)); + K_OOPS(K_SYSCALL_OBJ(e->sem, K_OBJ_SEM)); break; case K_POLL_TYPE_DATA_AVAILABLE: - Z_OOPS(Z_SYSCALL_OBJ(e->queue, K_OBJ_QUEUE)); + K_OOPS(K_SYSCALL_OBJ(e->queue, K_OBJ_QUEUE)); break; case K_POLL_TYPE_MSGQ_DATA_AVAILABLE: - Z_OOPS(Z_SYSCALL_OBJ(e->msgq, K_OBJ_MSGQ)); + K_OOPS(K_SYSCALL_OBJ(e->msgq, K_OBJ_MSGQ)); break; #ifdef CONFIG_PIPES case K_POLL_TYPE_PIPE_DATA_AVAILABLE: - Z_OOPS(Z_SYSCALL_OBJ(e->pipe, K_OBJ_PIPE)); + K_OOPS(K_SYSCALL_OBJ(e->pipe, K_OBJ_PIPE)); break; #endif default: @@ -432,7 +432,7 @@ static inline int z_vrfy_k_poll(struct k_poll_event *events, return ret; oops_free: k_free(events_copy); - Z_OOPS(1); + K_OOPS(1); } #include #endif @@ -482,7 +482,7 @@ void z_impl_k_poll_signal_init(struct k_poll_signal *sig) sys_dlist_init(&sig->poll_events); sig->signaled = 0U; /* signal->result is left uninitialized */ - z_object_init(sig); + k_object_init(sig); SYS_PORT_TRACING_FUNC(k_poll_api, signal_init, sig); } @@ -490,7 +490,7 @@ void z_impl_k_poll_signal_init(struct k_poll_signal *sig) #ifdef CONFIG_USERSPACE static inline void z_vrfy_k_poll_signal_init(struct k_poll_signal *sig) { - Z_OOPS(Z_SYSCALL_OBJ_INIT(sig, K_OBJ_POLL_SIGNAL)); + K_OOPS(K_SYSCALL_OBJ_INIT(sig, K_OBJ_POLL_SIGNAL)); z_impl_k_poll_signal_init(sig); } #include @@ -516,9 +516,9 @@ void z_impl_k_poll_signal_check(struct k_poll_signal *sig, void z_vrfy_k_poll_signal_check(struct k_poll_signal *sig, unsigned int *signaled, int *result) { - Z_OOPS(Z_SYSCALL_OBJ(sig, K_OBJ_POLL_SIGNAL)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(signaled, sizeof(unsigned int))); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(result, sizeof(int))); + K_OOPS(K_SYSCALL_OBJ(sig, K_OBJ_POLL_SIGNAL)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(signaled, sizeof(unsigned int))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(result, sizeof(int))); z_impl_k_poll_signal_check(sig, signaled, result); } #include @@ -553,14 +553,14 @@ int z_impl_k_poll_signal_raise(struct k_poll_signal *sig, int result) static inline int z_vrfy_k_poll_signal_raise(struct k_poll_signal *sig, int result) { - Z_OOPS(Z_SYSCALL_OBJ(sig, K_OBJ_POLL_SIGNAL)); + K_OOPS(K_SYSCALL_OBJ(sig, K_OBJ_POLL_SIGNAL)); return z_impl_k_poll_signal_raise(sig, result); } #include static inline void z_vrfy_k_poll_signal_reset(struct k_poll_signal *sig) { - Z_OOPS(Z_SYSCALL_OBJ(sig, K_OBJ_POLL_SIGNAL)); + K_OOPS(K_SYSCALL_OBJ(sig, K_OBJ_POLL_SIGNAL)); z_impl_k_poll_signal_reset(sig); } #include diff --git a/kernel/queue.c b/kernel/queue.c index 2625b9aba5bdbdc..04aaa149d97ed76 100644 --- a/kernel/queue.c +++ b/kernel/queue.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include @@ -66,13 +66,13 @@ void z_impl_k_queue_init(struct k_queue *queue) SYS_PORT_TRACING_OBJ_INIT(k_queue, queue); - z_object_init(queue); + k_object_init(queue); } #ifdef CONFIG_USERSPACE static inline void z_vrfy_k_queue_init(struct k_queue *queue) { - Z_OOPS(Z_SYSCALL_OBJ_NEVER_INIT(queue, K_OBJ_QUEUE)); + K_OOPS(K_SYSCALL_OBJ_NEVER_INIT(queue, K_OBJ_QUEUE)); z_impl_k_queue_init(queue); } #include @@ -114,7 +114,7 @@ void z_impl_k_queue_cancel_wait(struct k_queue *queue) #ifdef CONFIG_USERSPACE static inline void z_vrfy_k_queue_cancel_wait(struct k_queue *queue) { - Z_OOPS(Z_SYSCALL_OBJ(queue, K_OBJ_QUEUE)); + K_OOPS(K_SYSCALL_OBJ(queue, K_OBJ_QUEUE)); z_impl_k_queue_cancel_wait(queue); } #include @@ -217,7 +217,7 @@ int32_t z_impl_k_queue_alloc_append(struct k_queue *queue, void *data) static inline int32_t z_vrfy_k_queue_alloc_append(struct k_queue *queue, void *data) { - Z_OOPS(Z_SYSCALL_OBJ(queue, K_OBJ_QUEUE)); + K_OOPS(K_SYSCALL_OBJ(queue, K_OBJ_QUEUE)); return z_impl_k_queue_alloc_append(queue, data); } #include @@ -238,7 +238,7 @@ int32_t z_impl_k_queue_alloc_prepend(struct k_queue *queue, void *data) static inline int32_t z_vrfy_k_queue_alloc_prepend(struct k_queue *queue, void *data) { - Z_OOPS(Z_SYSCALL_OBJ(queue, K_OBJ_QUEUE)); + K_OOPS(K_SYSCALL_OBJ(queue, K_OBJ_QUEUE)); return z_impl_k_queue_alloc_prepend(queue, data); } #include @@ -405,28 +405,28 @@ void *z_impl_k_queue_peek_tail(struct k_queue *queue) static inline void *z_vrfy_k_queue_get(struct k_queue *queue, k_timeout_t timeout) { - Z_OOPS(Z_SYSCALL_OBJ(queue, K_OBJ_QUEUE)); + K_OOPS(K_SYSCALL_OBJ(queue, K_OBJ_QUEUE)); return z_impl_k_queue_get(queue, timeout); } #include static inline int z_vrfy_k_queue_is_empty(struct k_queue *queue) { - Z_OOPS(Z_SYSCALL_OBJ(queue, K_OBJ_QUEUE)); + K_OOPS(K_SYSCALL_OBJ(queue, K_OBJ_QUEUE)); return z_impl_k_queue_is_empty(queue); } #include static inline void *z_vrfy_k_queue_peek_head(struct k_queue *queue) { - Z_OOPS(Z_SYSCALL_OBJ(queue, K_OBJ_QUEUE)); + K_OOPS(K_SYSCALL_OBJ(queue, K_OBJ_QUEUE)); return z_impl_k_queue_peek_head(queue); } #include static inline void *z_vrfy_k_queue_peek_tail(struct k_queue *queue) { - Z_OOPS(Z_SYSCALL_OBJ(queue, K_OBJ_QUEUE)); + K_OOPS(K_SYSCALL_OBJ(queue, K_OBJ_QUEUE)); return z_impl_k_queue_peek_tail(queue); } #include diff --git a/kernel/sched.c b/kernel/sched.c index 66b10c3b04ff84f..bb009238d5db674 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -57,7 +57,8 @@ static ALWAYS_INLINE void z_priq_mq_remove(struct _priq_mq *pq, struct k_spinlock sched_spinlock; static void update_cache(int preempt_ok); -static void end_thread(struct k_thread *thread); +static void halt_thread(struct k_thread *thread, uint8_t new_state); +static void add_to_waitq_locked(struct k_thread *thread, _wait_q_t *wait_q); static inline int is_preempt(struct k_thread *thread) @@ -313,17 +314,32 @@ void z_requeue_current(struct k_thread *curr) signal_pending_ipi(); } +/* Return true if the thread is aborting, else false */ static inline bool is_aborting(struct k_thread *thread) { return (thread->base.thread_state & _THREAD_ABORTING) != 0U; } + +/* Return true if the thread is aborting or suspending, else false */ +static inline bool is_halting(struct k_thread *thread) +{ + return (thread->base.thread_state & + (_THREAD_ABORTING | _THREAD_SUSPENDING)) != 0U; +} #endif +/* Clear the halting bits (_THREAD_ABORTING and _THREAD_SUSPENDING) */ +static inline void clear_halting(struct k_thread *thread) +{ + thread->base.thread_state &= ~(_THREAD_ABORTING | _THREAD_SUSPENDING); +} + static ALWAYS_INLINE struct k_thread *next_up(void) { #ifdef CONFIG_SMP - if (is_aborting(_current)) { - end_thread(_current); + if (is_halting(_current)) { + halt_thread(_current, is_aborting(_current) ? + _THREAD_DEAD : _THREAD_SUSPENDED); } #endif @@ -665,31 +681,109 @@ void z_sched_start(struct k_thread *thread) z_reschedule(&sched_spinlock, key); } +/** + * @brief Halt a thread + * + * If the target thread is running on another CPU, flag it as needing to + * abort and send an IPI (if supported) to force a schedule point and wait + * until the target thread is switched out (ISRs will spin to wait and threads + * will block to wait). If the target thread is not running on another CPU, + * then it is safe to act immediately. + * + * Upon entry to this routine, the scheduler lock is already held. It is + * released before this routine returns. + * + * @param thread Thread to suspend or abort + * @param key Current key for sched_spinlock + * @param terminate True if aborting thread, false if suspending thread + */ +static void z_thread_halt(struct k_thread *thread, k_spinlock_key_t key, + bool terminate) +{ +#ifdef CONFIG_SMP + if (is_halting(_current) && arch_is_in_isr()) { + /* Another CPU (in an ISR) or thread is waiting for the + * current thread to halt. Halt it now to help avoid a + * potential deadlock. + */ + halt_thread(_current, + is_aborting(_current) ? _THREAD_DEAD + : _THREAD_SUSPENDED); + } + + bool active = thread_active_elsewhere(thread); + + if (active) { + /* It's running somewhere else, flag and poke */ + thread->base.thread_state |= (terminate ? _THREAD_ABORTING + : _THREAD_SUSPENDING); + + /* We might spin to wait, so a true synchronous IPI is needed + * here, not deferred! + */ +#ifdef CONFIG_SCHED_IPI_SUPPORTED + arch_sched_ipi(); +#endif + } + + if (is_halting(thread) && (thread != _current)) { + if (arch_is_in_isr()) { + /* ISRs can only spin waiting another CPU */ + k_spin_unlock(&sched_spinlock, key); + while (is_halting(thread)) { + } + + /* Now we know it's halting, but not necessarily + * halted (suspended or aborted). Wait for the switch + * to happen! + */ + key = k_spin_lock(&sched_spinlock); + z_sched_switch_spin(thread); + k_spin_unlock(&sched_spinlock, key); + } else if (active) { + /* Threads can wait on a queue */ + add_to_waitq_locked(_current, terminate ? + &thread->join_queue : + &thread->halt_queue); + z_swap(&sched_spinlock, key); + } + return; /* lock has been released */ + } +#endif + halt_thread(thread, terminate ? _THREAD_DEAD : _THREAD_SUSPENDED); + if ((thread == _current) && !arch_is_in_isr()) { + z_swap(&sched_spinlock, key); + __ASSERT(!terminate, "aborted _current back from dead"); + } else { + k_spin_unlock(&sched_spinlock, key); + } +} + void z_impl_k_thread_suspend(struct k_thread *thread) { SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, suspend, thread); (void)z_abort_thread_timeout(thread); - K_SPINLOCK(&sched_spinlock) { - if (z_is_thread_queued(thread)) { - dequeue_thread(thread); - } - z_mark_thread_as_suspended(thread); - update_cache(thread == _current); - } + k_spinlock_key_t key = k_spin_lock(&sched_spinlock); - if (thread == _current) { - z_reschedule_unlocked(); + if ((thread->base.thread_state & _THREAD_SUSPENDED) != 0U) { + + /* The target thread is already suspended. Nothing to do. */ + + k_spin_unlock(&sched_spinlock, key); + return; } + z_thread_halt(thread, key, false); + SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, suspend, thread); } #ifdef CONFIG_USERSPACE static inline void z_vrfy_k_thread_suspend(struct k_thread *thread) { - Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD)); + K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD)); z_impl_k_thread_suspend(thread); } #include @@ -718,7 +812,7 @@ void z_impl_k_thread_resume(struct k_thread *thread) #ifdef CONFIG_USERSPACE static inline void z_vrfy_k_thread_resume(struct k_thread *thread) { - Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD)); + K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD)); z_impl_k_thread_resume(thread); } #include @@ -798,8 +892,8 @@ ALWAYS_INLINE void z_unpend_thread_no_timeout(struct k_thread *thread) void z_sched_wake_thread(struct k_thread *thread, bool is_timeout) { K_SPINLOCK(&sched_spinlock) { - bool killed = ((thread->base.thread_state & _THREAD_DEAD) || - (thread->base.thread_state & _THREAD_ABORTING)); + bool killed = (thread->base.thread_state & + (_THREAD_DEAD | _THREAD_ABORTING)); #ifdef CONFIG_EVENTS bool do_nothing = thread->no_wake_on_timeout && is_timeout; @@ -1000,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); @@ -1335,7 +1429,7 @@ int z_impl_k_thread_priority_get(k_tid_t thread) #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_thread_priority_get(k_tid_t thread) { - Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD)); + K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD)); return z_impl_k_thread_priority_get(thread); } #include @@ -1358,10 +1452,10 @@ void z_impl_k_thread_priority_set(k_tid_t thread, int prio) #ifdef CONFIG_USERSPACE static inline void z_vrfy_k_thread_priority_set(k_tid_t thread, int prio) { - Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD)); - Z_OOPS(Z_SYSCALL_VERIFY_MSG(_is_valid_prio(prio, NULL), + K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD)); + K_OOPS(K_SYSCALL_VERIFY_MSG(_is_valid_prio(prio, NULL), "invalid thread priority %d", prio)); - Z_OOPS(Z_SYSCALL_VERIFY_MSG((int8_t)prio >= thread->base.prio, + K_OOPS(K_SYSCALL_VERIFY_MSG((int8_t)prio >= thread->base.prio, "thread priority may only be downgraded (%d < %d)", prio, thread->base.prio)); @@ -1389,8 +1483,8 @@ static inline void z_vrfy_k_thread_deadline_set(k_tid_t tid, int deadline) { struct k_thread *thread = tid; - Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD)); - Z_OOPS(Z_SYSCALL_VERIFY_MSG(deadline > 0, + K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD)); + K_OOPS(K_SYSCALL_VERIFY_MSG(deadline > 0, "invalid thread deadline %d", (int)deadline)); @@ -1433,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) @@ -1470,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; @@ -1485,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; @@ -1496,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); @@ -1520,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); - return k_ticks_to_us_floor64(ticks); + SYS_PORT_TRACING_FUNC_EXIT(k_thread, usleep, us, ret); + + return ret; } #ifdef CONFIG_USERSPACE @@ -1583,7 +1688,7 @@ void z_sched_ipi(void) #ifdef CONFIG_USERSPACE static inline void z_vrfy_k_wakeup(k_tid_t thread) { - Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD)); + K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD)); z_impl_k_wakeup(thread); } #include @@ -1712,24 +1817,42 @@ static inline void unpend_all(_wait_q_t *wait_q) extern void z_thread_cmsis_status_mask_clear(struct k_thread *thread); #endif -static void end_thread(struct k_thread *thread) +/** + * @brief Dequeues the specified thread + * + * Dequeues the specified thread and move it into the specified new state. + * + * @param thread Identify the thread to halt + * @param new_state New thread state (_THREAD_DEAD or _THREAD_SUSPENDED) + */ +static void halt_thread(struct k_thread *thread, uint8_t new_state) { /* We hold the lock, and the thread is known not to be running * anywhere. */ - if ((thread->base.thread_state & _THREAD_DEAD) == 0U) { - thread->base.thread_state |= _THREAD_DEAD; - thread->base.thread_state &= ~_THREAD_ABORTING; + if ((thread->base.thread_state & new_state) == 0U) { + thread->base.thread_state |= new_state; + clear_halting(thread); if (z_is_thread_queued(thread)) { dequeue_thread(thread); } - if (thread->base.pended_on != NULL) { - unpend_thread_no_timeout(thread); + + if (new_state == _THREAD_DEAD) { + if (thread->base.pended_on != NULL) { + unpend_thread_no_timeout(thread); + } + (void)z_abort_thread_timeout(thread); + unpend_all(&thread->join_queue); } - (void)z_abort_thread_timeout(thread); - unpend_all(&thread->join_queue); +#ifdef CONFIG_SMP + unpend_all(&thread->halt_queue); +#endif update_cache(1); + if (new_state == _THREAD_SUSPENDED) { + return; + } + #if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) arch_float_disable(thread); #endif @@ -1751,9 +1874,9 @@ static void end_thread(struct k_thread *thread) #ifdef CONFIG_USERSPACE z_mem_domain_exit_thread(thread); - z_thread_perms_all_clear(thread); - z_object_uninit(thread->stack_obj); - z_object_uninit(thread); + k_thread_perms_all_clear(thread); + k_object_uninit(thread->stack_obj); + k_object_uninit(thread); #endif } } @@ -1774,53 +1897,7 @@ void z_thread_abort(struct k_thread *thread) return; } -#ifdef CONFIG_SMP - if (is_aborting(thread) && thread == _current && arch_is_in_isr()) { - /* Another CPU is spinning for us, don't deadlock */ - end_thread(thread); - } - - bool active = thread_active_elsewhere(thread); - - if (active) { - /* It's running somewhere else, flag and poke */ - thread->base.thread_state |= _THREAD_ABORTING; - - /* We're going to spin, so need a true synchronous IPI - * here, not deferred! - */ -#ifdef CONFIG_SCHED_IPI_SUPPORTED - arch_sched_ipi(); -#endif - } - - if (is_aborting(thread) && thread != _current) { - if (arch_is_in_isr()) { - /* ISRs can only spin waiting another CPU */ - k_spin_unlock(&sched_spinlock, key); - while (is_aborting(thread)) { - } - - /* Now we know it's dying, but not necessarily - * dead. Wait for the switch to happen! - */ - key = k_spin_lock(&sched_spinlock); - z_sched_switch_spin(thread); - k_spin_unlock(&sched_spinlock, key); - } else if (active) { - /* Threads can join */ - add_to_waitq_locked(_current, &thread->join_queue); - z_swap(&sched_spinlock, key); - } - return; /* lock has been released */ - } -#endif - end_thread(thread); - if (thread == _current && !arch_is_in_isr()) { - z_swap(&sched_spinlock, key); - __ASSERT(false, "aborted _current back from dead"); - } - k_spin_unlock(&sched_spinlock, key); + z_thread_halt(thread, key, true); } #if !defined(CONFIG_ARCH_HAS_THREAD_ABORT) @@ -1878,8 +1955,8 @@ int z_impl_k_thread_join(struct k_thread *thread, k_timeout_t timeout) */ static bool thread_obj_validate(struct k_thread *thread) { - struct z_object *ko = z_object_find(thread); - int ret = z_object_validate(ko, K_OBJ_THREAD, _OBJ_INIT_TRUE); + struct k_object *ko = k_object_find(thread); + int ret = k_object_validate(ko, K_OBJ_THREAD, _OBJ_INIT_TRUE); switch (ret) { case 0: @@ -1888,9 +1965,9 @@ static bool thread_obj_validate(struct k_thread *thread) return true; default: #ifdef CONFIG_LOG - z_dump_object_error(ret, thread, ko, K_OBJ_THREAD); + k_object_dump_error(ret, thread, ko, K_OBJ_THREAD); #endif - Z_OOPS(Z_SYSCALL_VERIFY_MSG(ret, "access denied")); + K_OOPS(K_SYSCALL_VERIFY_MSG(ret, "access denied")); } CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ } @@ -1912,7 +1989,7 @@ static inline void z_vrfy_k_thread_abort(k_tid_t thread) return; } - Z_OOPS(Z_SYSCALL_VERIFY_MSG(!(thread->base.user_options & K_ESSENTIAL), + K_OOPS(K_SYSCALL_VERIFY_MSG(!(thread->base.user_options & K_ESSENTIAL), "aborting essential thread %p", thread)); z_impl_k_thread_abort((struct k_thread *)thread); diff --git a/kernel/sem.c b/kernel/sem.c index 3b8bcb12808dd86..2f8de51ed83f957 100644 --- a/kernel/sem.c +++ b/kernel/sem.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include @@ -63,7 +63,7 @@ int z_impl_k_sem_init(struct k_sem *sem, unsigned int initial_count, #if defined(CONFIG_POLL) sys_dlist_init(&sem->poll_events); #endif - z_object_init(sem); + k_object_init(sem); #ifdef CONFIG_OBJ_CORE_SEM k_obj_core_init_and_link(K_OBJ_CORE(sem), &obj_type_sem); @@ -76,7 +76,7 @@ int z_impl_k_sem_init(struct k_sem *sem, unsigned int initial_count, int z_vrfy_k_sem_init(struct k_sem *sem, unsigned int initial_count, unsigned int limit) { - Z_OOPS(Z_SYSCALL_OBJ_INIT(sem, K_OBJ_SEM)); + K_OOPS(K_SYSCALL_OBJ_INIT(sem, K_OBJ_SEM)); return z_impl_k_sem_init(sem, initial_count, limit); } #include @@ -123,7 +123,7 @@ void z_impl_k_sem_give(struct k_sem *sem) #ifdef CONFIG_USERSPACE static inline void z_vrfy_k_sem_give(struct k_sem *sem) { - Z_OOPS(Z_SYSCALL_OBJ(sem, K_OBJ_SEM)); + K_OOPS(K_SYSCALL_OBJ(sem, K_OBJ_SEM)); z_impl_k_sem_give(sem); } #include @@ -188,21 +188,21 @@ void z_impl_k_sem_reset(struct k_sem *sem) #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_sem_take(struct k_sem *sem, k_timeout_t timeout) { - Z_OOPS(Z_SYSCALL_OBJ(sem, K_OBJ_SEM)); + K_OOPS(K_SYSCALL_OBJ(sem, K_OBJ_SEM)); return z_impl_k_sem_take((struct k_sem *)sem, timeout); } #include static inline void z_vrfy_k_sem_reset(struct k_sem *sem) { - Z_OOPS(Z_SYSCALL_OBJ(sem, K_OBJ_SEM)); + K_OOPS(K_SYSCALL_OBJ(sem, K_OBJ_SEM)); z_impl_k_sem_reset(sem); } #include static inline unsigned int z_vrfy_k_sem_count_get(struct k_sem *sem) { - Z_OOPS(Z_SYSCALL_OBJ(sem, K_OBJ_SEM)); + K_OOPS(K_SYSCALL_OBJ(sem, K_OBJ_SEM)); return z_impl_k_sem_count_get(sem); } #include diff --git a/kernel/smp.c b/kernel/smp.c index dc30bd5f9edf171..45ec956dff92ac1 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,135 @@ 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); + #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; + } + + /* Initialize the dummy thread struct so that + * the scheduler can schedule actual threads to run. + */ + z_dummy_thread_init(&dummy_thread); + + /* 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/stack.c b/kernel/stack.c index 0362ece76b54ed8..6ada39c9b1eba54 100644 --- a/kernel/stack.c +++ b/kernel/stack.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #ifdef CONFIG_OBJ_CORE_STACK @@ -32,7 +32,7 @@ void k_stack_init(struct k_stack *stack, stack_data_t *buffer, stack->top = stack->base + num_entries; SYS_PORT_TRACING_OBJ_INIT(k_stack, stack); - z_object_init(stack); + k_object_init(stack); #ifdef CONFIG_OBJ_CORE_STACK k_obj_core_init_and_link(K_OBJ_CORE(stack), &obj_type_stack); @@ -64,8 +64,8 @@ int32_t z_impl_k_stack_alloc_init(struct k_stack *stack, uint32_t num_entries) static inline int32_t z_vrfy_k_stack_alloc_init(struct k_stack *stack, uint32_t num_entries) { - Z_OOPS(Z_SYSCALL_OBJ_NEVER_INIT(stack, K_OBJ_STACK)); - Z_OOPS(Z_SYSCALL_VERIFY(num_entries > 0)); + K_OOPS(K_SYSCALL_OBJ_NEVER_INIT(stack, K_OBJ_STACK)); + K_OOPS(K_SYSCALL_VERIFY(num_entries > 0)); return z_impl_k_stack_alloc_init(stack, num_entries); } #include @@ -132,7 +132,7 @@ int z_impl_k_stack_push(struct k_stack *stack, stack_data_t data) #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_stack_push(struct k_stack *stack, stack_data_t data) { - Z_OOPS(Z_SYSCALL_OBJ(stack, K_OBJ_STACK)); + K_OOPS(K_SYSCALL_OBJ(stack, K_OBJ_STACK)); return z_impl_k_stack_push(stack, data); } @@ -187,8 +187,8 @@ int z_impl_k_stack_pop(struct k_stack *stack, stack_data_t *data, static inline int z_vrfy_k_stack_pop(struct k_stack *stack, stack_data_t *data, k_timeout_t timeout) { - Z_OOPS(Z_SYSCALL_OBJ(stack, K_OBJ_STACK)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(data, sizeof(stack_data_t))); + K_OOPS(K_SYSCALL_OBJ(stack, K_OBJ_STACK)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(data, sizeof(stack_data_t))); return z_impl_k_stack_pop(stack, data, timeout); } #include diff --git a/kernel/thread.c b/kernel/thread.c index 2703116aca56048..fc31f4b36d8ba42 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -29,6 +29,7 @@ #include #include #include +#include #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -141,6 +142,7 @@ bool k_is_in_isr(void) { return arch_is_in_isr(); } +EXPORT_SYMBOL(k_is_in_isr); /* * This function tags the current thread as essential to system operation. @@ -257,7 +259,7 @@ static inline int z_vrfy_k_thread_name_set(struct k_thread *thread, const char * char name[CONFIG_THREAD_MAX_NAME_LEN]; if (thread != NULL) { - if (Z_SYSCALL_OBJ(thread, K_OBJ_THREAD) != 0) { + if (K_SYSCALL_OBJ(thread, K_OBJ_THREAD) != 0) { return -EINVAL; } } @@ -266,7 +268,7 @@ static inline int z_vrfy_k_thread_name_set(struct k_thread *thread, const char * * the current z_vrfy / z_impl split does not provide a * means of doing so. */ - if (z_user_string_copy(name, (char *)str, sizeof(name)) != 0) { + if (k_usermode_string_copy(name, (char *)str, sizeof(name)) != 0) { return -EFAULT; } @@ -278,7 +280,7 @@ static inline int z_vrfy_k_thread_name_set(struct k_thread *thread, const char * #include #endif /* CONFIG_USERSPACE */ -const char *k_thread_name_get(struct k_thread *thread) +const char *k_thread_name_get(k_tid_t thread) { #ifdef CONFIG_THREAD_NAME return (const char *)thread->name; @@ -311,15 +313,33 @@ static size_t copy_bytes(char *dest, size_t dest_size, const char *src, size_t s return bytes_to_copy; } +#define Z_STATE_STR_DUMMY "dummy" +#define Z_STATE_STR_PENDING "pending" +#define Z_STATE_STR_PRESTART "prestart" +#define Z_STATE_STR_DEAD "dead" +#define Z_STATE_STR_SUSPENDED "suspended" +#define Z_STATE_STR_ABORTING "aborting" +#define Z_STATE_STR_SUSPENDING "suspending" +#define Z_STATE_STR_QUEUED "queued" + const char *k_thread_state_str(k_tid_t thread_id, char *buf, size_t buf_size) { size_t off = 0; uint8_t bit; uint8_t thread_state = thread_id->base.thread_state; - static const char *states_str[8] = {"dummy", "pending", "prestart", - "dead", "suspended", "aborting", - "", "queued"}; - static const size_t states_sz[8] = {5, 7, 8, 4, 9, 8, 0, 6}; + static const struct { + const char *str; + size_t len; + } state_string[] = { + { Z_STATE_STR_DUMMY, sizeof(Z_STATE_STR_DUMMY) - 1}, + { Z_STATE_STR_PENDING, sizeof(Z_STATE_STR_PENDING) - 1}, + { Z_STATE_STR_PRESTART, sizeof(Z_STATE_STR_PRESTART) - 1}, + { Z_STATE_STR_DEAD, sizeof(Z_STATE_STR_DEAD) - 1}, + { Z_STATE_STR_SUSPENDED, sizeof(Z_STATE_STR_SUSPENDED) - 1}, + { Z_STATE_STR_ABORTING, sizeof(Z_STATE_STR_ABORTING) - 1}, + { Z_STATE_STR_SUSPENDING, sizeof(Z_STATE_STR_SUSPENDING) - 1}, + { Z_STATE_STR_QUEUED, sizeof(Z_STATE_STR_QUEUED) - 1}, + }; if ((buf == NULL) || (buf_size == 0)) { return ""; @@ -333,14 +353,16 @@ const char *k_thread_state_str(k_tid_t thread_id, char *buf, size_t buf_size) * separate the descriptive strings with a '+'. */ - for (uint8_t index = 0; thread_state != 0; index++) { + + for (unsigned int index = 0; thread_state != 0; index++) { bit = BIT(index); if ((thread_state & bit) == 0) { continue; } off += copy_bytes(buf + off, buf_size - off, - states_str[index], states_sz[index]); + state_string[index].str, + state_string[index].len); thread_state &= ~bit; @@ -360,7 +382,7 @@ static inline int z_vrfy_k_thread_name_copy(k_tid_t thread, { #ifdef CONFIG_THREAD_NAME size_t len; - struct z_object *ko = z_object_find(thread); + struct k_object *ko = k_object_find(thread); /* Special case: we allow reading the names of initialized threads * even if we don't have permission on them @@ -369,7 +391,7 @@ static inline int z_vrfy_k_thread_name_copy(k_tid_t thread, (ko->flags & K_OBJ_FLAG_INITIALIZED) == 0) { return -EINVAL; } - if (Z_SYSCALL_MEMORY_WRITE(buf, size) != 0) { + if (K_SYSCALL_MEMORY_WRITE(buf, size) != 0) { return -EFAULT; } len = strlen(thread->name); @@ -377,7 +399,7 @@ static inline int z_vrfy_k_thread_name_copy(k_tid_t thread, return -ENOSPC; } - return z_user_to_copy((void *)buf, thread->name, len + 1); + return k_usermode_to_copy((void *)buf, thread->name, len + 1); #else ARG_UNUSED(thread); ARG_UNUSED(buf); @@ -433,7 +455,7 @@ void z_impl_k_thread_start(struct k_thread *thread) #ifdef CONFIG_USERSPACE static inline void z_vrfy_k_thread_start(struct k_thread *thread) { - Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD)); + K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD)); return z_impl_k_thread_start(thread); } #include @@ -591,8 +613,8 @@ char *z_setup_new_thread(struct k_thread *new_thread, __ASSERT((options & K_USER) == 0U || z_stack_is_user_capable(stack), "user thread %p with kernel-only stack %p", new_thread, stack); - z_object_init(new_thread); - z_object_init(stack); + k_object_init(new_thread); + k_object_init(stack); new_thread->stack_obj = stack; new_thread->syscall_frame = NULL; @@ -673,7 +695,7 @@ char *z_setup_new_thread(struct k_thread *new_thread, z_mem_domain_init_thread(new_thread); if ((options & K_INHERIT_PERMS) != 0U) { - z_thread_perms_inherit(_current, new_thread); + k_thread_perms_inherit(_current, new_thread); } #endif #ifdef CONFIG_SCHED_DEADLINE @@ -681,6 +703,10 @@ char *z_setup_new_thread(struct k_thread *new_thread, #endif new_thread->resource_pool = _current->resource_pool; +#ifdef CONFIG_SMP + z_waitq_init(&new_thread->halt_queue); +#endif + #ifdef CONFIG_SCHED_THREAD_USAGE new_thread->base.usage = (struct k_cycle_stats) {}; new_thread->base.usage.track_usage = @@ -715,7 +741,7 @@ k_tid_t z_impl_k_thread_create(struct k_thread *new_thread, #ifdef CONFIG_USERSPACE bool z_stack_is_user_capable(k_thread_stack_t *stack) { - return z_object_find(stack) != NULL; + return k_object_find(stack) != NULL; } k_tid_t z_vrfy_k_thread_create(struct k_thread *new_thread, @@ -725,16 +751,16 @@ k_tid_t z_vrfy_k_thread_create(struct k_thread *new_thread, int prio, uint32_t options, k_timeout_t delay) { size_t total_size, stack_obj_size; - struct z_object *stack_object; + struct k_object *stack_object; /* The thread and stack objects *must* be in an uninitialized state */ - Z_OOPS(Z_SYSCALL_OBJ_NEVER_INIT(new_thread, K_OBJ_THREAD)); + K_OOPS(K_SYSCALL_OBJ_NEVER_INIT(new_thread, K_OBJ_THREAD)); /* No need to check z_stack_is_user_capable(), it won't be in the * object table if it isn't */ - stack_object = z_object_find(stack); - Z_OOPS(Z_SYSCALL_VERIFY_MSG(z_obj_validation_check(stack_object, stack, + stack_object = k_object_find(stack); + K_OOPS(K_SYSCALL_VERIFY_MSG(k_object_validation_check(stack_object, stack, K_OBJ_THREAD_STACK_ELEMENT, _OBJ_INIT_FALSE) == 0, "bad stack object")); @@ -742,7 +768,7 @@ k_tid_t z_vrfy_k_thread_create(struct k_thread *new_thread, /* Verify that the stack size passed in is OK by computing the total * size and comparing it with the size value in the object metadata */ - Z_OOPS(Z_SYSCALL_VERIFY_MSG(!size_add_overflow(K_THREAD_STACK_RESERVED, + K_OOPS(K_SYSCALL_VERIFY_MSG(!size_add_overflow(K_THREAD_STACK_RESERVED, stack_size, &total_size), "stack size overflow (%zu+%zu)", stack_size, @@ -756,21 +782,21 @@ k_tid_t z_vrfy_k_thread_create(struct k_thread *new_thread, #else stack_obj_size = stack_object->data.stack_size; #endif - Z_OOPS(Z_SYSCALL_VERIFY_MSG(total_size <= stack_obj_size, + K_OOPS(K_SYSCALL_VERIFY_MSG(total_size <= stack_obj_size, "stack size %zu is too big, max is %zu", total_size, stack_obj_size)); /* User threads may only create other user threads and they can't * be marked as essential */ - Z_OOPS(Z_SYSCALL_VERIFY(options & K_USER)); - Z_OOPS(Z_SYSCALL_VERIFY(!(options & K_ESSENTIAL))); + K_OOPS(K_SYSCALL_VERIFY(options & K_USER)); + K_OOPS(K_SYSCALL_VERIFY(!(options & K_ESSENTIAL))); /* Check validity of prio argument; must be the same or worse priority * than the caller */ - Z_OOPS(Z_SYSCALL_VERIFY(_is_valid_prio(prio, NULL))); - Z_OOPS(Z_SYSCALL_VERIFY(z_is_prio_lower_or_equal(prio, + K_OOPS(K_SYSCALL_VERIFY(_is_valid_prio(prio, NULL))); + K_OOPS(K_SYSCALL_VERIFY(z_is_prio_lower_or_equal(prio, _current->base.prio))); z_setup_new_thread(new_thread, stack, stack_size, @@ -791,7 +817,7 @@ k_tid_t z_vrfy_k_thread_create(struct k_thread *new_thread, static void grant_static_access(void) { - STRUCT_SECTION_FOREACH(z_object_assignment, pos) { + STRUCT_SECTION_FOREACH(k_object_assignment, pos) { for (int i = 0; pos->objects[i] != NULL; i++) { k_object_access_grant(pos->objects[i], pos->thread); @@ -966,7 +992,7 @@ int z_impl_k_float_enable(struct k_thread *thread, unsigned int options) #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_float_disable(struct k_thread *thread) { - Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD)); + K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD)); return z_impl_k_float_disable(thread); } #include @@ -1060,7 +1086,7 @@ int z_vrfy_k_thread_stack_space_get(const struct k_thread *thread, size_t unused; int ret; - ret = Z_SYSCALL_OBJ(thread, K_OBJ_THREAD); + ret = K_SYSCALL_OBJ(thread, K_OBJ_THREAD); CHECKIF(ret != 0) { return ret; } @@ -1070,7 +1096,7 @@ int z_vrfy_k_thread_stack_space_get(const struct k_thread *thread, return ret; } - ret = z_user_to_copy(unused_ptr, &unused, sizeof(size_t)); + ret = k_usermode_to_copy(unused_ptr, &unused, sizeof(size_t)); CHECKIF(ret != 0) { return ret; } @@ -1085,7 +1111,7 @@ int z_vrfy_k_thread_stack_space_get(const struct k_thread *thread, static inline k_ticks_t z_vrfy_k_thread_timeout_remaining_ticks( const struct k_thread *t) { - Z_OOPS(Z_SYSCALL_OBJ(t, K_OBJ_THREAD)); + K_OOPS(K_SYSCALL_OBJ(t, K_OBJ_THREAD)); return z_impl_k_thread_timeout_remaining_ticks(t); } #include @@ -1093,7 +1119,7 @@ static inline k_ticks_t z_vrfy_k_thread_timeout_remaining_ticks( static inline k_ticks_t z_vrfy_k_thread_timeout_expires_ticks( const struct k_thread *t) { - Z_OOPS(Z_SYSCALL_OBJ(t, K_OBJ_THREAD)); + K_OOPS(K_SYSCALL_OBJ(t, K_OBJ_THREAD)); return z_impl_k_thread_timeout_expires_ticks(t); } #include diff --git a/kernel/timeout.c b/kernel/timeout.c index 339bc65a014dd0d..29f158980352a39 100644 --- a/kernel/timeout.c +++ b/kernel/timeout.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include @@ -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/timer.c b/kernel/timer.c index 24fe71c7f67ef49..48cc69baffee523 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include @@ -128,7 +128,7 @@ void k_timer_init(struct k_timer *timer, timer->user_data = NULL; - z_object_init(timer); + k_object_init(timer); #ifdef CONFIG_OBJ_CORE_TIMER k_obj_core_init_and_link(K_OBJ_CORE(timer), &obj_type_timer); @@ -141,7 +141,15 @@ void z_impl_k_timer_start(struct k_timer *timer, k_timeout_t duration, { SYS_PORT_TRACING_OBJ_FUNC(k_timer, start, timer, duration, period); + /* Acquire spinlock to ensure safety during concurrent calls to + * k_timer_start for scheduling or rescheduling. This is necessary + * since k_timer_start can be preempted, especially for the same + * timer instance. + */ + k_spinlock_key_t key = k_spin_lock(&lock); + if (K_TIMEOUT_EQ(duration, K_FOREVER)) { + k_spin_unlock(&lock, key); return; } @@ -168,6 +176,8 @@ void z_impl_k_timer_start(struct k_timer *timer, k_timeout_t duration, z_add_timeout(&timer->timeout, z_timer_expiration_handler, duration); + + k_spin_unlock(&lock, key); } #ifdef CONFIG_USERSPACE @@ -175,7 +185,7 @@ static inline void z_vrfy_k_timer_start(struct k_timer *timer, k_timeout_t duration, k_timeout_t period) { - Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER)); + K_OOPS(K_SYSCALL_OBJ(timer, K_OBJ_TIMER)); z_impl_k_timer_start(timer, duration, period); } #include @@ -208,7 +218,7 @@ void z_impl_k_timer_stop(struct k_timer *timer) #ifdef CONFIG_USERSPACE static inline void z_vrfy_k_timer_stop(struct k_timer *timer) { - Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER)); + K_OOPS(K_SYSCALL_OBJ(timer, K_OBJ_TIMER)); z_impl_k_timer_stop(timer); } #include @@ -228,7 +238,7 @@ uint32_t z_impl_k_timer_status_get(struct k_timer *timer) #ifdef CONFIG_USERSPACE static inline uint32_t z_vrfy_k_timer_status_get(struct k_timer *timer) { - Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER)); + K_OOPS(K_SYSCALL_OBJ(timer, K_OBJ_TIMER)); return z_impl_k_timer_status_get(timer); } #include @@ -296,7 +306,7 @@ uint32_t z_impl_k_timer_status_sync(struct k_timer *timer) #ifdef CONFIG_USERSPACE static inline uint32_t z_vrfy_k_timer_status_sync(struct k_timer *timer) { - Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER)); + K_OOPS(K_SYSCALL_OBJ(timer, K_OBJ_TIMER)); return z_impl_k_timer_status_sync(timer); } #include @@ -304,7 +314,7 @@ static inline uint32_t z_vrfy_k_timer_status_sync(struct k_timer *timer) static inline k_ticks_t z_vrfy_k_timer_remaining_ticks( const struct k_timer *timer) { - Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER)); + K_OOPS(K_SYSCALL_OBJ(timer, K_OBJ_TIMER)); return z_impl_k_timer_remaining_ticks(timer); } #include @@ -312,14 +322,14 @@ static inline k_ticks_t z_vrfy_k_timer_remaining_ticks( static inline k_ticks_t z_vrfy_k_timer_expires_ticks( const struct k_timer *timer) { - Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER)); + K_OOPS(K_SYSCALL_OBJ(timer, K_OBJ_TIMER)); return z_impl_k_timer_expires_ticks(timer); } #include static inline void *z_vrfy_k_timer_user_data_get(const struct k_timer *timer) { - Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER)); + K_OOPS(K_SYSCALL_OBJ(timer, K_OBJ_TIMER)); return z_impl_k_timer_user_data_get(timer); } #include @@ -327,7 +337,7 @@ static inline void *z_vrfy_k_timer_user_data_get(const struct k_timer *timer) static inline void z_vrfy_k_timer_user_data_set(struct k_timer *timer, void *user_data) { - Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER)); + K_OOPS(K_SYSCALL_OBJ(timer, K_OBJ_TIMER)); z_impl_k_timer_user_data_set(timer, user_data); } #include diff --git a/kernel/userspace.c b/kernel/userspace.c index ed36bec929ce857..a3e6df69120b8f5 100644 --- a/kernel/userspace.c +++ b/kernel/userspace.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -77,7 +77,7 @@ static struct k_spinlock obj_lock; /* kobj struct data */ extern uint8_t _thread_idx_map[CONFIG_MAX_THREAD_BYTES]; #endif -static void clear_perms_cb(struct z_object *ko, void *ctx_ptr); +static void clear_perms_cb(struct k_object *ko, void *ctx_ptr); const char *otype_to_str(enum k_objects otype) { @@ -119,7 +119,7 @@ struct perm_ctx { */ uint8_t *z_priv_stack_find(k_thread_stack_t *stack) { - struct z_object *obj = z_object_find(stack); + struct k_object *obj = k_object_find(stack); __ASSERT(obj != NULL, "stack object not found"); __ASSERT(obj->type == K_OBJ_THREAD_STACK_ELEMENT, @@ -166,14 +166,14 @@ uint8_t *z_priv_stack_find(k_thread_stack_t *stack) MAX(DYN_OBJ_DATA_ALIGN_K_THREAD, (sizeof(void *))) struct dyn_obj { - struct z_object kobj; + struct k_object kobj; sys_dnode_t dobj_list; /* The object itself */ void *data; }; -extern struct z_object *z_object_gperf_find(const void *obj); +extern struct k_object *z_object_gperf_find(const void *obj); extern void z_object_gperf_wordlist_foreach(_wordlist_cb_func_t func, void *context); @@ -281,7 +281,7 @@ static bool thread_idx_alloc(uintptr_t *tidx) *tidx); /* Clear permission from all objects */ - z_object_wordlist_foreach(clear_perms_cb, + k_object_wordlist_foreach(clear_perms_cb, (void *)*tidx); return true; @@ -306,12 +306,12 @@ static bool thread_idx_alloc(uintptr_t *tidx) static void thread_idx_free(uintptr_t tidx) { /* To prevent leaked permission when index is recycled */ - z_object_wordlist_foreach(clear_perms_cb, (void *)tidx); + k_object_wordlist_foreach(clear_perms_cb, (void *)tidx); sys_bitfield_set_bit((mem_addr_t)_thread_idx_map, tidx); } -static struct z_object *dynamic_object_create(enum k_objects otype, size_t align, +static struct k_object *dynamic_object_create(enum k_objects otype, size_t align, size_t size) { struct dyn_obj *dyn; @@ -373,9 +373,9 @@ static struct z_object *dynamic_object_create(enum k_objects otype, size_t align return &dyn->kobj; } -struct z_object *z_dynamic_object_aligned_create(size_t align, size_t size) +struct k_object *k_object_create_dynamic_aligned(size_t align, size_t size) { - struct z_object *obj = dynamic_object_create(K_OBJ_ANY, align, size); + struct k_object *obj = dynamic_object_create(K_OBJ_ANY, align, size); if (obj == NULL) { LOG_ERR("could not allocate kernel object, out of memory"); @@ -386,7 +386,7 @@ struct z_object *z_dynamic_object_aligned_create(size_t align, size_t size) static void *z_object_alloc(enum k_objects otype, size_t size) { - struct z_object *zo; + struct k_object *zo; uintptr_t tidx = 0; if (otype <= K_OBJ_ANY || otype >= K_OBJ_LAST) { @@ -428,7 +428,7 @@ static void *z_object_alloc(enum k_objects otype, size_t size) /* The allocating thread implicitly gets permission on kernel objects * that it allocates */ - z_thread_perms_set(zo, _current); + k_thread_perms_set(zo, _current); /* Activates reference counting logic for automatic disposal when * all permissions have been revoked @@ -475,9 +475,9 @@ void k_object_free(void *obj) } } -struct z_object *z_object_find(const void *obj) +struct k_object *k_object_find(const void *obj) { - struct z_object *ret; + struct k_object *ret; ret = z_object_gperf_find(obj); @@ -497,7 +497,7 @@ struct z_object *z_object_find(const void *obj) return ret; } -void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context) +void k_object_wordlist_foreach(_wordlist_cb_func_t func, void *context) { struct dyn_obj *obj, *next; @@ -514,9 +514,9 @@ void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context) static unsigned int thread_index_get(struct k_thread *thread) { - struct z_object *ko; + struct k_object *ko; - ko = z_object_find(thread); + ko = k_object_find(thread); if (ko == NULL) { return -1; @@ -525,7 +525,7 @@ static unsigned int thread_index_get(struct k_thread *thread) return ko->data.thread_id; } -static void unref_check(struct z_object *ko, uintptr_t index) +static void unref_check(struct k_object *ko, uintptr_t index) { k_spinlock_key_t key = k_spin_lock(&obj_lock); @@ -579,7 +579,7 @@ static void unref_check(struct z_object *ko, uintptr_t index) k_spin_unlock(&obj_lock, key); } -static void wordlist_cb(struct z_object *ko, void *ctx_ptr) +static void wordlist_cb(struct k_object *ko, void *ctx_ptr) { struct perm_ctx *ctx = (struct perm_ctx *)ctx_ptr; @@ -589,7 +589,7 @@ static void wordlist_cb(struct z_object *ko, void *ctx_ptr) } } -void z_thread_perms_inherit(struct k_thread *parent, struct k_thread *child) +void k_thread_perms_inherit(struct k_thread *parent, struct k_thread *child) { struct perm_ctx ctx = { thread_index_get(parent), @@ -598,11 +598,11 @@ void z_thread_perms_inherit(struct k_thread *parent, struct k_thread *child) }; if ((ctx.parent_id != -1) && (ctx.child_id != -1)) { - z_object_wordlist_foreach(wordlist_cb, &ctx); + k_object_wordlist_foreach(wordlist_cb, &ctx); } } -void z_thread_perms_set(struct z_object *ko, struct k_thread *thread) +void k_thread_perms_set(struct k_object *ko, struct k_thread *thread) { int index = thread_index_get(thread); @@ -611,7 +611,7 @@ void z_thread_perms_set(struct z_object *ko, struct k_thread *thread) } } -void z_thread_perms_clear(struct z_object *ko, struct k_thread *thread) +void k_thread_perms_clear(struct k_object *ko, struct k_thread *thread) { int index = thread_index_get(thread); @@ -621,23 +621,23 @@ void z_thread_perms_clear(struct z_object *ko, struct k_thread *thread) } } -static void clear_perms_cb(struct z_object *ko, void *ctx_ptr) +static void clear_perms_cb(struct k_object *ko, void *ctx_ptr) { uintptr_t id = (uintptr_t)ctx_ptr; unref_check(ko, id); } -void z_thread_perms_all_clear(struct k_thread *thread) +void k_thread_perms_all_clear(struct k_thread *thread) { uintptr_t index = thread_index_get(thread); if ((int)index != -1) { - z_object_wordlist_foreach(clear_perms_cb, (void *)index); + k_object_wordlist_foreach(clear_perms_cb, (void *)index); } } -static int thread_perms_test(struct z_object *ko) +static int thread_perms_test(struct k_object *ko) { int index; @@ -652,7 +652,7 @@ static int thread_perms_test(struct z_object *ko) return 0; } -static void dump_permission_error(struct z_object *ko) +static void dump_permission_error(struct k_object *ko) { int index = thread_index_get(_current); LOG_ERR("thread %p (%d) does not have permission on %s %p", @@ -661,7 +661,7 @@ static void dump_permission_error(struct z_object *ko) LOG_HEXDUMP_ERR(ko->perms, sizeof(ko->perms), "permission bitmap"); } -void z_dump_object_error(int retval, const void *obj, struct z_object *ko, +void k_object_dump_error(int retval, const void *obj, struct k_object *ko, enum k_objects otype) { switch (retval) { @@ -691,19 +691,19 @@ void z_dump_object_error(int retval, const void *obj, struct z_object *ko, void z_impl_k_object_access_grant(const void *object, struct k_thread *thread) { - struct z_object *ko = z_object_find(object); + struct k_object *ko = k_object_find(object); if (ko != NULL) { - z_thread_perms_set(ko, thread); + k_thread_perms_set(ko, thread); } } void k_object_access_revoke(const void *object, struct k_thread *thread) { - struct z_object *ko = z_object_find(object); + struct k_object *ko = k_object_find(object); if (ko != NULL) { - z_thread_perms_clear(ko, thread); + k_thread_perms_clear(ko, thread); } } @@ -714,14 +714,14 @@ void z_impl_k_object_release(const void *object) void k_object_access_all_grant(const void *object) { - struct z_object *ko = z_object_find(object); + struct k_object *ko = k_object_find(object); if (ko != NULL) { ko->flags |= K_OBJ_FLAG_PUBLIC; } } -int z_object_validate(struct z_object *ko, enum k_objects otype, +int k_object_validate(struct k_object *ko, enum k_objects otype, enum _obj_init_check init) { if (unlikely((ko == NULL) || @@ -754,19 +754,19 @@ int z_object_validate(struct z_object *ko, enum k_objects otype, return 0; } -void z_object_init(const void *obj) +void k_object_init(const void *obj) { - struct z_object *ko; + struct k_object *ko; /* By the time we get here, if the caller was from userspace, all the - * necessary checks have been done in z_object_validate(), which takes + * necessary checks have been done in k_object_validate(), which takes * place before the object is initialized. * * This function runs after the object has been initialized and * finalizes it */ - ko = z_object_find(obj); + ko = k_object_find(obj); if (ko == NULL) { /* Supervisor threads can ignore rules about kernel objects * and may declare them on stacks, etc. Such objects will never @@ -779,23 +779,23 @@ void z_object_init(const void *obj) ko->flags |= K_OBJ_FLAG_INITIALIZED; } -void z_object_recycle(const void *obj) +void k_object_recycle(const void *obj) { - struct z_object *ko = z_object_find(obj); + struct k_object *ko = k_object_find(obj); if (ko != NULL) { (void)memset(ko->perms, 0, sizeof(ko->perms)); - z_thread_perms_set(ko, _current); + k_thread_perms_set(ko, _current); ko->flags |= K_OBJ_FLAG_INITIALIZED; } } -void z_object_uninit(const void *obj) +void k_object_uninit(const void *obj) { - struct z_object *ko; + struct k_object *ko; - /* See comments in z_object_init() */ - ko = z_object_find(obj); + /* See comments in k_object_init() */ + ko = k_object_find(obj); if (ko == NULL) { return; } @@ -806,12 +806,12 @@ void z_object_uninit(const void *obj) /* * Copy to/from helper functions used in syscall handlers */ -void *z_user_alloc_from_copy(const void *src, size_t size) +void *k_usermode_alloc_from_copy(const void *src, size_t size) { void *dst = NULL; /* Does the caller in user mode have access to read this memory? */ - if (Z_SYSCALL_MEMORY_READ(src, size)) { + if (K_SYSCALL_MEMORY_READ(src, size)) { goto out_err; } @@ -831,8 +831,8 @@ static int user_copy(void *dst, const void *src, size_t size, bool to_user) int ret = EFAULT; /* Does the caller in user mode have access to this memory? */ - if (to_user ? Z_SYSCALL_MEMORY_WRITE(dst, size) : - Z_SYSCALL_MEMORY_READ(src, size)) { + if (to_user ? K_SYSCALL_MEMORY_WRITE(dst, size) : + K_SYSCALL_MEMORY_READ(src, size)) { goto out_err; } @@ -842,23 +842,23 @@ static int user_copy(void *dst, const void *src, size_t size, bool to_user) return ret; } -int z_user_from_copy(void *dst, const void *src, size_t size) +int k_usermode_from_copy(void *dst, const void *src, size_t size) { return user_copy(dst, src, size, false); } -int z_user_to_copy(void *dst, const void *src, size_t size) +int k_usermode_to_copy(void *dst, const void *src, size_t size) { return user_copy(dst, src, size, true); } -char *z_user_string_alloc_copy(const char *src, size_t maxlen) +char *k_usermode_string_alloc_copy(const char *src, size_t maxlen) { size_t actual_len; int err; char *ret = NULL; - actual_len = z_user_string_nlen(src, maxlen, &err); + actual_len = k_usermode_string_nlen(src, maxlen, &err); if (err != 0) { goto out; } @@ -872,7 +872,7 @@ char *z_user_string_alloc_copy(const char *src, size_t maxlen) goto out; } - ret = z_user_alloc_from_copy(src, actual_len); + ret = k_usermode_alloc_from_copy(src, actual_len); /* Someone may have modified the source string during the above * checks. Ensure what we actually copied is still terminated @@ -885,12 +885,12 @@ char *z_user_string_alloc_copy(const char *src, size_t maxlen) return ret; } -int z_user_string_copy(char *dst, const char *src, size_t maxlen) +int k_usermode_string_copy(char *dst, const char *src, size_t maxlen) { size_t actual_len; int ret, err; - actual_len = z_user_string_nlen(src, maxlen, &err); + actual_len = k_usermode_string_nlen(src, maxlen, &err); if (err != 0) { ret = EFAULT; goto out; @@ -907,9 +907,9 @@ int z_user_string_copy(char *dst, const char *src, size_t maxlen) goto out; } - ret = z_user_from_copy(dst, src, actual_len); + ret = k_usermode_from_copy(dst, src, actual_len); - /* See comment above in z_user_string_alloc_copy() */ + /* See comment above in k_usermode_string_alloc_copy() */ dst[actual_len - 1] = '\0'; out: return ret; diff --git a/kernel/userspace_handler.c b/kernel/userspace_handler.c index 5453bbcede497c2..a1cf9f9d7a3e068 100644 --- a/kernel/userspace_handler.c +++ b/kernel/userspace_handler.c @@ -5,26 +5,26 @@ */ #include -#include +#include #include #include -static struct z_object *validate_kernel_object(const void *obj, +static struct k_object *validate_kernel_object(const void *obj, enum k_objects otype, enum _obj_init_check init) { - struct z_object *ko; + struct k_object *ko; int ret; - ko = z_object_find(obj); + ko = k_object_find(obj); /* This can be any kernel object and it doesn't have to be * initialized */ - ret = z_object_validate(ko, otype, init); + ret = k_object_validate(ko, K_OBJ_ANY, _OBJ_INIT_ANY); if (ret != 0) { #ifdef CONFIG_LOG - z_dump_object_error(ret, obj, ko, otype); + k_object_dump_error(ret, obj, ko, otype); #endif return NULL; } @@ -32,14 +32,14 @@ static struct z_object *validate_kernel_object(const void *obj, return ko; } -static ALWAYS_INLINE struct z_object *validate_any_object(const void *obj) +static ALWAYS_INLINE struct k_object *validate_any_object(const void *obj) { return validate_kernel_object(obj, K_OBJ_ANY, _OBJ_INIT_ANY); } bool k_object_is_valid(const void *obj, enum k_objects otype) { - struct z_object *ko; + struct k_object *ko; ko = validate_kernel_object(obj, otype, _OBJ_INIT_TRUE); @@ -50,30 +50,30 @@ bool k_object_is_valid(const void *obj, enum k_objects otype) * syscall_dispatch.c declares weak handlers results in build errors if these * are located in userspace.c. Just put in a separate file. * - * To avoid double z_object_find() lookups, we don't call the implementation + * To avoid double k_object_find() lookups, we don't call the implementation * function, but call a level deeper. */ static inline void z_vrfy_k_object_access_grant(const void *object, struct k_thread *thread) { - struct z_object *ko; + struct k_object *ko; - Z_OOPS(Z_SYSCALL_OBJ_INIT(thread, K_OBJ_THREAD)); + K_OOPS(K_SYSCALL_OBJ_INIT(thread, K_OBJ_THREAD)); ko = validate_any_object(object); - Z_OOPS(Z_SYSCALL_VERIFY_MSG(ko != NULL, "object %p access denied", + K_OOPS(K_SYSCALL_VERIFY_MSG(ko != NULL, "object %p access denied", object)); - z_thread_perms_set(ko, thread); + k_thread_perms_set(ko, thread); } #include static inline void z_vrfy_k_object_release(const void *object) { - struct z_object *ko; + struct k_object *ko; ko = validate_any_object((void *)object); - Z_OOPS(Z_SYSCALL_VERIFY_MSG(ko != NULL, "object %p access denied", + K_OOPS(K_SYSCALL_VERIFY_MSG(ko != NULL, "object %p access denied", (void *)object)); - z_thread_perms_clear(ko, _current); + k_thread_perms_clear(ko, _current); } #include diff --git a/kernel/work.c b/kernel/work.c index c5d7c9b5bb89a2a..a56aa67829c96df 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 6fe18f639927c1e..7a0ee04e4acda64 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 97ee3f6002d1521..af6717bc22ec78f 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 022eb083c84c612..5431a1c7e287ca3 100644 --- a/lib/acpi/Kconfig +++ b/lib/acpi/Kconfig @@ -14,15 +14,28 @@ module = ACPI module-str = acpi 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 help Size of PRT table buffer. +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" - default y depends on SHELL help Enable commands for debugging ACPI using the built-in shell. @@ -33,18 +46,6 @@ config ACPI_DEV_MAX help maximum acpi child devices. -config ACPI_INIT_PRIORITY - int "acpi boot time init level" - default 42 - help - boot time init level for acpi driver. - -config ACPI_MAX_INIT_TABLES - int "maximum table entries" - default 128 - help - maximum number of table entries. - endif # ACPI config ACPI_HID_LEN_MAX diff --git a/lib/acpi/acpi.c b/lib/acpi/acpi.c index d8f91d01ce80766..d9ae1819511fed8 100644 --- a/lib/acpi/acpi.c +++ b/lib/acpi/acpi.c @@ -14,37 +14,32 @@ #include LOG_MODULE_REGISTER(ACPI, CONFIG_ACPI_LOG_LEVEL); -struct acpi { +static struct { struct acpi_dev child_dev[CONFIG_ACPI_DEV_MAX]; int num_dev; +#ifdef CONFIG_PCIE_PRT ACPI_PCI_ROUTING_TABLE pci_prt_table[CONFIG_ACPI_MAX_PRT_ENTRY]; +#endif bool early_init; - int status; -}; - -static struct acpi bus_ctx = { + ACPI_STATUS status; +} acpi = { .status = AE_NOT_CONFIGURED, }; -static ACPI_TABLE_DESC acpi_tables[CONFIG_ACPI_MAX_INIT_TABLES]; - static int acpi_init(void); static int check_init_status(void) { - int ret; - - if (ACPI_SUCCESS(bus_ctx.status)) { - return 0; + if (acpi.status == AE_NOT_CONFIGURED) { + acpi.status = acpi_init(); } - if (bus_ctx.status == AE_NOT_CONFIGURED) { - ret = acpi_init(); + if (ACPI_SUCCESS(acpi.status)) { + return 0; } else { - LOG_ERR("ACPI init was not success\n"); - ret = -EIO; + LOG_ERR("ACPI init was not success"); + return -EIO; } - return ret; } static void notify_handler(ACPI_HANDLE device, UINT32 value, void *ctx) @@ -52,24 +47,6 @@ static void notify_handler(ACPI_HANDLE device, UINT32 value, void *ctx) ACPI_INFO(("Received a notify 0x%X", value)); } -static ACPI_STATUS region_handler(UINT32 Function, ACPI_PHYSICAL_ADDRESS address, UINT32 bit_width, - UINT64 *value, void *handler_ctx, void *region_ctx) -{ - return AE_OK; -} - -static ACPI_STATUS region_init(ACPI_HANDLE RegionHandle, UINT32 Function, void *handler_ctx, - void **region_ctx) -{ - if (Function == ACPI_REGION_DEACTIVATE) { - *region_ctx = NULL; - } else { - *region_ctx = RegionHandle; - } - - return AE_OK; -} - static ACPI_STATUS install_handlers(void) { ACPI_STATUS status; @@ -82,13 +59,7 @@ static ACPI_STATUS install_handlers(void) goto exit; } - status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_SYSTEM_MEMORY, - region_handler, region_init, NULL); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "While installing an OpRegion handler")); - } exit: - return status; } @@ -104,21 +75,18 @@ static ACPI_STATUS initialize_acpica(void) } /* Initialize the ACPI Table Manager and get all ACPI tables */ - if (!bus_ctx.early_init) { + if (!acpi.early_init) { status = AcpiInitializeTables(NULL, 16, FALSE); - } else { - /* Copy the root table list to dynamic memory if already initialized */ - status = AcpiReallocateRootTable(); - } - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "While initializing Table Manager")); - goto exit; + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "While initializing Table Manager")); + goto exit; + } } - /* Initialize the ACPI hardware */ - status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION); + /* Create the ACPI namespace from ACPI tables */ + status = AcpiLoadTables(); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "While enabling ACPI")); + ACPI_EXCEPTION((AE_INFO, status, "While loading ACPI tables")); goto exit; } @@ -129,10 +97,10 @@ static ACPI_STATUS initialize_acpica(void) goto exit; } - /* Create the ACPI namespace from ACPI tables */ - status = AcpiLoadTables(); + /* Initialize the ACPI hardware */ + status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "While loading ACPI tables")); + ACPI_EXCEPTION((AE_INFO, status, "While enabling ACPI")); goto exit; } @@ -223,63 +191,19 @@ static ACPI_STATUS acpi_enable_pic_mode(void) return status; } -static int acpi_get_irq_table(struct acpi *bus, char *bus_name, - ACPI_PCI_ROUTING_TABLE *rt_table, uint32_t rt_size) -{ - ACPI_BUFFER rt_buffer; - ACPI_NAMESPACE_NODE *node; - int status; - - LOG_DBG("%s", bus_name); - - node = acpi_evaluate_method(bus_name, METHOD_NAME__PRT); - if (!node) { - LOG_ERR("Evaluation failed for given device: %s", bus_name); - return -ENODEV; - } - - rt_buffer.Pointer = rt_table; - rt_buffer.Length = ACPI_DEBUG_BUFFER_SIZE; - - status = AcpiGetIrqRoutingTable(node, &rt_buffer); - if (ACPI_FAILURE(status)) { - LOG_ERR("unable to retrieve IRQ Routing Table: %s", bus_name); - return -EIO; - } - - for (int i = 0; i < CONFIG_ACPI_MAX_PRT_ENTRY; i++) { - if (!bus->pci_prt_table[i].SourceIndex) { - break; - } - if (IS_ENABLED(CONFIG_X86_64)) { - /* mark the PRT irq numbers as reserved. */ - arch_irq_set_used(bus->pci_prt_table[i].SourceIndex); - } - } - - return 0; -} - -static int acpi_retrieve_legacy_irq(struct acpi *bus) -{ - /* TODO: assume platform have only one PCH with single PCI bus (bus 0). */ - return acpi_get_irq_table(bus, "_SB.PC00", bus->pci_prt_table, sizeof(bus->pci_prt_table)); -} - static ACPI_STATUS dev_resource_enum_callback(ACPI_HANDLE obj_handle, UINT32 level, void *ctx, void **ret_value) { ACPI_NAMESPACE_NODE *node; ACPI_BUFFER rt_buffer; - struct acpi *bus = (struct acpi *)ctx; struct acpi_dev *child_dev; node = ACPI_CAST_PTR(ACPI_NAMESPACE_NODE, obj_handle); char *path_name; - int status; + ACPI_STATUS status; ACPI_DEVICE_INFO *dev_info; - LOG_DBG("%s %p\n", __func__, node); + LOG_DBG("%s %p", __func__, node); /* get device info such as HID, Class ID etc. */ status = AcpiGetObjectInfo(obj_handle, &dev_info); @@ -288,20 +212,20 @@ static ACPI_STATUS dev_resource_enum_callback(ACPI_HANDLE obj_handle, UINT32 lev goto exit; } - if (bus->num_dev >= CONFIG_ACPI_DEV_MAX) { + if (acpi.num_dev >= CONFIG_ACPI_DEV_MAX) { return AE_NO_MEMORY; } - child_dev = (struct acpi_dev *)&bus->child_dev[bus->num_dev++]; + child_dev = (struct acpi_dev *)&acpi.child_dev[acpi.num_dev++]; child_dev->handle = obj_handle; child_dev->dev_info = dev_info; path_name = AcpiNsGetNormalizedPathname(node, TRUE); if (!path_name) { - LOG_ERR("No memory for path_name\n"); + LOG_ERR("No memory for path_name"); goto exit; } else { - LOG_DBG("Device path: %s\n", path_name); + LOG_DBG("Device path: %s", path_name); child_dev->path = path_name; } @@ -320,122 +244,55 @@ static ACPI_STATUS dev_resource_enum_callback(ACPI_HANDLE obj_handle, UINT32 lev return status; } -static int acpi_enum_devices(struct acpi *bus) +static int acpi_enum_devices(void) { LOG_DBG(""); AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, - dev_resource_enum_callback, NULL, bus, NULL); + dev_resource_enum_callback, NULL, NULL, NULL); return 0; } -static int acpi_init(void) -{ - int status; - - LOG_DBG(""); - - if (bus_ctx.status != AE_NOT_CONFIGURED) { - LOG_DBG("acpi init already done"); - return bus_ctx.status; - } - - /* For debug version only */ - ACPI_DEBUG_INITIALIZE(); - - status = initialize_acpica(); - if (ACPI_FAILURE(status)) { - LOG_ERR("Error in ACPI init:%d", status); - goto exit; - } - - /* Enable IO APIC mode */ - status = acpi_enable_pic_mode(); - if (ACPI_FAILURE(status)) { - LOG_WRN("Error in enable pic mode acpi method:%d", status); - } - - status = acpi_retrieve_legacy_irq(&bus_ctx); - if (status) { - LOG_ERR("Error in retrieve legacy interrupt info:%d", status); - goto exit; - } - - acpi_enum_devices(&bus_ctx); - -exit: - bus_ctx.status = status; - - return status; -} - static int acpi_early_init(void) { ACPI_STATUS status; LOG_DBG(""); - if (bus_ctx.early_init) { + if (acpi.early_init) { LOG_DBG("acpi early init already done"); return 0; } - status = AcpiInitializeTables(acpi_tables, CONFIG_ACPI_MAX_INIT_TABLES, TRUE); + status = AcpiInitializeTables(NULL, 16, FALSE); if (ACPI_FAILURE(status)) { LOG_ERR("Error in acpi table init:%d", status); return -EIO; } - bus_ctx.early_init = true; + acpi.early_init = true; return 0; } -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 (((bus_ctx.pci_prt_table[i].Address >> 16) & 0xffff) == slot && - bus_ctx.pci_prt_table[i].Pin + 1 == pin) { - LOG_DBG("[%d]Device irq info: slot:%d pin:%d irq:%d", i, slot, pin, - bus_ctx.pci_prt_table[i].SourceIndex); - return bus_ctx.pci_prt_table[i].SourceIndex; - } - } - - return UINT_MAX; -} - int acpi_current_resource_get(char *dev_name, ACPI_RESOURCE **res) { ACPI_BUFFER rt_buffer; ACPI_NAMESPACE_NODE *node; - int status; + ACPI_STATUS status; LOG_DBG("%s", dev_name); status = check_init_status(); if (status) { - return status; + return -EAGAIN; } node = acpi_evaluate_method(dev_name, METHOD_NAME__CRS); if (!node) { LOG_ERR("Evaluation failed for given device: %s", dev_name); - status = -ENOTSUP; - goto exit; + return -ENOTSUP; } rt_buffer.Pointer = NULL; @@ -444,34 +301,31 @@ int acpi_current_resource_get(char *dev_name, ACPI_RESOURCE **res) status = AcpiGetCurrentResources(node, &rt_buffer); if (ACPI_FAILURE(status)) { LOG_ERR("AcpiGetCurrentResources failed: %s", AcpiFormatException(status)); - status = -ENOTSUP; + return -ENOTSUP; } else { *res = rt_buffer.Pointer; } -exit: - - return status; + return 0; } int acpi_possible_resource_get(char *dev_name, ACPI_RESOURCE **res) { ACPI_BUFFER rt_buffer; ACPI_NAMESPACE_NODE *node; - int status; + ACPI_STATUS status; LOG_DBG("%s", dev_name); status = check_init_status(); if (status) { - return status; + return -EAGAIN; } node = acpi_evaluate_method(dev_name, METHOD_NAME__PRS); if (!node) { LOG_ERR("Evaluation failed for given device: %s", dev_name); - status = -ENOTSUP; - goto exit; + return -ENOTSUP; } rt_buffer.Pointer = NULL; @@ -480,9 +334,7 @@ int acpi_possible_resource_get(char *dev_name, ACPI_RESOURCE **res) AcpiGetPossibleResources(node, &rt_buffer); *res = rt_buffer.Pointer; -exit: - - return status; + return 0; } int acpi_current_resource_free(ACPI_RESOURCE *res) @@ -492,6 +344,58 @@ int acpi_current_resource_free(ACPI_RESOURCE *res) return 0; } +#ifdef CONFIG_PCIE_PRT +static int acpi_get_irq_table(char *bus_name, ACPI_PCI_ROUTING_TABLE *rt_table, uint32_t rt_size) +{ + ACPI_BUFFER rt_buffer; + ACPI_NAMESPACE_NODE *node; + ACPI_STATUS status; + + LOG_DBG("%s", bus_name); + + node = acpi_evaluate_method(bus_name, METHOD_NAME__PRT); + if (!node) { + LOG_ERR("Evaluation failed for given device: %s", bus_name); + return -ENODEV; + } + + rt_buffer.Pointer = rt_table; + rt_buffer.Length = rt_size * 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); + 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; + } + + for (size_t i = 0; i < ARRAY_SIZE(acpi.pci_prt_table); i++) { + if (!acpi.pci_prt_table[i].SourceIndex) { + break; + } + if (IS_ENABLED(CONFIG_X86_64)) { + /* mark the PRT irq numbers as reserved. */ + arch_irq_set_used(acpi.pci_prt_table[i].SourceIndex); + } + } + + return 0; + +} + int acpi_get_irq_routing_table(char *bus_name, ACPI_PCI_ROUTING_TABLE *rt_table, size_t rt_size) { @@ -502,14 +406,41 @@ int acpi_get_irq_routing_table(char *bus_name, return ret; } - return acpi_get_irq_table(&bus_ctx, bus_name, rt_table, rt_size); + return acpi_get_irq_table(bus_name, rt_table, 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; } +#endif /* CONFIG_PCIE_PRT */ ACPI_RESOURCE *acpi_resource_parse(ACPI_RESOURCE *res, int res_type) { do { if (!res->Length) { - LOG_DBG("Error: zero length found!\n"); + LOG_DBG("Error: zero length found!"); break; } else if (res->Type == res_type) { break; @@ -569,7 +500,7 @@ int acpi_device_type_get(ACPI_RESOURCE *res) do { if (!res->Length) { - LOG_ERR("Error: zero length found!\n"); + LOG_ERR("Error: zero length found!"); break; } type = acpi_res_type(res); @@ -594,9 +525,9 @@ struct acpi_dev *acpi_device_get(char *hid, int inst) } do { - child_dev = &bus_ctx.child_dev[i]; + child_dev = &acpi.child_dev[i]; if (!child_dev->path) { - LOG_DBG("NULL device path found\n"); + LOG_DBG("NULL device path found"); continue; } @@ -615,22 +546,22 @@ struct acpi_dev *acpi_device_get(char *hid, int inst) return child_dev; } } - } while (i++ < bus_ctx.num_dev); + } while (i++ < acpi.num_dev); return NULL; } struct acpi_dev *acpi_device_by_index_get(int index) { - return index < bus_ctx.num_dev ? &bus_ctx.child_dev[index] : NULL; + return index < acpi.num_dev ? &acpi.child_dev[index] : NULL; } void *acpi_table_get(char *signature, int inst) { - int status; + ACPI_STATUS status; ACPI_TABLE_HEADER *table; - if (!bus_ctx.early_init) { + if (!acpi.early_init) { status = acpi_early_init(); if (status) { LOG_ERR("ACPI early init failed"); @@ -647,7 +578,7 @@ void *acpi_table_get(char *signature, int inst) return (void *)table; } -static uint32_t acpi_get_subtable_entry_num(int type, struct acpi_subtable_header *subtable, +static uint32_t acpi_get_subtable_entry_num(int type, ACPI_SUBTABLE_HEADER *subtable, uintptr_t offset, uintptr_t base, uint32_t madt_len) { uint32_t subtable_cnt = 0; @@ -667,12 +598,12 @@ static uint32_t acpi_get_subtable_entry_num(int type, struct acpi_subtable_heade return subtable_cnt; } -int acpi_madt_entry_get(int type, struct acpi_subtable_header **tables, int *num_inst) +int acpi_madt_entry_get(int type, ACPI_SUBTABLE_HEADER **tables, int *num_inst) { - struct acpi_table_header *madt = acpi_table_get("APIC", 0); + ACPI_TABLE_HEADER *madt = acpi_table_get("APIC", 0); uintptr_t base = POINTER_TO_UINT(madt); uintptr_t offset = sizeof(ACPI_TABLE_MADT); - struct acpi_subtable_header *subtable; + ACPI_SUBTABLE_HEADER *subtable; if (!madt) { return -EIO; @@ -695,15 +626,15 @@ int acpi_madt_entry_get(int type, struct acpi_subtable_header **tables, int *num return -ENODEV; } -int acpi_dmar_entry_get(enum AcpiDmarType type, struct acpi_subtable_header **tables) +int acpi_dmar_entry_get(enum AcpiDmarType type, ACPI_SUBTABLE_HEADER **tables) { struct acpi_table_dmar *dmar = acpi_table_get("DMAR", 0); uintptr_t base = POINTER_TO_UINT(dmar); uintptr_t offset = sizeof(ACPI_TABLE_DMAR); - struct acpi_dmar_header *subtable; + ACPI_DMAR_HEADER *subtable; if (!dmar) { - LOG_ERR("error on get DMAR table\n"); + LOG_ERR("error on get DMAR table"); return -EIO; } @@ -720,22 +651,109 @@ int acpi_dmar_entry_get(enum AcpiDmarType type, struct acpi_subtable_header **ta return -ENODEV; } -int acpi_drhd_get(enum AcpiDmarScopeType scope, struct acpi_dmar_device_scope *dev_scope, - union acpi_dmar_id *dmar_id, int *num_inst, int max_inst) +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) { uintptr_t offset = sizeof(ACPI_DMAR_HARDWARE_UNIT); uint32_t i = 0; - struct acpi_dmar_header *drdh; - struct acpi_dmar_device_scope *subtable; - struct acpi_dmar_pci_path *dev_path; + ACPI_DMAR_HEADER *drdh; + ACPI_DMAR_DEVICE_SCOPE *subtable; + ACPI_DMAR_PCI_PATH *dev_path; int ret; uintptr_t base; int scope_size; ret = acpi_dmar_entry_get(ACPI_DMAR_TYPE_HARDWARE_UNIT, - (struct acpi_subtable_header **)&drdh); + (ACPI_SUBTABLE_HEADER **)&drdh); if (ret) { - LOG_ERR("Error on retrieve DMAR table\n"); + LOG_ERR("Error on retrieve DMAR table"); return ret; } @@ -759,7 +777,7 @@ int acpi_drhd_get(enum AcpiDmarScopeType scope, struct acpi_dmar_device_scope *d while (num_path--) { if (i >= max_inst) { - LOG_ERR("DHRD not enough buffer size\n"); + LOG_ERR("DHRD not enough buffer size"); return -ENOBUFS; } dmar_id[i].bits.bus = subtable->Bus; @@ -780,7 +798,7 @@ int acpi_drhd_get(enum AcpiDmarScopeType scope, struct acpi_dmar_device_scope *d *num_inst = i; if (!i) { - LOG_ERR("Error on retrieve DRHD Info\n"); + LOG_ERR("Error on retrieve DRHD Info"); return -ENODEV; } @@ -791,10 +809,13 @@ int acpi_drhd_get(enum AcpiDmarScopeType scope, struct acpi_dmar_device_scope *d return 0; } -struct acpi_madt_local_apic *acpi_local_apic_get(uint32_t cpu_num) +#define ACPI_CPU_FLAGS_ENABLED 0x01u + +ACPI_MADT_LOCAL_APIC *acpi_local_apic_get(int cpu_num) { - struct acpi_madt_local_apic *lapic; + ACPI_MADT_LOCAL_APIC *lapic; int cpu_cnt; + int idx; if (acpi_madt_entry_get(ACPI_MADT_TYPE_LOCAL_APIC, (ACPI_SUBTABLE_HEADER **)&lapic, &cpu_cnt)) { @@ -802,10 +823,52 @@ struct acpi_madt_local_apic *acpi_local_apic_get(uint32_t cpu_num) return NULL; } - if ((cpu_num >= cpu_cnt) || !(lapic[cpu_num].LapicFlags & 1u)) { - /* Proccessor not enabled. */ - return NULL; + for (idx = 0; cpu_num >= 0 && idx < cpu_cnt; idx++) { + if (lapic[idx].LapicFlags & ACPI_CPU_FLAGS_ENABLED) { + if (cpu_num == 0) { + return &lapic[idx]; + } + + cpu_num--; + } } - return &lapic[cpu_num]; + return NULL; +} + +static int acpi_init(void) +{ + ACPI_STATUS status; + + LOG_DBG(""); + + /* For debug version only */ + ACPI_DEBUG_INITIALIZE(); + + status = initialize_acpica(); + if (ACPI_FAILURE(status)) { + LOG_ERR("Error in ACPI init:%d", status); + goto exit; + } + + /* Enable IO APIC mode */ + status = acpi_enable_pic_mode(); + if (ACPI_FAILURE(status)) { + 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: + return status; } diff --git a/lib/acpi/acpi_shell.c b/lib/acpi/acpi_shell.c index c6c5d5ed60d3628..e2db3aaa30e9089 100644 --- a/lib/acpi/acpi_shell.c +++ b/lib/acpi/acpi_shell.c @@ -12,131 +12,129 @@ #include #include -#define MAX_PR_BUFF (4096) - -static ACPI_PCI_ROUTING_TABLE irq_prt_table[CONFIG_ACPI_MAX_PRT_ENTRY]; -static uint8_t prs_buffer[MAX_PR_BUFF]; - static void dump_dev_res(const struct shell *sh, ACPI_RESOURCE *res_lst) { ACPI_RESOURCE *res = res_lst; - shell_print(sh, "\n**** ACPI Device Resource Info ****\n"); + shell_print(sh, "**** ACPI Device Resource Info ****"); do { if (!res->Length) { - shell_error(sh, "Error: zero length found!\n"); + shell_error(sh, "Error: zero length found!"); break; } switch (res->Type) { case ACPI_RESOURCE_TYPE_IRQ: - shell_print(sh, "\nACPI_RESOURCE_TYPE_IRQ\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_IRQ"); ACPI_RESOURCE_IRQ *irq_res = &res->Data.Irq; - shell_print(sh, - "DescriptorLength: %x, Triggering:%x, Polarity:%x, Shareable:%x,", - irq_res->DescriptorLength, irq_res->Triggering, irq_res->Polarity, - irq_res->Shareable); - shell_print(sh, - "InterruptCount:%d, Interrupts[0]:%x\n", irq_res->InterruptCount, - irq_res->Interrupts[0]); + shell_print(sh, "\tDescriptorLength: %x", irq_res->DescriptorLength); + shell_print(sh, "\tTriggering: %x", irq_res->Triggering); + shell_print(sh, "\tPolarity: %x", irq_res->Polarity); + shell_print(sh, "\tShareable: %x", irq_res->Shareable); + shell_print(sh, "\tInterruptCount: %d", irq_res->InterruptCount); + shell_print(sh, "\tInterrupts[0]: %x", irq_res->Interrupts[0]); break; - case ACPI_RESOURCE_TYPE_IO: - ACPI_RESOURCE_IO * io_res = &res->Data.Io; - - shell_print(sh, "\n ACPI_RESOURCE_TYPE_IO\n"); - shell_print(sh, - "IoDecode: %x, Alignment:%x, AddressLength:%x, Minimum:%x,Maximum:%x\n", - io_res->IoDecode, io_res->Alignment, - io_res->AddressLength, io_res->Minimum, - io_res->Maximum); + case ACPI_RESOURCE_TYPE_IO: { + ACPI_RESOURCE_IO *io_res = &res->Data.Io; + + shell_print(sh, "ACPI_RESOURCE_TYPE_IO"); + shell_print(sh, "\tIoDecode: %x", io_res->IoDecode); + shell_print(sh, "\tAlignment: %x", io_res->Alignment); + shell_print(sh, "\tAddressLength: %x", io_res->AddressLength); + shell_print(sh, "\tMinimum: %x", io_res->Minimum); + shell_print(sh, "\tMaximum: %x", io_res->Maximum); break; + } case ACPI_RESOURCE_TYPE_DMA: - shell_print(sh, "ACPI_RESOURCE_TYPE_DMA\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_DMA"); break; case ACPI_RESOURCE_TYPE_START_DEPENDENT: - shell_print(sh, "ACPI_RESOURCE_TYPE_START_DEPENDENT\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_START_DEPENDENT"); break; case ACPI_RESOURCE_TYPE_END_DEPENDENT: - shell_print(sh, "ACPI_RESOURCE_TYPE_END_DEPENDENT\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_END_DEPENDENT"); break; case ACPI_RESOURCE_TYPE_FIXED_IO: - shell_print(sh, "ACPI_RESOURCE_TYPE_FIXED_IO\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_FIXED_IO"); break; case ACPI_RESOURCE_TYPE_VENDOR: - shell_print(sh, "ACPI_RESOURCE_TYPE_VENDOR\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_VENDOR"); break; case ACPI_RESOURCE_TYPE_MEMORY24: - shell_print(sh, "ACPI_RESOURCE_TYPE_MEMORY24\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_MEMORY24"); break; - case ACPI_RESOURCE_TYPE_MEMORY32: - ACPI_RESOURCE_MEMORY32 * mem_res = &res->Data.Memory32; + case ACPI_RESOURCE_TYPE_MEMORY32: { + ACPI_RESOURCE_MEMORY32 *mem_res = &res->Data.Memory32; - shell_print(sh, "\nACPI_RESOURCE_TYPE_MEMORY32\n\n"); - shell_print(sh, "Minimum:%x, Maximum:%x\n", - mem_res->Minimum, mem_res->Maximum); + shell_print(sh, "ACPI_RESOURCE_TYPE_MEMORY32"); + shell_print(sh, "\tMinimum: %x", mem_res->Minimum); + shell_print(sh, "\tMaximum: %x", mem_res->Maximum); break; - case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - ACPI_RESOURCE_FIXED_MEMORY32 * fix_mem_res = &res->Data.FixedMemory32; + } + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: { + ACPI_RESOURCE_FIXED_MEMORY32 *fix_mem_res = &res->Data.FixedMemory32; - shell_print(sh, "\nACPI_RESOURCE_TYPE_FIXED_MEMORY32\n\n"); - shell_print(sh, "Address:%x\n", fix_mem_res->Address); + shell_print(sh, "ACPI_RESOURCE_TYPE_FIXED_MEMORY32"); + shell_print(sh, "\tAddress: %x", fix_mem_res->Address); break; + } case ACPI_RESOURCE_TYPE_ADDRESS16: - shell_print(sh, "ACPI_RESOURCE_TYPE_ADDRESS16\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_ADDRESS16"); break; - case ACPI_RESOURCE_TYPE_ADDRESS32: - ACPI_RESOURCE_ADDRESS32 * add_res = &res->Data.Address32; + case ACPI_RESOURCE_TYPE_ADDRESS32: { + ACPI_RESOURCE_ADDRESS32 *add_res = &res->Data.Address32; - shell_print(sh, "\nACPI_RESOURCE_TYPE_ADDRESS32\n\n"); - shell_print(sh, "Minimum:%x, Maximum:%x\n", add_res->Address.Minimum, - add_res->Address.Maximum); + shell_print(sh, "ACPI_RESOURCE_TYPE_ADDRESS32"); + shell_print(sh, "\tMinimum: %x", add_res->Address.Minimum); + shell_print(sh, "\tMaximum: %x", add_res->Address.Maximum); break; - case ACPI_RESOURCE_TYPE_ADDRESS64: - ACPI_RESOURCE_ADDRESS64 * add_res64 = &res->Data.Address64; + } + case ACPI_RESOURCE_TYPE_ADDRESS64: { + ACPI_RESOURCE_ADDRESS64 *add_res64 = &res->Data.Address64; - shell_print(sh, "\nACPI_RESOURCE_TYPE_ADDRESS64\n\n"); - shell_print(sh, - "Minimum:%llx, Maximum:%llx\n", add_res64->Address.Minimum, - add_res64->Address.Maximum); + shell_print(sh, "ACPI_RESOURCE_TYPE_ADDRESS64"); + shell_print(sh, "\tMinimum: %llx", add_res64->Address.Minimum); + shell_print(sh, "\tMaximum: %llx", add_res64->Address.Maximum); break; + } case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: - shell_print(sh, "ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64"); break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: - shell_print(sh, "ACPI_RESOURCE_TYPE_EXTENDED_IRQ\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_EXTENDED_IRQ"); break; case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: - shell_print(sh, "ACPI_RESOURCE_TYPE_GENERIC_REGISTER\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_GENERIC_REGISTER"); break; case ACPI_RESOURCE_TYPE_GPIO: - shell_print(sh, "ACPI_RESOURCE_TYPE_GPIO\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_GPIO"); break; case ACPI_RESOURCE_TYPE_FIXED_DMA: - shell_print(sh, "ACPI_RESOURCE_TYPE_FIXED_DMA\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_FIXED_DMA"); break; case ACPI_RESOURCE_TYPE_SERIAL_BUS: - shell_print(sh, "ACPI_RESOURCE_TYPE_SERIAL_BUS\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_SERIAL_BUS"); break; case ACPI_RESOURCE_TYPE_PIN_FUNCTION: - shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_FUNCTION\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_FUNCTION"); break; case ACPI_RESOURCE_TYPE_PIN_CONFIG: - shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_CONFIG\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_CONFIG"); break; case ACPI_RESOURCE_TYPE_PIN_GROUP: - shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_GROUP\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_GROUP"); break; case ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION: - shell_print(sh, - "ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION"); break; case ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG: - shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG\n\n"); + shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG"); break; default: + shell_error(sh, "Unknown resource type %d", res->Type); } res = ACPI_NEXT_RESOURCE(res); @@ -150,13 +148,13 @@ 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\n"); + shell_error(sh, "invalid arugment"); return -EINVAL; } status = acpi_current_resource_get(argv[1], &res_lst); if (status) { - shell_error(sh, "Error on ACPI _CRS method: %d\n", status); + shell_error(sh, "Error on ACPI _CRS method: %d", status); return status; } @@ -170,16 +168,16 @@ static int dump_dev_crs(const struct shell *sh, size_t argc, char **argv) static int dump_dev_prs(const struct shell *sh, size_t argc, char **argv) { int status; - ACPI_RESOURCE *res_lst = (ACPI_RESOURCE *)prs_buffer; + ACPI_RESOURCE *res_lst; if (argc < 2) { - shell_error(sh, "invalid arugment\n"); + shell_error(sh, "invalid arugment"); return -EINVAL; } status = acpi_possible_resource_get(argv[1], &res_lst); if (status) { - shell_error(sh, "Error in on ACPI _PRS method: %d\n", status); + shell_error(sh, "Error in on ACPI _PRS method: %d", status); return status; } @@ -190,29 +188,31 @@ 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) { - int status, cnt; - ACPI_PCI_ROUTING_TABLE *prt; - - if (argc < 2) { - shell_error(sh, "invalid arugment\n"); - return -EINVAL; - } + 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; + + if (argc < 2) { + shell_error(sh, "invalid arugment"); + return -EINVAL; + } - status = acpi_get_irq_routing_table(argv[1], - irq_prt_table, sizeof(irq_prt_table)); - if (status) { - return status; - } + 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\n", cnt); - shell_print(sh, - "DevNum: %lld Pin:%d IRQ: %d\n", (prt->Address >> 16) & 0xFFFF, prt->Pin, - prt->SourceIndex); + 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); - } + prt = ACPI_ADD_PTR(ACPI_PCI_ROUTING_TABLE, prt, prt->Length); + } + })); /* IF_ENABLED(CONFIG_PCIE_PRT) */ return 0; } @@ -227,10 +227,11 @@ static int enum_dev(const struct shell *sh, size_t argc, char **argv) dev = acpi_device_get(argv[1], 0); if (!dev || !dev->res_lst) { - shell_error(sh, "acpi get device failed for HID: %s\n", argv[1]); + shell_error(sh, "acpi get device failed for HID: %s", argv[1]); return -EIO; } - shell_print(sh, "\nName:%s\n", dev->path ? dev->path : "Non"); + + shell_print(sh, "Name: %s", dev->path ? dev->path : "None"); dump_dev_res(sh, dev->res_lst); return 0; @@ -244,17 +245,17 @@ static int read_table(const struct shell *sh, size_t argc, char **argv) return -EINVAL; } - shell_print(sh, "ACPI Table Name: %s\n", argv[1]); - table = acpi_table_get(argv[1], 0); if (!table) { - shell_error(sh, "ACPI get table failed\n"); + shell_error(sh, "ACPI get table %s failed", argv[1]); return -EIO; } - shell_print(sh, "ACPI Table Info:\n"); - shell_print(sh, "Signature: %4s Table Length:%d Revision:%d OemId:%s\n", - table->Signature, table->Length, table->Revision, table->OemId); + shell_print(sh, "ACPI Table %s:", argv[1]); + shell_print(sh, "\tSignature: %.4s", table->Signature); + shell_print(sh, "\tTable Length: %d", table->Length); + shell_print(sh, "\tRevision: %d", table->Revision); + shell_print(sh, "\tOemId: %s", table->OemId); return 0; } @@ -267,8 +268,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE( SHELL_CMD(prs, NULL, "display device possible resource settings (eg:acpi crs _SB.PC00.LPCB.RTC)", dump_dev_prs), - SHELL_CMD(prt, NULL, "display PRT details for a given bus (eg:acpi prt _SB.PC00)", - dump_prt), + SHELL_COND_CMD(CONFIG_PCIE_PRT, prt, NULL, + "display PRT details for a given bus (eg:acpi prt _SB.PC00)", + dump_prt), SHELL_CMD(enum, NULL, "enumerate device using hid (for enum HPET timer device,eg:acpi enum PNP0103)", enum_dev), diff --git a/lib/cpp/Kconfig b/lib/cpp/Kconfig index 696df05102ac9b1..6ac4dae170a44c1 100644 --- a/lib/cpp/Kconfig +++ b/lib/cpp/Kconfig @@ -74,6 +74,7 @@ config FULL_LIBCPP_SUPPORTED choice LIBCPP_IMPLEMENTATION prompt "C++ Standard Library Implementation" default EXTERNAL_LIBCPP if REQUIRES_FULL_LIBCPP && NATIVE_BUILD + default LIBCXX_LIBCPP if REQUIRES_FULL_LIBCPP && "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "llvm" default GLIBCXX_LIBCPP if REQUIRES_FULL_LIBCPP default MINIMAL_LIBCPP @@ -96,6 +97,17 @@ config GLIBCXX_LIBCPP Build with GNU C++ Standard Library (libstdc++) provided by the GNU Compiler Collection (GCC)-based toolchain. +config LIBCXX_LIBCPP + bool "LLVM C++ Standard Library" + depends on !NATIVE_APPLICATION + depends on NEWLIB_LIBC + depends on "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "llvm" + select FULL_LIBCPP_SUPPORTED + help + Build with LLVM C++ Standard Library (libc++) provided by LLVM + toolchain. Information about library can be found at + https://libcxx.llvm.org + config ARCMWDT_LIBCPP bool "ARC MWDT C++ Library" depends on !NATIVE_APPLICATION diff --git a/lib/crc/crc_shell.c b/lib/crc/crc_shell.c index e75d88623e1027e..32393ff6f6e39c6 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 000000000000000..f3853fc5b7da85f --- /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 000000000000000..7f01b280b3b5227 --- /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) + 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 a29f4adfbd6b642..df11f18b9e0fd44 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 000000000000000..80640da2fd42afd --- /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 000000000000000..e9c28b96d2ffb59 --- /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 000000000000000..443ffc9e7ebeac0 --- /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 000000000000000..af63c8cdd8c75a7 --- /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/Kconfig b/lib/libc/Kconfig index 4ebf556dd5cf953..8b71808ff54845b 100644 --- a/lib/libc/Kconfig +++ b/lib/libc/Kconfig @@ -10,6 +10,14 @@ config REQUIRES_FULL_LIBC Select a C library implementation that provides a complete C library implementation, rather than the subset provided by MINIMAL_LIBC. +config REQUIRES_FLOAT_PRINTF + bool "Requires floating point support in printf" + select CBPRINTF_FP_SUPPORT if MINIMAL_LIBC + select NEWLIB_LIBC_FLOAT_PRINTF if NEWLIB_LIBC + help + Select a printf implementation that provides a complete + implementation including floating point support. + config FULL_LIBC_SUPPORTED bool help @@ -53,7 +61,7 @@ menu "C Library" choice LIBC_IMPLEMENTATION prompt "C Library Implementation" - default EXTERNAL_LIBC if NATIVE_BUILD + default EXTERNAL_LIBC if NATIVE_BUILD && !(NATIVE_LIBRARY && POSIX_API) default PICOLIBC default NEWLIB_LIBC if REQUIRES_FULL_LIBC default MINIMAL_LIBC @@ -72,7 +80,7 @@ config MINIMAL_LIBC config PICOLIBC bool "Picolibc library" select COMMON_LIBC_ABORT - select THREAD_LOCAL_STORAGE if ARCH_HAS_THREAD_LOCAL_STORAGE && TOOLCHAIN_SUPPORTS_THREAD_LOCAL_STORAGE + imply THREAD_LOCAL_STORAGE if ARCH_HAS_THREAD_LOCAL_STORAGE && TOOLCHAIN_SUPPORTS_THREAD_LOCAL_STORAGE select LIBC_ERRNO if THREAD_LOCAL_STORAGE select NEED_LIBC_MEM_PARTITION imply COMMON_LIBC_MALLOC diff --git a/lib/libc/arcmwdt/include/errno.h b/lib/libc/arcmwdt/include/errno.h new file mode 100644 index 000000000000000..c69da58b1678165 --- /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 000000000000000..822e66f24d283db --- /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/arcmwdt/libc-hooks.c b/lib/libc/arcmwdt/libc-hooks.c index b7ee5f90a81b3a0..babf24ebda8c9b3 100644 --- a/lib/libc/arcmwdt/libc-hooks.c +++ b/lib/libc/arcmwdt/libc-hooks.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include @@ -56,7 +56,7 @@ int z_impl_zephyr_write_stdout(const void *buffer, int nbytes) #ifdef CONFIG_USERSPACE static inline int z_vrfy_zephyr_write_stdout(const void *buf, int nbytes) { - Z_OOPS(Z_SYSCALL_MEMORY_READ(buf, nbytes)); + K_OOPS(K_SYSCALL_MEMORY_READ(buf, nbytes)); return z_impl_zephyr_write_stdout(buf, nbytes); } #include diff --git a/lib/libc/common/CMakeLists.txt b/lib/libc/common/CMakeLists.txt index 48372158ea569f4..4b101d8b84bdc97 100644 --- a/lib/libc/common/CMakeLists.txt +++ b/lib/libc/common/CMakeLists.txt @@ -1,8 +1,20 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_system_include_directories(include) + zephyr_library() zephyr_library_property(ALLOW_EMPTY TRUE) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_ABORT source/stdlib/abort.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_TIME source/time/time.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_MALLOC source/stdlib/malloc.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_STRNLEN source/string/strnlen.c) +zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_THRD + source/thrd/cnd.c + source/thrd/mtx.c + source/thrd/once.c + source/thrd/thrd.c + source/thrd/tss.c + ) + +# Prevent compiler from optimizing calloc into an infinite recursive call +zephyr_library_compile_options($) diff --git a/lib/libc/common/Kconfig b/lib/libc/common/Kconfig index 56ac8f7b22b3193..dc22d0c2108d5f1 100644 --- a/lib/libc/common/Kconfig +++ b/lib/libc/common/Kconfig @@ -67,3 +67,13 @@ config COMMON_LIBC_STRNLEN bool help common implementation of strnlen(). + +config COMMON_LIBC_THRD + bool "C11 API support" + depends on DYNAMIC_THREAD + # Note: the POSIX_API dependency is only necessary until common elements + # of C11 threads and POSIX API can be abstracted out to a common library. + depends on POSIX_API + default y + help + Common implementation of C11 API. diff --git a/lib/libc/common/include/machine/_threads.h b/lib/libc/common/include/machine/_threads.h new file mode 100644 index 000000000000000..cebce717c739fca --- /dev/null +++ b/lib/libc/common/include/machine/_threads.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_LIBC_COMMON_INCLUDE_MACHINE__THREADS_H_ +#define ZEPHYR_LIB_LIBC_COMMON_INCLUDE_MACHINE__THREADS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ONCE_FLAG_INIT {0} + +typedef int cnd_t; +typedef int mtx_t; +typedef int thrd_t; +typedef int tss_t; +typedef struct { + char flag; +} once_flag; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_LIB_LIBC_COMMON_INCLUDE_MACHINE__THREADS_H_ */ diff --git a/lib/libc/common/include/threads.h b/lib/libc/common/include/threads.h new file mode 100644 index 000000000000000..b2a8c738389569c --- /dev/null +++ b/lib/libc/common/include/threads.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_LIBC_COMMON_INCLUDE_THREADS_H_ +#define ZEPHYR_LIB_LIBC_COMMON_INCLUDE_THREADS_H_ + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*thrd_start_t)(void *arg); + +enum { + thrd_success, +#define thrd_success thrd_success + thrd_nomem, +#define thrd_nomem thrd_nomem + thrd_timedout, +#define thrd_timedout thrd_timedout + thrd_busy, +#define thrd_busy thrd_busy + thrd_error, +#define thrd_error thrd_error +}; + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec *duration, struct timespec *remaining); +void thrd_yield(void); +_Noreturn void thrd_exit(int res); +int thrd_detach(thrd_t thr); +int thrd_join(thrd_t thr, int *res); + +enum { + mtx_plain, +#define mtx_plain mtx_plain + mtx_timed, +#define mtx_timed mtx_timed + mtx_recursive, +#define mtx_recursive mtx_recursive +}; + +int mtx_init(mtx_t *mutex, int type); +void mtx_destroy(mtx_t *mutex); +int mtx_lock(mtx_t *mutex); +int mtx_timedlock(mtx_t *ZRESTRICT mutex, const struct timespec *ZRESTRICT time_point); +int mtx_trylock(mtx_t *mutex); +int mtx_unlock(mtx_t *mutex); + +int cnd_init(cnd_t *cond); +int cnd_wait(cnd_t *cond, mtx_t *mtx); +int cnd_timedwait(cnd_t *ZRESTRICT cond, mtx_t *ZRESTRICT mtx, const struct timespec *ZRESTRICT ts); +int cnd_signal(cnd_t *cond); +int cnd_broadcast(cnd_t *cond); +void cnd_destroy(cnd_t *cond); + +#ifndef thread_local +#define thread_local _Thread_local +#endif + +typedef void (*tss_dtor_t)(void *val); + +int tss_create(tss_t *key, tss_dtor_t destructor); +void *tss_get(tss_t key); +int tss_set(tss_t key, void *val); +void tss_delete(tss_t key); + +void call_once(once_flag *flag, void (*func)(void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_LIB_LIBC_COMMON_INCLUDE_THREADS_H_ */ diff --git a/lib/libc/common/source/stdlib/malloc.c b/lib/libc/common/source/stdlib/malloc.c index 6762c38e92720bf..e3a5db6f7d53c76 100644 --- a/lib/libc/common/source/stdlib/malloc.c +++ b/lib/libc/common/source/stdlib/malloc.c @@ -18,7 +18,7 @@ #include #include #ifdef CONFIG_MMU -#include +#include #endif #define LOG_LEVEL CONFIG_KERNEL_LOG_LEVEL diff --git a/lib/libc/common/source/thrd/cnd.c b/lib/libc/common/source/thrd/cnd.c new file mode 100644 index 000000000000000..aea6f5cb78a4209 --- /dev/null +++ b/lib/libc/common/source/thrd/cnd.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +int cnd_broadcast(cnd_t *cond) +{ + switch (pthread_cond_broadcast(cond)) { + case 0: + return thrd_success; + default: + return thrd_error; + } +} + +void cnd_destroy(cnd_t *cond) +{ + (void)pthread_cond_destroy(cond); +} + +int cnd_init(cnd_t *cond) +{ + switch (pthread_cond_init(cond, NULL)) { + case 0: + return thrd_success; + case ENOMEM: + return thrd_nomem; + default: + return thrd_error; + } +} + +int cnd_signal(cnd_t *cond) +{ + switch (pthread_cond_signal(cond)) { + case 0: + return thrd_success; + case ENOMEM: + return thrd_nomem; + default: + return thrd_error; + } +} + +int cnd_timedwait(cnd_t *restrict cond, mtx_t *restrict mtx, const struct timespec *restrict ts) +{ + switch (pthread_cond_timedwait(cond, mtx, ts)) { + case 0: + return thrd_success; + case ETIMEDOUT: + return thrd_timedout; + default: + return thrd_error; + } +} + +int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + switch (pthread_cond_wait(cond, mtx)) { + case 0: + return thrd_success; + default: + return thrd_error; + } +} diff --git a/lib/libc/common/source/thrd/mtx.c b/lib/libc/common/source/thrd/mtx.c new file mode 100644 index 000000000000000..9746ea64fe6901e --- /dev/null +++ b/lib/libc/common/source/thrd/mtx.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +int mtx_init(mtx_t *mutex, int type) +{ + int ret; + pthread_mutexattr_t attr; + pthread_mutexattr_t *attrp = NULL; + + switch (type) { + case mtx_plain: + case mtx_timed: + break; + case mtx_plain | mtx_recursive: + case mtx_timed | mtx_recursive: + attrp = &attr; + ret = pthread_mutexattr_init(attrp); + __ASSERT_NO_MSG(ret == 0); + + ret = pthread_mutexattr_settype(attrp, PTHREAD_MUTEX_RECURSIVE); + __ASSERT_NO_MSG(ret == 0); + break; + default: + return thrd_error; + } + + switch (pthread_mutex_init(mutex, attrp)) { + case 0: + ret = thrd_success; + break; + default: + ret = thrd_error; + break; + } + + if (attrp != NULL) { + (void)pthread_mutexattr_destroy(attrp); + } + + return ret; +} + +void mtx_destroy(mtx_t *mutex) +{ + (void)pthread_mutex_destroy(mutex); +} + +int mtx_lock(mtx_t *mutex) +{ + switch (pthread_mutex_lock(mutex)) { + case 0: + return thrd_success; + default: + return thrd_error; + } +} + +int mtx_timedlock(mtx_t *restrict mutex, const struct timespec *restrict time_point) +{ + switch (pthread_mutex_timedlock(mutex, time_point)) { + case 0: + return thrd_success; + case ETIMEDOUT: + return thrd_timedout; + default: + return thrd_error; + } +} + +int mtx_trylock(mtx_t *mutex) +{ + switch (pthread_mutex_trylock(mutex)) { + case 0: + return thrd_success; + case EBUSY: + return thrd_busy; + default: + return thrd_error; + } +} + +int mtx_unlock(mtx_t *mutex) +{ + switch (pthread_mutex_unlock(mutex)) { + case 0: + return thrd_success; + default: + return thrd_error; + } +} diff --git a/lib/libc/common/source/thrd/once.c b/lib/libc/common/source/thrd/once.c new file mode 100644 index 000000000000000..7cfd9983df8958a --- /dev/null +++ b/lib/libc/common/source/thrd/once.c @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +void call_once(once_flag *flag, void (*func)(void)) +{ + (void)pthread_once((pthread_once_t *)flag, func); +} diff --git a/lib/libc/common/source/thrd/thrd.c b/lib/libc/common/source/thrd/thrd.c new file mode 100644 index 000000000000000..d811fe31ce6b7fc --- /dev/null +++ b/lib/libc/common/source/thrd/thrd.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include + +struct thrd_trampoline_arg { + thrd_start_t func; + void *arg; +}; + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + typedef void *(*pthread_func_t)(void *arg); + + pthread_func_t pfunc = (pthread_func_t)func; + + switch (pthread_create(thr, NULL, pfunc, arg)) { + case 0: + return thrd_success; + case EAGAIN: + return thrd_nomem; + default: + return thrd_error; + } +} + +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return pthread_equal(lhs, rhs); +} + +thrd_t thrd_current(void) +{ + return pthread_self(); +} + +int thrd_sleep(const struct timespec *duration, struct timespec *remaining) +{ + return nanosleep(duration, remaining); +} + +void thrd_yield(void) +{ + (void)sched_yield(); +} + +FUNC_NORETURN void thrd_exit(int res) +{ + pthread_exit(INT_TO_POINTER(res)); + + CODE_UNREACHABLE; +} + +int thrd_detach(thrd_t thr) +{ + switch (pthread_detach(thr)) { + case 0: + return thrd_success; + default: + return thrd_error; + } +} + +int thrd_join(thrd_t thr, int *res) +{ + void *ret; + + switch (pthread_join(thr, &ret)) { + case 0: + if (res != NULL) { + *res = POINTER_TO_INT(ret); + } + return thrd_success; + default: + return thrd_error; + } +} diff --git a/lib/libc/common/source/thrd/tss.c b/lib/libc/common/source/thrd/tss.c new file mode 100644 index 000000000000000..4b110d17170d686 --- /dev/null +++ b/lib/libc/common/source/thrd/tss.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +int tss_create(tss_t *key, tss_dtor_t destructor) +{ + switch (pthread_key_create(key, destructor)) { + case 0: + return thrd_success; + case EAGAIN: + return thrd_busy; + case ENOMEM: + return thrd_nomem; + default: + return thrd_error; + } +} + +void *tss_get(tss_t key) +{ + return pthread_getspecific(key); +} + +int tss_set(tss_t key, void *val) +{ + switch (pthread_setspecific(key, val)) { + case 0: + return thrd_success; + case ENOMEM: + return thrd_nomem; + default: + return thrd_error; + } +} + +void tss_delete(tss_t key) +{ + (void)pthread_key_delete(key); +} diff --git a/lib/libc/minimal/CMakeLists.txt b/lib/libc/minimal/CMakeLists.txt index 71a404e7870926a..abcab108e524e05 100644 --- a/lib/libc/minimal/CMakeLists.txt +++ b/lib/libc/minimal/CMakeLists.txt @@ -7,7 +7,7 @@ zephyr_library() set(GEN_DIR ${ZEPHYR_BINARY_DIR}/include/generated) set(STRERROR_TABLE_H ${GEN_DIR}/libc/minimal/strerror_table.h) -zephyr_library_cc_option(-fno-builtin) +zephyr_library_compile_options($) zephyr_library_sources( source/stdlib/atoi.c diff --git a/lib/libc/minimal/source/stdout/stdout_console.c b/lib/libc/minimal/source/stdout/stdout_console.c index 8db7528497efa89..33ea7ffaa66d82e 100644 --- a/lib/libc/minimal/source/stdout/stdout_console.c +++ b/lib/libc/minimal/source/stdout/stdout_console.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include static int _stdout_hook_default(int c) @@ -101,7 +101,7 @@ static inline size_t z_vrfy_zephyr_fwrite(const void *ZRESTRICT ptr, FILE *ZRESTRICT stream) { - Z_OOPS(Z_SYSCALL_MEMORY_ARRAY_READ(ptr, nitems, size)); + K_OOPS(K_SYSCALL_MEMORY_ARRAY_READ(ptr, nitems, size)); return z_impl_zephyr_fwrite((const void *ZRESTRICT)ptr, size, nitems, (FILE *ZRESTRICT)stream); } diff --git a/lib/libc/minimal/source/string/strerror.c b/lib/libc/minimal/source/string/strerror.c index 624e8922b7fcf96..77dfd8b477ab31e 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/CMakeLists.txt b/lib/libc/newlib/CMakeLists.txt index 856befd38110e3a..6556a3e814ce03c 100644 --- a/lib/libc/newlib/CMakeLists.txt +++ b/lib/libc/newlib/CMakeLists.txt @@ -37,39 +37,41 @@ zephyr_compile_definitions(_ANSI_SOURCE) # used by the network stack zephyr_compile_definitions(__LINUX_ERRNO_EXTENSIONS__) -# We are using -# - ${CMAKE_C_LINKER_WRAPPER_FLAG}${CMAKE_LINK_LIBRARY_FLAG}c -# - ${CMAKE_C_LINKER_WRAPPER_FLAG}${CMAKE_LINK_LIBRARY_FLAG}gcc -# - c -# in code below. -# This is needed because when linking with newlib on aarch64, then libgcc has a -# link dependency to libc (strchr), but libc also has dependencies to libgcc. -# -# CMake is capable of handling circular link dependencies for CMake defined -# static libraries, which can be further controlled using LINK_INTERFACE_MULTIPLICITY. -# However, libc and libgcc are not regular CMake libraries, and is seen as linker -# flags by CMake, and thus symbol de-duplications will be performed. -# CMake link options cannot be used, as that will place those libs first on the -# linker invocation. -Wl,--start-group is problematic as the placement of -lc -# and -lgcc is not guaranteed in case later libraries are also using -# -lc / -libbgcc as interface linker flags. -# -# Thus, we resort to use `${CMAKE_C_LINKER_WRAPPER_FLAG}${CMAKE_LINK_LIBRARY_FLAG}` -# as this ensures the uniqueness and thus avoids symbol de-duplication which means -# libc will be followed by libgcc, which is finally followed by libc again. +if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + # We are using + # - ${CMAKE_C_LINKER_WRAPPER_FLAG}${CMAKE_LINK_LIBRARY_FLAG}c + # - ${CMAKE_C_LINKER_WRAPPER_FLAG}${CMAKE_LINK_LIBRARY_FLAG}gcc + # - c + # in code below. + # This is needed because when linking with newlib on aarch64, then libgcc has a + # link dependency to libc (strchr), but libc also has dependencies to libgcc. + # + # CMake is capable of handling circular link dependencies for CMake defined + # static libraries, which can be further controlled using LINK_INTERFACE_MULTIPLICITY. + # However, libc and libgcc are not regular CMake libraries, and is seen as linker + # flags by CMake, and thus symbol de-duplications will be performed. + # CMake link options cannot be used, as that will place those libs first on the + # linker invocation. -Wl,--start-group is problematic as the placement of -lc + # and -lgcc is not guaranteed in case later libraries are also using + # -lc / -libbgcc as interface linker flags. + # + # Thus, we resort to use `${CMAKE_C_LINKER_WRAPPER_FLAG}${CMAKE_LINK_LIBRARY_FLAG}` + # as this ensures the uniqueness and thus avoids symbol de-duplication which means + # libc will be followed by libgcc, which is finally followed by libc again. -list(JOIN CMAKE_C_LINKER_WRAPPER_FLAG "" linker_wrapper_string) + list(JOIN CMAKE_C_LINKER_WRAPPER_FLAG "" linker_wrapper_string) -zephyr_link_libraries( - m - "${linker_wrapper_string}${CMAKE_LINK_LIBRARY_FLAG}c" - ${LIBC_LIBRARY_DIR_FLAG} # NB: Optional - $<$:-u_printf_float> - $<$:-u_scanf_float> - # Lib C depends on libgcc. e.g. libc.a(lib_a-fvwrite.o) references __aeabi_idiv - "${linker_wrapper_string}${CMAKE_LINK_LIBRARY_FLAG}gcc" - c - ) + zephyr_link_libraries( + m + "${linker_wrapper_string}${CMAKE_LINK_LIBRARY_FLAG}c" + ${LIBC_LIBRARY_DIR_FLAG} # NB: Optional + $<$:-u_printf_float> + $<$:-u_scanf_float> + # Lib C depends on libgcc. e.g. libc.a(lib_a-fvwrite.o) references __aeabi_idiv + "${linker_wrapper_string}${CMAKE_LINK_LIBRARY_FLAG}gcc" + ) +endif() +zephyr_link_libraries(c) if(CONFIG_NEWLIB_LIBC_NANO) zephyr_link_libraries( diff --git a/lib/libc/newlib/libc-hooks.c b/lib/libc/newlib/libc-hooks.c index 1769e32dc14053f..7e066a2817f5b3b 100644 --- a/lib/libc/newlib/libc-hooks.c +++ b/lib/libc/newlib/libc-hooks.c @@ -15,12 +15,12 @@ #include #include #include -#include +#include #include #include #include #include -#include +#include #include #define LIBC_BSS K_APP_BMEM(z_libc_partition) @@ -181,7 +181,7 @@ int z_impl_zephyr_read_stdin(char *buf, int nbytes) #ifdef CONFIG_USERSPACE static inline int z_vrfy_zephyr_read_stdin(char *buf, int nbytes) { - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(buf, nbytes)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(buf, nbytes)); return z_impl_zephyr_read_stdin((char *)buf, nbytes); } #include @@ -204,7 +204,7 @@ int z_impl_zephyr_write_stdout(const void *buffer, int nbytes) #ifdef CONFIG_USERSPACE static inline int z_vrfy_zephyr_write_stdout(const void *buf, int nbytes) { - Z_OOPS(Z_SYSCALL_MEMORY_READ(buf, nbytes)); + K_OOPS(K_SYSCALL_MEMORY_READ(buf, nbytes)); return z_impl_zephyr_write_stdout((const void *)buf, nbytes); } #include diff --git a/lib/libc/picolibc/CMakeLists.txt b/lib/libc/picolibc/CMakeLists.txt index 3bbe8128a1f54de..23e84231e2a07e3 100644 --- a/lib/libc/picolibc/CMakeLists.txt +++ b/lib/libc/picolibc/CMakeLists.txt @@ -9,14 +9,21 @@ 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) zephyr_link_libraries(-DPICOLIBC_DOUBLE_PRINTF_SCANF) + elseif(CONFIG_PICOLIBC_IO_MINIMAL) + zephyr_compile_definitions(PICOLIBC_MINIMAL_PRINTF_SCANF) + zephyr_link_libraries(-DPICOLIBC_MINIMAL_PRINTF_SCANF) + elseif(CONFIG_PICOLIBC_IO_LONG_LONG) + zephyr_compile_definitions(PICOLIBC_LONG_LONG_PRINTF_SCANF) + zephyr_link_libraries(-DPICOLIBC_LONG_LONG_PRINTF_SCANF) else() zephyr_compile_definitions(PICOLIBC_INTEGER_PRINTF_SCANF) zephyr_link_libraries(-DPICOLIBC_INTEGER_PRINTF_SCANF) diff --git a/lib/libc/picolibc/Kconfig b/lib/libc/picolibc/Kconfig index b5e1f1bb58101ad..fa6ae7e6e9ba592 100644 --- a/lib/libc/picolibc/Kconfig +++ b/lib/libc/picolibc/Kconfig @@ -13,6 +13,12 @@ config PICOLIBC_USE_MODULE This is enabled by default for toolchains other than the Zephyr SDK. +# force TLS when using toolchain with TLS support +config PICOLIBC_USE_TOOLCHAIN + bool + default y if PICOLIBC && !PICOLIBC_USE_MODULE + select THREAD_LOCAL_STORAGE if ARCH_HAS_THREAD_LOCAL_STORAGE && TOOLCHAIN_SUPPORTS_THREAD_LOCAL_STORAGE + config PICOLIBC_HEAP_SIZE int "[DEPRECATED] Picolibc heap size (bytes)" default -2 @@ -25,16 +31,42 @@ config PICOLIBC_HEAP_SIZE If set to -2, then the value of COMMON_LIBC_MALLOC_ARENA_SIZE will be used. -config PICOLIBC_IO_LONG_LONG - bool "support for long long in integer-only printf/scanf" +choice PICOLIBC_IO_LEVEL + prompt "Picolibc printf/scanf level" + default PICOLIBC_IO_MINIMAL if CBPRINTF_NANO + default PICOLIBC_IO_LONG_LONG if CBPRINTF_FULL_INTEGRAL + default PICOLIBC_IO_INTEGER help - Includes support for long long in integer-only printf/scanf. long long - types are always supported in the floating-point versions. + Selects the level of printf and scanf support config PICOLIBC_IO_FLOAT - bool "support for floating point values in printf/scanf" + bool "full support for integer/floating point values in printf/scanf" + help + Include full floating point and integer support in printf/scanf + functions. + +config PICOLIBC_IO_LONG_LONG + bool "full support for integer values, including long long, in printf/scanf" + depends on !REQUIRES_FLOAT_PRINTF && (!CBPRINTF_FP_SUPPORT || CBPRINTF_NANO) + help + Includes full integer with long long, but no floating + point in printf/scanf. + +config PICOLIBC_IO_INTEGER + bool "full support for integer values, other than long long, in printf/scanf" + depends on !REQUIRES_FLOAT_PRINTF && ((!CBPRINTF_FP_SUPPORT && !CBPRINTF_FULL_INTEGRAL) || CBPRINTF_NANO) + help + Include full integer other than long long, but no floating point + in printf/scanf. + +config PICOLIBC_IO_MINIMAL + bool "limited support for integer values in printf/scanf" + depends on !REQUIRES_FLOAT_PRINTF && CBPRINTF_NANO help - Include floating point support in printf/scanf functions. + Include limited integer and no floating point support in + printf/scanf. + +endchoice if PICOLIBC_USE_MODULE @@ -82,21 +114,31 @@ config PICOLIBC_FAST_STRCMP This provides a faster strcmp version even when libc is built in space-optimized mode +config PICOLIBC_ASSERT_VERBOSE + bool "assert provides verbose information" + help + The usual picolibc assert helper, __assert_func, takes file, line, + function and expression information to make the presented message + more helpful. These all require storage in the image. Unselecting + this option eliminates all of that information, making the results + less helpful but also making them consume less memory. + config PICOLIBC_IO_C99_FORMATS bool "support C99 format additions in printf/scanf" default y help - Includes support for hex floats (in floating-point version) and j, z, - t size modifiers. + Includes C99 printf and scanf support for j, z, t size + modifiers. C99 support is always included in the floating-point + variant config PICOLIBC_IO_POS_ARGS bool "Support POSIX positional args (e.g. %$1d) in printf/scanf" default y - depends on !PICOLIBC_IO_FLOAT + depends on !PICOLIBC_IO_MINIMAL help - Includes support for positional args (e.g. $1) in integer-only printf - and scanf. Positional args are always supported in the floating-point - versions. + Includes support for positional args (e.g. $1) in integer-only + printf and scanf. Positional args are always supported in the + floating-point variant. config PICOLIBC_IO_FLOAT_EXACT bool "support for exact float/string conversion" @@ -106,6 +148,21 @@ config PICOLIBC_IO_FLOAT_EXACT This ensures that printf values with enough digits can be fed to scanf and generate exactly the same binary value. +config PICOLIBC_IO_SMALL_ULTOA + bool "avoid soft division in printf" + default y + help + Replaces division and modulus by 10 with shifts and adds when + doing binary to decimal conversion in printf for 64-bit + values on 32-bit targets. + +config PICOLIBC_IO_MINIMAL_LONG_LONG + bool "Include long long support in minimal printf" + depends on PICOLIBC_IO_MINIMAL + default y if CBPRINTF_FULL_INTEGRAL + help + Include long long support in the minimal picolibc printf code + config PICOLIBC_LOCALE_INFO bool "support locales in libc functions" help diff --git a/lib/libc/picolibc/libc-hooks.c b/lib/libc/picolibc/libc-hooks.c index 8df622c492cc90d..e7539bc5dfe1111 100644 --- a/lib/libc/picolibc/libc-hooks.c +++ b/lib/libc/picolibc/libc-hooks.c @@ -14,13 +14,13 @@ #include #include #include -#include +#include #include #include #include #include #ifdef CONFIG_MMU -#include +#include #endif #define LIBC_BSS K_APP_BMEM(z_libc_partition) @@ -206,6 +206,27 @@ void __retarget_lock_release(_LOCK_T lock) #endif /* CONFIG_MULTITHREADING */ +#ifdef CONFIG_PICOLIBC_ASSERT_VERBOSE + +FUNC_NORETURN void __assert_func(const char *file, int line, + const char *function, const char *expression) +{ + __ASSERT(0, "assertion \"%s\" failed: file \"%s\", line %d%s%s\n", + expression, file, line, + function ? ", function: " : "", function ? function : ""); + CODE_UNREACHABLE; +} + +#else + +FUNC_NORETURN void __assert_no_args(void) +{ + __ASSERT_NO_MSG(0); + CODE_UNREACHABLE; +} + +#endif + /* This function gets called if static buffer overflow detection is enabled on * stdlib side (Picolibc here), in case such an overflow is detected. Picolibc * provides an implementation not suitable for us, so we override it here. diff --git a/lib/mem_blocks/CMakeLists.txt b/lib/mem_blocks/CMakeLists.txt new file mode 100644 index 000000000000000..9bf33924172642b --- /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 000000000000000..ea04f8be97beff0 --- /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 4f082716c487c15..3a52bebab04b835 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 e6b25ade5a5304c..14b6241b72c9359 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.cbprintf b/lib/os/Kconfig.cbprintf index 0e4984b155944b4..54ba8ccfa502bb8 100644 --- a/lib/os/Kconfig.cbprintf +++ b/lib/os/Kconfig.cbprintf @@ -31,7 +31,7 @@ choice CBPRINTF_INTEGRAL_CONV # 01: 0% / 0 B (01 / 00) config CBPRINTF_FULL_INTEGRAL bool "Convert the full range of integer values" - select PICOLIBC_IO_LONG_LONG if PICOLIBC + select PICOLIBC_IO_MINIMAL_LONG_LONG if PICOLIBC_IO_MINIMAL && PICOLIBC_USE_MODULE help Build cbprintf with buffers sized to support converting the full range of all integral and pointer values. @@ -67,7 +67,6 @@ config CBPRINTF_FP_SUPPORT bool "Floating point formatting in cbprintf" default y if FPU depends on CBPRINTF_COMPLETE - select PICOLIBC_IO_FLOAT if PICOLIBC help Build the cbprintf utility function with support for floating point format specifiers. Selecting this increases stack size @@ -90,6 +89,7 @@ config CBPRINTF_FP_A_SUPPORT config CBPRINTF_FP_ALWAYS_A bool "Select %a format for all floating point specifications" select CBPRINTF_FP_A_SUPPORT + depends on !PICOLIBC help The %a format for floats requires significantly less code than the standard decimal representations (%f, %e, %g). Selecting this @@ -103,10 +103,12 @@ config CBPRINTF_FP_ALWAYS_A config CBPRINTF_N_SPECIFIER bool "Support %n specifications" depends on CBPRINTF_COMPLETE + depends on !PICOLIBC default y help If selected %n can be used to determine the number of characters emitted. If enabled there is a small increase in code size. + Picolibc does not support this feature for security reasons. # 180: 18% / 138 B (180 / 80) [NANO] config CBPRINTF_LIBC_SUBSTS @@ -120,6 +122,9 @@ config CBPRINTF_LIBC_SUBSTS When used with CBPRINTF_NANO this increases the implementation code size by a small amount. + When used with picolibc, this option generates cbprintf-compatible + functions using stdio, effectively inverting the sense above. + module = CBPRINTF_PACKAGE module-str = cbprintf_package source "subsys/logging/Kconfig.template.log_config" @@ -159,3 +164,11 @@ config CBPRINTF_PACKAGE_SUPPORT_TAGGED_ARGUMENTS to determine the types of arguments, but instead, each argument is tagged with a type by preceding it with another argument as type (integer). + +config CBPRINTF_CONVERT_CHECK_PTR + bool + default y if !LOG_FMT_SECTION_STRIP + help + If enabled, cbprintf_package_convert() supports checking if string + candidate is used for %p format specifier. Check cannot be performed + if string is not present in the memory. diff --git a/lib/os/Kconfig.heap b/lib/os/Kconfig.heap deleted file mode 100644 index b913d6100dcd3fd..000000000000000 --- 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) - 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/assert.c b/lib/os/assert.c index b6a33ae732024d1..1fee487bff64ebc 100644 --- a/lib/os/assert.c +++ b/lib/os/assert.c @@ -7,7 +7,7 @@ #include #include #include - +#include /** * @brief Assert Action Handler @@ -42,6 +42,7 @@ __weak void assert_post_action(const char *file, unsigned int line) k_panic(); } +EXPORT_SYMBOL(assert_post_action); void assert_print(const char *fmt, ...) { @@ -53,3 +54,4 @@ void assert_print(const char *fmt, ...) va_end(ap); } +EXPORT_SYMBOL(assert_print); diff --git a/lib/os/cbprintf_packaged.c b/lib/os/cbprintf_packaged.c index 58076e9320aa561..1c208c42e67a180 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 & @@ -999,7 +997,8 @@ int cbprintf_package_convert(void *in_packaged, bool is_ro = ptr_in_rodata(str); int len; - if (fmt_present && is_ptr(fmt, arg_idx)) { + if (IS_ENABLED(CONFIG_CBPRINTF_CONVERT_CHECK_PTR) && + fmt_present && is_ptr(fmt, arg_idx)) { LOG_WRN("(unsigned) char * used for %%p argument. " "It's recommended to cast it to void * because " "it may cause misbehavior in certain " @@ -1077,7 +1076,8 @@ int cbprintf_package_convert(void *in_packaged, const char *str = *(const char **)&buf32[arg_pos]; bool is_ro = ptr_in_rodata(str); - if (fmt_present && is_ptr(fmt, arg_idx)) { + if (IS_ENABLED(CONFIG_CBPRINTF_CONVERT_CHECK_PTR) && + fmt_present && is_ptr(fmt, arg_idx)) { continue; } diff --git a/lib/os/fdtable.c b/lib/os/fdtable.c index b261c958de2f763..757ebf4361fdcb7 100644 --- a/lib/os/fdtable.c +++ b/lib/os/fdtable.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include struct fd_entry { @@ -263,7 +263,7 @@ void z_finalize_fd(int fd, void *obj, const struct fd_op_vtable *vtable) * This call is a no-op if obj is invalid or points to something * not a kernel object. */ - z_object_recycle(obj); + k_object_recycle(obj); #endif fdtable[fd].obj = obj; fdtable[fd].vtable = vtable; diff --git a/lib/os/heap-validate.c b/lib/os/heap-validate.c deleted file mode 100644 index 18aafe71804583d..000000000000000 --- 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/mutex.c b/lib/os/mutex.c index 3cd84612a228d03..e1c6d7fb48f126c 100644 --- a/lib/os/mutex.c +++ b/lib/os/mutex.c @@ -6,14 +6,14 @@ #include #include -#include +#include #include static struct k_mutex *get_k_mutex(struct sys_mutex *mutex) { - struct z_object *obj; + struct k_object *obj; - obj = z_object_find(mutex); + obj = k_object_find(mutex); if (obj == NULL || obj->type != K_OBJ_SYS_MUTEX) { return NULL; } @@ -27,7 +27,7 @@ static bool check_sys_mutex_addr(struct sys_mutex *addr) * underlying k_mutex, but we don't want threads using mutexes * that are outside their memory domain */ - return Z_SYSCALL_MEMORY_WRITE(addr, sizeof(struct sys_mutex)); + return K_SYSCALL_MEMORY_WRITE(addr, sizeof(struct sys_mutex)); } int z_impl_z_sys_mutex_kernel_lock(struct sys_mutex *mutex, k_timeout_t timeout) diff --git a/lib/os/printk.c b/lib/os/printk.c index 0701f8a3a6feadf..ac19e9e38fcf515 100644 --- a/lib/os/printk.c +++ b/lib/os/printk.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -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) { @@ -174,7 +175,7 @@ void z_impl_k_str_out(char *c, size_t n) #ifdef CONFIG_USERSPACE static inline void z_vrfy_k_str_out(char *c, size_t n) { - Z_OOPS(Z_SYSCALL_MEMORY_READ(c, n)); + K_OOPS(K_SYSCALL_MEMORY_READ(c, n)); z_impl_k_str_out((char *)c, n); } #include diff --git a/lib/os/sem.c b/lib/os/sem.c index 132a0c834a825d0..b01ead58e507e1d 100644 --- a/lib/os/sem.c +++ b/lib/os/sem.c @@ -5,7 +5,7 @@ */ #include -#include +#include #ifdef CONFIG_USERSPACE #define SYS_SEM_MINIMUM 0 diff --git a/lib/os/thread_entry.c b/lib/os/thread_entry.c index 89eb2fe7b4b32f5..ed6ca142d99f7cd 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 c6b3a88aeab4a9c..c8d836f584641f3 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -3,7 +3,7 @@ set(GEN_DIR ${ZEPHYR_BINARY_DIR}/include/generated) zephyr_syscall_header( - ${ZEPHYR_BASE}/include/zephyr/posix/time.h + posix_clock.h ) zephyr_interface_library_named(posix_subsys) @@ -36,13 +36,13 @@ endif() zephyr_library() add_subdirectory_ifdef(CONFIG_GETOPT getopt) +add_subdirectory_ifdef(CONFIG_SHELL shell) 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}) @@ -53,10 +53,12 @@ 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_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_sources_ifdef(CONFIG_POSIX_PUTMSG stropts.c) zephyr_library_include_directories( ${ZEPHYR_BASE}/kernel/include diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index 199ed956af25033..b2f379be8d15b41 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -3,8 +3,11 @@ # # SPDX-License-Identifier: Apache-2.0 +menu "POSIX API Support" + 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 @@ -36,6 +39,23 @@ config PTHREAD_IPC the pthread mutex, condition variable and barrier IPC mechanisms. +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. + source "lib/posix/Kconfig.barrier" source "lib/posix/Kconfig.clock" source "lib/posix/Kconfig.cond" @@ -48,8 +68,15 @@ source "lib/posix/Kconfig.limits" source "lib/posix/Kconfig.mqueue" source "lib/posix/Kconfig.mutex" source "lib/posix/Kconfig.pthread" +source "lib/posix/Kconfig.rwlock" +source "lib/posix/Kconfig.sched" 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" +source "lib/posix/Kconfig.stropts" + +rsource "shell/Kconfig" + +endmenu # "POSIX API Support" diff --git a/lib/posix/Kconfig.clock b/lib/posix/Kconfig.clock index d9767bb391040c6..e306e691b44a45b 100644 --- a/lib/posix/Kconfig.clock +++ b/lib/posix/Kconfig.clock @@ -3,8 +3,9 @@ # SPDX-License-Identifier: Apache-2.0 config POSIX_CLOCK - bool "POSIX clock, timer, and sleep APIs" + bool "POSIX clock and sleep APIs" default y if POSIX_API + imply TIMER + depends on !NATIVE_LIBC help - This enables POSIX clock\_\*(), timer\_\*(), and \*sleep() - functions. + This enables POSIX clock\_\*() and \*sleep() functions. diff --git a/lib/posix/Kconfig.mqueue b/lib/posix/Kconfig.mqueue index 58e04d21fafb50a..7c49aee6c2198d7 100644 --- a/lib/posix/Kconfig.mqueue +++ b/lib/posix/Kconfig.mqueue @@ -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.pthread b/lib/posix/Kconfig.pthread index 388a30c5fa40d7b..8870b7251097d68 100644 --- a/lib/posix/Kconfig.pthread +++ b/lib/posix/Kconfig.pthread @@ -27,4 +27,36 @@ config PTHREAD_RECYCLER_DELAY_MS 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/Kconfig.rwlock b/lib/posix/Kconfig.rwlock new file mode 100644 index 000000000000000..6bd89a0a9f510c8 --- /dev/null +++ b/lib/posix/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 +source "lib/posix/Kconfig.template.pooled_ipc_type" diff --git a/lib/posix/Kconfig.sched b/lib/posix/Kconfig.sched new file mode 100644 index 000000000000000..62e7541c8e1f212 --- /dev/null +++ b/lib/posix/Kconfig.sched @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +config POSIX_PRIORITY_SCHEDULING + bool "_POSIX_PRIORITY_SCHEDULING API support" + 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/Kconfig.semaphore b/lib/posix/Kconfig.semaphore index d9b9b47a5089f8f..aa3468fea763191 100644 --- a/lib/posix/Kconfig.semaphore +++ b/lib/posix/Kconfig.semaphore @@ -8,3 +8,11 @@ config SEM_VALUE_MAX 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}. diff --git a/lib/posix/Kconfig.signal b/lib/posix/Kconfig.signal index c51e68f1f36a49b..1df8cf3ab166e3d 100644 --- a/lib/posix/Kconfig.signal +++ b/lib/posix/Kconfig.signal @@ -9,12 +9,6 @@ config POSIX_SIGNAL 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" @@ -24,3 +18,12 @@ config POSIX_SIGNAL_STRING_DESC Will use 256 bytes of ROM. endif + +# 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)] diff --git a/lib/posix/Kconfig.stropts b/lib/posix/Kconfig.stropts new file mode 100644 index 000000000000000..347f0f33c150af3 --- /dev/null +++ b/lib/posix/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/clock.c b/lib/posix/clock.c index 51812ed53bc65e1..a8835a44248471a 100644 --- a/lib/posix/clock.c +++ b/lib/posix/clock.c @@ -3,11 +3,15 @@ * * SPDX-License-Identifier: Apache-2.0 */ + +#include "posix_clock.h" + #include #include #include #include -#include +#include +#include #include /* @@ -25,10 +29,40 @@ static struct k_spinlock rt_clock_base_lock; * * See IEEE 1003.1 */ -int z_impl_clock_gettime(clockid_t clock_id, struct timespec *ts) +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; - k_spinlock_key_t key; switch (clock_id) { case CLOCK_MONOTONIC: @@ -37,9 +71,7 @@ int z_impl_clock_gettime(clockid_t clock_id, struct timespec *ts) break; case CLOCK_REALTIME: - key = k_spin_lock(&rt_clock_base_lock); - base = rt_clock_base; - k_spin_unlock(&rt_clock_base_lock, key); + (void)__posix_clock_get_base(clock_id, &base); break; default: @@ -65,15 +97,6 @@ int z_impl_clock_gettime(clockid_t clock_id, struct timespec *ts) return 0; } -#ifdef CONFIG_USERSPACE -int z_vrfy_clock_gettime(clockid_t clock_id, struct timespec *ts) -{ - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(ts, sizeof(*ts))); - return z_impl_clock_gettime(clock_id, ts); -} -#include -#endif - /** * @brief Set the time of the specified clock. * @@ -92,6 +115,11 @@ int clock_settime(clockid_t clock_id, const struct timespec *tp) 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; @@ -195,3 +223,35 @@ int gettimeofday(struct timeval *tv, void *tz) 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/fnmatch.c b/lib/posix/fnmatch.c index 338891fd9b37007..b52858513598f39 100644 --- a/lib/posix/fnmatch.c +++ b/lib/posix/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/getopt/getopt.c b/lib/posix/getopt/getopt.c index 514af721cb525fb..c17a0ff04c238b7 100644 --- a/lib/posix/getopt/getopt.c +++ b/lib/posix/getopt/getopt.c @@ -30,7 +30,7 @@ */ #include -#ifdef CONFIG_ARCH_POSIX +#ifdef CONFIG_NATIVE_LIBC #include #else #include diff --git a/lib/posix/key.c b/lib/posix/key.c index 03d03eed84a3a56..20237f36712fa2e 100644 --- a/lib/posix/key.c +++ b/lib/posix/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/mqueue.c index 5c3d5e5e5d9a017..042b40910a8a202 100644 --- a/lib/posix/mqueue.c +++ b/lib/posix/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/posix_clock.h b/lib/posix/posix_clock.h new file mode 100644 index 000000000000000..a665f4ce06d90ec --- /dev/null +++ b/lib/posix/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/posix_internal.h b/lib/posix/posix_internal.h index 39c64c53331c158..17d8c29d43852ec 100644 --- a/lib/posix/posix_internal.h +++ b/lib/posix/posix_internal.h @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -21,27 +22,43 @@ */ #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; - /* Dynamic stack */ - k_thread_stack_t *dynamic_stack; + /* pthread_attr_t */ + struct posix_thread_attr attr; /* Exit status */ void *retval; - /* Pthread cancellation */ - uint8_t cancel_state; - bool cancel_pending; - - /* Detach state */ - uint8_t detachstate; + /* Signal mask */ + sigset_t sigset; /* Queue ID (internal-only) */ uint8_t qid; @@ -85,4 +102,7 @@ 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/pthread.c b/lib/posix/pthread.c index 7377f2b133dfc7e..c4a1e490a338ba6 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -15,7 +15,23 @@ #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); @@ -25,8 +41,21 @@ LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); #define DYNAMIC_STACK_SIZE 0 #endif -#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE -#define PTHREAD_CANCELED ((void *) -1) +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() */ @@ -35,37 +64,59 @@ enum posix_thread_qid { 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 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 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 K_MUTEX_DEFINE(pthread_once_lock); +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 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, -}; +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 @@ -87,7 +138,6 @@ static inline size_t get_posix_thread_idx(pthread_t 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); @@ -105,16 +155,14 @@ struct posix_thread *to_posix_thread(pthread_t pthread) 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); + 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); @@ -135,49 +183,148 @@ pthread_t pthread_self(void) return mark_pthread_obj_initialized(bit); } -static bool is_posix_policy_prio_valid(uint32_t priority, int policy) +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 piority %d and / or policy %d", priority, policy); + LOG_ERR("Invalid priority %d and / or policy %d", priority, policy); return false; } -static uint32_t zephyr_to_posix_priority(int32_t z_prio, int *policy) +/* Non-static so that they can be tested in ztest */ +int zephyr_to_posix_priority(int z_prio, int *policy) { - uint32_t prio; + int priority; if (z_prio < 0) { - *policy = SCHED_FIFO; - prio = -1 * (z_prio + 1); - __ASSERT_NO_MSG(prio < CONFIG_NUM_COOP_PRIORITIES); + __ASSERT_NO_MSG(-z_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); + __ASSERT_NO_MSG(z_prio < CONFIG_NUM_PREEMPT_PRIORITIES); } - return prio; + *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; } -static int32_t posix_to_zephyr_priority(uint32_t priority, int policy) +/* Non-static so that they can be tested in ztest */ +int posix_to_zephyr_priority(int priority, int policy) { - int32_t prio; + __ASSERT_NO_MSG(is_posix_policy_prio_valid(priority, policy)); - 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 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 prio; + return true; } /** @@ -187,16 +334,15 @@ static int32_t posix_to_zephyr_priority(uint32_t priority, int policy) */ 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; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U) || - (is_posix_policy_prio_valid(priority, attr->schedpolicy) == false)) { + 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 = priority; + attr->priority = schedparam->sched_priority; return 0; } @@ -207,51 +353,35 @@ int pthread_attr_setschedparam(pthread_attr_t *_attr, const struct sched_param * */ int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksize) { - struct pthread_attr *attr = (struct pthread_attr *)_attr; + int ret; + struct posix_thread_attr *attr = (struct posix_thread_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; + if (!__attr_is_initialized(attr) || stacksize == 0 || stacksize < PTHREAD_STACK_MIN || + stacksize > PTHREAD_STACK_MAX) { + LOG_ERR("Invalid stacksize %zu", stacksize); + return EINVAL; } - /* require a valid scheduler policy */ - if (!valid_posix_policy(attr->schedpolicy)) { - LOG_ERR("Invalid scheduler policy %d", attr->schedpolicy); - return false; + 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); + } } - /* require a valid detachstate */ - if (!(attr->detachstate == PTHREAD_CREATE_JOINABLE || - attr->detachstate == PTHREAD_CREATE_DETACHED)) { - LOG_ERR("Invalid detachstate %d", attr->detachstate); - return false; - } + attr->stack = stackaddr; + __set_attr_stacksize(attr, stacksize); - /* 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; - } + LOG_DBG("Assigned thread stack %zu@%p to attr %p", __get_attr_stacksize(attr), attr->stack, + _attr); - return true; + return 0; } static void posix_thread_recycle_work_handler(struct k_work *work) @@ -281,8 +411,7 @@ static void posix_thread_finalize(struct posix_thread *t, void *retval) /* 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; + posix_thread_q_set(t, POSIX_THREAD_DONE_Q); t->retval = retval; k_spin_unlock(&pthread_pool_lock, key); @@ -321,8 +450,8 @@ static void posix_thread_recycle(void) 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) { + 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; } @@ -338,19 +467,18 @@ static void posix_thread_recycle(void) 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; - } + 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)) { - sys_dlist_append(&ready_q, sys_dlist_get(&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); } @@ -367,49 +495,39 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou 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)) { + if (!(_attr == NULL || __attr_is_runnable((struct posix_thread_attr *)_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; + 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; } - 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 */ @@ -417,31 +535,33 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou return EAGAIN; } - if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { - err = pthread_barrier_init(&barrier, NULL, 2); + 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) { - if (t->dynamic_stack != NULL) { - LOG_DBG("freeing thread stack at %p", attr->stack); - (void)k_thread_stack_free(attr->stack); + /* 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); } - - /* 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; + 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, 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)); + 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 */ @@ -459,6 +579,34 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou 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. * @@ -466,27 +614,34 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou */ int pthread_setcancelstate(int state, int *oldstate) { - bool cancel_pending; - k_spinlock_key_t key; + 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; } - t = to_posix_thread(pthread_self()); - if (t == NULL) { - return EINVAL; - } + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread_self()); + if (t == NULL) { + ret = EINVAL; + K_SPINLOCK_BREAK; + } - 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 (oldstate != NULL) { + *oldstate = t->attr.cancelstate; + } - if (state == PTHREAD_CANCEL_ENABLE && cancel_pending) { + 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); } @@ -494,31 +649,72 @@ int pthread_setcancelstate(int state, int *oldstate) } /** - * @brief Cancel execution of a thread. + * @brief Set cancelability Type. * * See IEEE 1003.1 */ -int pthread_cancel(pthread_t pthread) +int pthread_setcanceltype(int type, int *oldtype) { - int cancel_state; - k_spinlock_key_t key; + int ret = 0; struct posix_thread *t; - t = to_posix_thread(pthread); - if (t == NULL) { - return ESRCH; + if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS) { + LOG_ERR("Invalid pthread cancel type %d", type); + return EINVAL; } - key = k_spin_lock(&pthread_pool_lock); - t->cancel_pending = true; - cancel_state = t->cancel_state; - k_spin_unlock(&pthread_pool_lock, key); + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread_self()); + if (t == NULL) { + ret = EINVAL; + K_SPINLOCK_BREAK; + } - if (cancel_state == PTHREAD_CANCEL_ENABLE) { + if (oldtype != NULL) { + *oldtype = t->attr.canceltype; + } + t->attr.canceltype = type; + } + + return ret; +} + +/** + * @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 0; + return ret; } /** @@ -528,26 +724,30 @@ int pthread_cancel(pthread_t pthread) */ 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; - } + int ret = 0; + int new_prio = K_LOWEST_APPLICATION_THREAD_PRIO; + struct posix_thread *t = NULL; - if (!valid_posix_policy(policy)) { - LOG_ERR("Invalid scheduler policy %d", policy); + if (param == NULL || !valid_posix_policy(policy) || + !is_posix_policy_prio_valid(param->sched_priority, policy)) { return EINVAL; } - if (is_posix_policy_prio_valid(param->sched_priority, policy) == false) { - 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); } - new_prio = posix_to_zephyr_priority(param->sched_priority, policy); + if (ret == 0) { + k_thread_priority_set(&t->thread, new_prio); + } - k_thread_priority_set(&t->thread, new_prio); - return 0; + return ret; } /** @@ -555,15 +755,37 @@ int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_para * * See IEEE 1003.1 */ -int pthread_attr_init(pthread_attr_t *attr) +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; } - (void)memcpy(attr, &init_pthread_attrs, sizeof(pthread_attr_t)); + 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; } @@ -575,18 +797,30 @@ int pthread_attr_init(pthread_attr_t *attr) */ int pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *param) { - uint32_t priority; + int ret = 0; struct posix_thread *t; - t = to_posix_thread(pthread); - if (t == NULL) { - return ESRCH; + if (policy == NULL || param == NULL) { + return EINVAL; } - priority = k_thread_priority_get(&t->thread); + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread); + if (t == NULL) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } - param->sched_priority = zephyr_to_posix_priority(priority, policy); - return 0; + 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; } /** @@ -597,17 +831,23 @@ int pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *pa 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; - ret = k_mutex_lock(&pthread_once_lock, K_FOREVER); - __ASSERT_NO_MSG(ret == 0); + if (init_func == NULL) { + return EINVAL; + } - if (once->is_initialized != 0 && once->init_executed == 0) { - init_func(); - once->init_executed = 1; + K_SPINLOCK(&pthread_pool_lock) { + if (!_once->flag) { + run_init_func = true; + _once->flag = true; + } } - ret = k_mutex_unlock(&pthread_once_lock); - __ASSERT_NO_MSG(ret == 0); + if (run_init_func) { + init_func(); + } return 0; } @@ -620,20 +860,25 @@ int pthread_once(pthread_once_t *once, void (*init_func)(void)) FUNC_NORETURN void pthread_exit(void *retval) { - k_spinlock_key_t key; - struct posix_thread *self; + 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; + } - 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()); - } - /* 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); + CODE_UNREACHABLE; + } posix_thread_finalize(self, retval); CODE_UNREACHABLE; @@ -646,31 +891,30 @@ void pthread_exit(void *retval) */ int pthread_join(pthread_t pthread, void **status) { - struct posix_thread *t; - int ret; + int ret = 0; + struct posix_thread *t = NULL; 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; - } + 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); + LOG_DBG("Pthread %p joining..", &t->thread); - ret = 0; - K_SPINLOCK(&pthread_pool_lock) - { - if (t->detachstate != PTHREAD_CREATE_JOINABLE) { + if (t->attr.detachstate != PTHREAD_CREATE_JOINABLE) { + /* undefined behaviour */ 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 */ + if (posix_thread_q_get(t) == POSIX_THREAD_READY_Q) { ret = ESRCH; K_SPINLOCK_BREAK; } @@ -679,7 +923,7 @@ int pthread_join(pthread_t pthread, void **status) * 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; + t->attr.detachstate = PTHREAD_CREATE_DETACHED; } switch (ret) { @@ -716,26 +960,25 @@ int pthread_join(pthread_t pthread, void **status) */ int pthread_detach(pthread_t pthread) { - int ret; - k_spinlock_key_t key; + int ret = 0; struct posix_thread *t; - enum posix_thread_qid qid; - t = to_posix_thread(pthread); - if (t == NULL) { - return ESRCH; - } + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread); + if (t == NULL) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } - 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; + 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; } - k_spin_unlock(&pthread_pool_lock, key); if (ret == 0) { LOG_DBG("Pthread %p detached", &t->thread); @@ -751,9 +994,9 @@ int pthread_detach(pthread_t pthread) */ int pthread_attr_getdetachstate(const pthread_attr_t *_attr, int *detachstate) { - const struct pthread_attr *attr = (const struct pthread_attr *)_attr; + const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if (!__attr_is_initialized(attr) || (detachstate == NULL)) { return EINVAL; } @@ -768,10 +1011,10 @@ int pthread_attr_getdetachstate(const pthread_attr_t *_attr, int *detachstate) */ int pthread_attr_setdetachstate(pthread_attr_t *_attr, int detachstate) { - struct pthread_attr *attr = (struct pthread_attr *)_attr; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U) || - (detachstate != PTHREAD_CREATE_DETACHED && detachstate != PTHREAD_CREATE_JOINABLE)) { + if (!__attr_is_initialized(attr) || ((detachstate != PTHREAD_CREATE_DETACHED) && + (detachstate != PTHREAD_CREATE_JOINABLE))) { return EINVAL; } @@ -786,9 +1029,9 @@ int pthread_attr_setdetachstate(pthread_attr_t *_attr, int detachstate) */ int pthread_attr_getschedpolicy(const pthread_attr_t *_attr, int *policy) { - const struct pthread_attr *attr = (const struct pthread_attr *)_attr; + const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if (!__attr_is_initialized(attr) || (policy == NULL)) { return EINVAL; } @@ -803,9 +1046,9 @@ int pthread_attr_getschedpolicy(const pthread_attr_t *_attr, int *policy) */ int pthread_attr_setschedpolicy(pthread_attr_t *_attr, int policy) { - struct pthread_attr *attr = (struct pthread_attr *)_attr; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U) || !valid_posix_policy(policy)) { + if (!__attr_is_initialized(attr) || !valid_posix_policy(policy)) { return EINVAL; } @@ -820,13 +1063,13 @@ int pthread_attr_setschedpolicy(pthread_attr_t *_attr, int policy) */ int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize) { - const struct pthread_attr *attr = (const struct pthread_attr *)_attr; + const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if (!__attr_is_initialized(attr) || (stacksize == NULL)) { return EINVAL; } - *stacksize = attr->stacksize; + *stacksize = __get_attr_stacksize(attr); return 0; } @@ -837,17 +1080,44 @@ int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize) */ int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t stacksize) { - struct pthread_attr *attr = (struct pthread_attr *)_attr; + int ret; + void *new_stack; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if (!__attr_is_initialized(attr) || stacksize == 0 || stacksize < PTHREAD_STACK_MIN || + stacksize > PTHREAD_STACK_MAX) { return EINVAL; } - if (stacksize < PTHREAD_STACK_MIN) { - 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); + } } - attr->stacksize = stacksize; + __set_attr_stacksize(attr, stacksize); + attr->stack = new_stack; + return 0; } @@ -858,14 +1128,40 @@ int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t stacksize) */ int pthread_attr_getstack(const pthread_attr_t *_attr, void **stackaddr, size_t *stacksize) { - const struct pthread_attr *attr = (const struct pthread_attr *)_attr; + const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if (!__attr_is_initialized(attr) || (stackaddr == NULL) || (stacksize == NULL)) { return EINVAL; } *stackaddr = attr->stack; - *stacksize = attr->stacksize; + *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; } @@ -876,9 +1172,9 @@ int pthread_attr_getstack(const pthread_attr_t *_attr, void **stackaddr, size_t */ int pthread_attr_getschedparam(const pthread_attr_t *_attr, struct sched_param *schedparam) { - struct pthread_attr *attr = (struct pthread_attr *)_attr; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if (!__attr_is_initialized(attr) || (schedparam == NULL)) { return EINVAL; } @@ -893,14 +1189,23 @@ int pthread_attr_getschedparam(const pthread_attr_t *_attr, struct sched_param * */ int pthread_attr_destroy(pthread_attr_t *_attr) { - struct pthread_attr *attr = (struct pthread_attr *)_attr; + int ret; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; - if ((attr != NULL) && (attr->initialized != 0U)) { - attr->initialized = false; - return 0; + if (!__attr_is_initialized(attr)) { + return EINVAL; } - 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) @@ -952,20 +1257,68 @@ int pthread_getname_np(pthread_t thread, char *name, size_t len) #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) { - sys_dlist_append(&ready_q, &posix_thread_pool[i].q_node); + posix_thread_q_set(&posix_thread_pool[i], POSIX_THREAD_READY_Q); } 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 index 60039fb088a0422..a380b5d5693dab8 100644 --- a/lib/posix/rwlock.c +++ b/lib/posix/rwlock.c @@ -3,19 +3,102 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include -#include -#include -#include -#define INITIALIZED 1 -#define NOT_INITIALIZED 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(pthread_rwlock_t *rwlock, int32_t timeout); -static uint32_t write_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout); +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. @@ -25,12 +108,23 @@ static uint32_t write_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout); 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; + 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; } @@ -41,20 +135,28 @@ int pthread_rwlock_init(pthread_rwlock_t *rwlock, */ int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) { - if (rwlock->status == NOT_INITIALIZED) { + int ret = 0; + int err; + size_t bit; + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { return EINVAL; } - if (rwlock->wr_owner != NULL) { - return EBUSY; - } + K_SPINLOCK(&posix_rwlock_spinlock) { + if (rwl->wr_owner != NULL) { + ret = EBUSY; + K_SPINLOCK_BREAK; + } - if (rwlock->status == INITIALIZED) { - rwlock->status = NOT_INITIALIZED; - return 0; + bit = posix_rwlock_to_offset(rwl); + err = sys_bitarray_free(&posix_rwlock_bitarray, 1, bit); + __ASSERT_NO_MSG(err == 0); } - return EINVAL; + return ret; } /** @@ -67,11 +169,14 @@ int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) */ int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) { - if (rwlock->status == NOT_INITIALIZED) { + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { return EINVAL; } - return read_lock_acquire(rwlock, SYS_FOREVER_MS); + return read_lock_acquire(rwl, SYS_FOREVER_MS); } /** @@ -87,15 +192,20 @@ int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, { int32_t timeout; uint32_t ret = 0U; + struct posix_rwlock *rwl; - if (rwlock->status == NOT_INITIALIZED || abstime->tv_nsec < 0 || - abstime->tv_nsec > NSEC_PER_SEC) { + if (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) { + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { + return EINVAL; + } + + if (read_lock_acquire(rwl, timeout) != 0U) { ret = ETIMEDOUT; } @@ -112,11 +222,14 @@ int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, */ int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) { - if (rwlock->status == NOT_INITIALIZED) { + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { return EINVAL; } - return read_lock_acquire(rwlock, 0); + return read_lock_acquire(rwl, 0); } /** @@ -129,11 +242,14 @@ int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) */ int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) { - if (rwlock->status == NOT_INITIALIZED) { + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { return EINVAL; } - return write_lock_acquire(rwlock, SYS_FOREVER_MS); + return write_lock_acquire(rwl, SYS_FOREVER_MS); } /** @@ -149,15 +265,20 @@ int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, { int32_t timeout; uint32_t ret = 0U; + struct posix_rwlock *rwl; - if (rwlock->status == NOT_INITIALIZED || abstime->tv_nsec < 0 || - abstime->tv_nsec > NSEC_PER_SEC) { + if (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) { + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { + return EINVAL; + } + + if (write_lock_acquire(rwl, timeout) != 0U) { ret = ETIMEDOUT; } @@ -174,11 +295,14 @@ int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, */ int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) { - if (rwlock->status == NOT_INITIALIZED) { + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { return EINVAL; } - return write_lock_acquire(rwlock, 0); + return write_lock_acquire(rwl, 0); } /** @@ -189,37 +313,38 @@ int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) */ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) { - if (rwlock->status == NOT_INITIALIZED) { + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { return EINVAL; } - if (k_current_get() == rwlock->wr_owner) { + if (k_current_get() == rwl->wr_owner) { /* Write unlock */ - rwlock->wr_owner = NULL; - k_sem_give(&rwlock->reader_active); - k_sem_give(&rwlock->wr_sem); + rwl->wr_owner = NULL; + k_sem_give(&rwl->reader_active); + k_sem_give(&rwl->wr_sem); } else { /* Read unlock */ - k_sem_give(&rwlock->rd_sem); + k_sem_give(&rwl->rd_sem); - if (k_sem_count_get(&rwlock->rd_sem) == - CONCURRENT_READER_LIMIT) { + if (k_sem_count_get(&rwl->rd_sem) == CONCURRENT_READER_LIMIT) { /* Last read lock, unlock writer */ - k_sem_give(&rwlock->reader_active); + k_sem_give(&rwl->reader_active); } } return 0; } - -static uint32_t read_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout) +static uint32_t read_lock_acquire(struct posix_rwlock *rwl, 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); + 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; } @@ -227,7 +352,7 @@ static uint32_t read_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout) return ret; } -static uint32_t write_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout) +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(); @@ -236,7 +361,7 @@ static uint32_t write_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout) k_timeout = SYS_TIMEOUT_MS(timeout); /* waiting for release of write lock */ - if (k_sem_take(&rwlock->wr_sem, k_timeout) == 0) { + 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; @@ -247,10 +372,10 @@ static uint32_t write_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout) 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(); + if (k_sem_take(&rwl->reader_active, k_timeout) == 0) { + rwl->wr_owner = k_current_get(); } else { - k_sem_give(&rwlock->wr_sem); + k_sem_give(&rwl->wr_sem); ret = EBUSY; } diff --git a/lib/posix/sched.c b/lib/posix/sched.c index 4f71badded980e6..195c58957520da6 100644 --- a/lib/posix/sched.c +++ b/lib/posix/sched.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2018-2023 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -41,3 +41,63 @@ int sched_get_priority_max(int policy) 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; +} diff --git a/lib/posix/semaphore.c b/lib/posix/semaphore.c index 7a1392cd5211383..07ec11add4e599a 100644 --- a/lib/posix/semaphore.c +++ b/lib/posix/semaphore.c @@ -1,11 +1,78 @@ /* * 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. @@ -148,3 +215,172 @@ int sem_wait(sem_t *semaphore) (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/shell/CMakeLists.txt b/lib/posix/shell/CMakeLists.txt new file mode 100644 index 000000000000000..b6dfe6a565fc612 --- /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 000000000000000..1ce4ae5a9590306 --- /dev/null +++ b/lib/posix/shell/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2024 Meta +# SPDX-License-Identifier: Apache-2.0 + +if SHELL + +config POSIX_SHELL + bool + help + Compile the parent `posix` shell command. + +rsource "Kconfig.uname" + +endif # SHELL diff --git a/lib/posix/shell/Kconfig.uname b/lib/posix/shell/Kconfig.uname new file mode 100644 index 000000000000000..11ea1166433a820 --- /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 000000000000000..95fdd4ef5a0a537 --- /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 000000000000000..cb17d613b18a55e --- /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 000000000000000..54e12de9a593041 --- /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/signal.c b/lib/posix/signal.c index d2153238ff8fc57..f14ef7fe614f969 100644 --- a/lib/posix/signal.c +++ b/lib/posix/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/stropts.c b/lib/posix/stropts.c new file mode 100644 index 000000000000000..54fca00cc9ff44c --- /dev/null +++ b/lib/posix/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/timer.c b/lib/posix/timer.c index 11081f1b4d87f05..7caecc180a1279b 100644 --- a/lib/posix/timer.c +++ b/lib/posix/timer.c @@ -1,31 +1,36 @@ /* * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2024, Meta * * SPDX-License-Identifier: Apache-2.0 */ -#include #include -#include -#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; - void (*sigev_notify_function)(union sigval val); - union sigval val; + 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, 4); + CONFIG_MAX_TIMER_COUNT, __alignof__(struct timer_obj)); static void zephyr_timer_wrapper(struct k_timer *ztimer) { @@ -35,9 +40,64 @@ static void zephyr_timer_wrapper(struct k_timer *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; } - (timer->sigev_notify_function)(timer->val); + 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); } /** @@ -50,39 +110,89 @@ static void zephyr_timer_wrapper(struct k_timer *ztimer) */ 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 (clockid != CLOCK_MONOTONIC || evp == NULL || - (evp->sigev_notify != SIGEV_NONE && - evp->sigev_notify != SIGEV_SIGNAL)) { + if (evp == NULL || timerid == NULL) { 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 { + 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->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; + *timer = (struct timer_obj){0}; + timer->evp = *evp; + evp = &timer->evp; - if (evp->sigev_notify == SIGEV_NONE) { + switch (evp->sigev_notify) { + case SIGEV_NONE: k_timer_init(&timer->ztimer, NULL, NULL); - } else { + 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; - return 0; +free_timer: + k_mem_slab_free(&posix_timer_slab, (void *)&timer); + +out: + return ret; } /** @@ -222,6 +332,10 @@ int timer_delete(timer_t timerid) 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/utils/CMakeLists.txt b/lib/utils/CMakeLists.txt new file mode 100644 index 000000000000000..e0e1673f44503e2 --- /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 000000000000000..340c0ac42c24cfd --- /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/misc/generated/generated_header.template b/misc/generated/generated_header.template deleted file mode 100644 index 2b323cd20e1c7e1..000000000000000 --- a/misc/generated/generated_header.template +++ /dev/null @@ -1 +0,0 @@ -/* WARNING. THIS FILE IS AUTO-GENERATED. DO NOT MODIFY! */ diff --git a/modules/Kconfig b/modules/Kconfig index fb60ecf73b98441..14fe21b26f72e37 100644 --- a/modules/Kconfig +++ b/modules/Kconfig @@ -12,8 +12,6 @@ comment "Available modules." osource "$(KCONFIG_BINARY_DIR)/Kconfig.modules" -comment "Optional modules. Make sure they're installed, via the project manifest." - source "modules/Kconfig.altera" source "modules/Kconfig.atmel" source "modules/Kconfig.chre" @@ -34,7 +32,6 @@ source "modules/Kconfig.silabs" source "modules/Kconfig.simplelink" source "modules/Kconfig.mspm0" source "modules/Kconfig.sof" -source "modules/Kconfig.st" source "modules/Kconfig.stm32" source "modules/Kconfig.syst" source "modules/Kconfig.telink" @@ -46,6 +43,7 @@ source "modules/Kconfig.xtensa" source "modules/zcbor/Kconfig" source "modules/Kconfig.mcuboot" source "modules/Kconfig.intel" +source "modules/hostap/Kconfig" comment "Unavailable modules, please install those via the project manifest." diff --git a/modules/Kconfig.infineon b/modules/Kconfig.infineon index 348305ccbf73351..7ca374f4f32a4d8 100644 --- a/modules/Kconfig.infineon +++ b/modules/Kconfig.infineon @@ -50,4 +50,19 @@ config HAS_XMCLIB_CCU help Enable XMCLIB CCU4/CCU8 +config HAS_XMCLIB_WDT + bool + 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.libmetal b/modules/Kconfig.libmetal index dd01125e14ecb60..b1575c829028d19 100644 --- a/modules/Kconfig.libmetal +++ b/modules/Kconfig.libmetal @@ -1,8 +1,12 @@ # Copyright (c) 2018 Linaro Limited # SPDX-License-Identifier: Apache-2.0 +config ZEPHYR_LIBMETAL_MODULE + bool + menuconfig LIBMETAL bool "libmetal Support" + depends on ZEPHYR_LIBMETAL_MODULE help This option enables the libmetal HAL abstraction layer diff --git a/modules/Kconfig.mcuboot b/modules/Kconfig.mcuboot index 8df4bde8829c5b7..b9b842b0a361250 100644 --- a/modules/Kconfig.mcuboot +++ b/modules/Kconfig.mcuboot @@ -110,6 +110,12 @@ config MCUBOOT_IMGTOOL_SIGN_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 4413c29423eee98..bc4ac6d158f122e 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.open-amp b/modules/Kconfig.open-amp index 5db32041bca61b5..71d2885e5a78e7a 100644 --- a/modules/Kconfig.open-amp +++ b/modules/Kconfig.open-amp @@ -1,8 +1,12 @@ # Copyright (c) 2018 Linaro Limited # SPDX-License-Identifier: Apache-2.0 +config ZEPHYR_OPEN_AMP_MODULE + bool + config OPENAMP bool "OpenAMP Support" + depends on ZEPHYR_OPEN_AMP_MODULE select LIBMETAL help This option enables the OpenAMP IPC library diff --git a/modules/Kconfig.sof b/modules/Kconfig.sof index 17e40df34b53b62..4a0b94186606e73 100644 --- a/modules/Kconfig.sof +++ b/modules/Kconfig.sof @@ -1,7 +1,11 @@ # Copyright (c) 2020 Intel Corporation # SPDX-License-Identifier: Apache-2.0 +config ZEPHYR_SOF_MODULE + bool + config SOF bool "Sound Open Firmware (SOF)" + depends on ZEPHYR_SOF_MODULE help Build Sound Open Firmware (SOF) support. diff --git a/modules/Kconfig.st b/modules/Kconfig.st deleted file mode 100644 index 2db03e18f77c8a6..000000000000000 --- a/modules/Kconfig.st +++ /dev/null @@ -1,187 +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_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 ad598f6300685d3..57749a8ec6b4d7c 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/Kconfig.tinycrypt b/modules/Kconfig.tinycrypt index 7f279fbc59ac74a..168e05ed79980b5 100644 --- a/modules/Kconfig.tinycrypt +++ b/modules/Kconfig.tinycrypt @@ -3,8 +3,12 @@ # Copyright (c) 2015 Intel Corporation # SPDX-License-Identifier: Apache-2.0 +config ZEPHYR_TINYCRYPT_MODULE + bool + config TINYCRYPT bool "TinyCrypt Support" + depends on ZEPHYR_TINYCRYPT_MODULE help This option enables the TinyCrypt cryptography library. diff --git a/modules/acpica/CMakeLists.txt b/modules/acpica/CMakeLists.txt index 2c77a6c16330c9a..ad8a75b0230e727 100644 --- a/modules/acpica/CMakeLists.txt +++ b/modules/acpica/CMakeLists.txt @@ -1,179 +1,179 @@ # Copyright (c) 2023 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -if (CONFIG_ACPI) - set(ACPI_DIR ${ZEPHYR_CURRENT_MODULE_DIR}/) - set(INC_DIR ${ACPI_DIR}/source/include/) - set(SRC_DIR ${ACPI_DIR}/source) - set(COMP_DIR ${ACPI_DIR}/source/components) - set(PARENT_SRC_DIR ${ACPI_DIR}../../zephyr) - set(ACPI_PARENT_DIR ${ACPI_DIR}/../) +if(CONFIG_ACPI) + set(ACPI_DIR ${ZEPHYR_CURRENT_MODULE_DIR}/) + set(INC_DIR ${ACPI_DIR}/source/include/) + set(SRC_DIR ${ACPI_DIR}/source) + set(COMP_DIR ${ACPI_DIR}/source/components) + set(PARENT_SRC_DIR ${ACPI_DIR}../../zephyr) + set(ACPI_PARENT_DIR ${ACPI_DIR}/../) - zephyr_include_directories( - ${PARENT_SRC_DIR}/include/ - ${ACPI_PARENT_DIR}/ - ${INC_DIR}/ - ${INC_DIR}/platform/ - ${SRC_DIR}/compiler/ - ${ZEPHYR_CURRENT_MODULE_DIR}/generate/zephyr/ - ${SRC_DIR}/tools/acpiexec/ - ${SRC_DIR}/tools/acpidump/ - ) + zephyr_include_directories( + ${PARENT_SRC_DIR}/include/ + ${ACPI_PARENT_DIR}/ + ${INC_DIR}/ + ${INC_DIR}/platform/ + ${SRC_DIR}/compiler/ + ${ZEPHYR_CURRENT_MODULE_DIR}/generate/zephyr/ + ${SRC_DIR}/tools/acpiexec/ + ${SRC_DIR}/tools/acpidump/ + ) - zephyr_library() + zephyr_library() - add_compile_definitions(__ZEPHYR__) - add_compile_definitions(ACPI_DEBUG_OUTPUT) - add_compile_definitions(ACPI_EXAMPLE_APP) - add_compile_definitions(CONFIG_EXTERNAL_LIBC) + add_compile_definitions(__ZEPHYR__) + add_compile_definitions(ACPI_DEBUG_OUTPUT) + add_compile_definitions(ACPI_EXAMPLE_APP) + add_compile_definitions(CONFIG_EXTERNAL_LIBC) - get_filename_component(libname "${SRC_DIR}/common/" NAME) + get_filename_component(libname "${SRC_DIR}/common/" NAME) -if (CONFIG_ACPI_DSDT_SUPPORT) - zephyr_library_sources( - ${COMP_DIR}/dispatcher/dsargs.c - ${COMP_DIR}/dispatcher/dscontrol.c - ${COMP_DIR}/dispatcher/dsdebug.c - ${COMP_DIR}/dispatcher/dsfield.c - ${COMP_DIR}/dispatcher/dsinit.c - ${COMP_DIR}/dispatcher/dsmethod.c - ${COMP_DIR}/dispatcher/dsmthdat.c - ${COMP_DIR}/dispatcher/dsobject.c - ${COMP_DIR}/dispatcher/dsopcode.c - ${COMP_DIR}/dispatcher/dspkginit.c - ${COMP_DIR}/dispatcher/dsutils.c - ${COMP_DIR}/dispatcher/dswexec.c - ${COMP_DIR}/dispatcher/dswload.c - ${COMP_DIR}/dispatcher/dswload2.c - ${COMP_DIR}/dispatcher/dswscope.c - ${COMP_DIR}/dispatcher/dswstate.c - ${COMP_DIR}/events/evhandler.c - ${COMP_DIR}/events/evmisc.c - ${COMP_DIR}/events/evregion.c - ${COMP_DIR}/events/evrgnini.c - ${COMP_DIR}/events/evxface.c - ${COMP_DIR}/events/evxfregn.c - ${COMP_DIR}/executer/exconcat.c - ${COMP_DIR}/executer/exconfig.c - ${COMP_DIR}/executer/exconvrt.c - ${COMP_DIR}/executer/excreate.c - ${COMP_DIR}/executer/exdebug.c - ${COMP_DIR}/executer/exdump.c - ${COMP_DIR}/executer/exfield.c - ${COMP_DIR}/executer/exfldio.c - ${COMP_DIR}/executer/exmisc.c - ${COMP_DIR}/executer/exmutex.c - ${COMP_DIR}/executer/exnames.c - ${COMP_DIR}/executer/exoparg1.c - ${COMP_DIR}/executer/exoparg2.c - ${COMP_DIR}/executer/exoparg3.c - ${COMP_DIR}/executer/exoparg6.c - ${COMP_DIR}/executer/exprep.c - ${COMP_DIR}/executer/exregion.c - ${COMP_DIR}/executer/exresnte.c - ${COMP_DIR}/executer/exresolv.c - ${COMP_DIR}/executer/exresop.c - ${COMP_DIR}/executer/exserial.c - ${COMP_DIR}/executer/exstore.c - ${COMP_DIR}/executer/exstoren.c - ${COMP_DIR}/executer/exstorob.c - ${COMP_DIR}/executer/exsystem.c - ${COMP_DIR}/executer/extrace.c - ${COMP_DIR}/executer/exutils.c - ${COMP_DIR}/hardware/hwpci.c - ${COMP_DIR}/namespace/nsaccess.c - ${COMP_DIR}/namespace/nsalloc.c - ${COMP_DIR}/namespace/nsarguments.c - ${COMP_DIR}/namespace/nsconvert.c - ${COMP_DIR}/namespace/nsdump.c - ${COMP_DIR}/namespace/nseval.c - ${COMP_DIR}/namespace/nsinit.c - ${COMP_DIR}/namespace/nsload.c - ${COMP_DIR}/namespace/nsnames.c - ${COMP_DIR}/namespace/nsobject.c - ${COMP_DIR}/namespace/nsparse.c - ${COMP_DIR}/namespace/nspredef.c - ${COMP_DIR}/namespace/nsprepkg.c - ${COMP_DIR}/namespace/nsrepair.c - ${COMP_DIR}/namespace/nsrepair2.c - ${COMP_DIR}/namespace/nssearch.c - ${COMP_DIR}/namespace/nsutils.c - ${COMP_DIR}/namespace/nswalk.c - ${COMP_DIR}/namespace/nsxfeval.c - ${COMP_DIR}/namespace/nsxfname.c - ${COMP_DIR}/namespace/nsxfobj.c - ${COMP_DIR}/parser/psargs.c - ${COMP_DIR}/parser/psloop.c - ${COMP_DIR}/parser/psobject.c - ${COMP_DIR}/parser/psopcode.c - ${COMP_DIR}/parser/psopinfo.c - ${COMP_DIR}/parser/psparse.c - ${COMP_DIR}/parser/psscope.c - ${COMP_DIR}/parser/pstree.c - ${COMP_DIR}/parser/psutils.c - ${COMP_DIR}/parser/pswalk.c - ${COMP_DIR}/parser/psxface.c - ${COMP_DIR}/resources/rsxface.c - ${COMP_DIR}/resources/rsutils.c - ${COMP_DIR}/resources/rsaddr.c - ${COMP_DIR}/resources/rscalc.c - ${COMP_DIR}/resources/rscreate.c - ${COMP_DIR}/resources/rsdumpinfo.c - ${COMP_DIR}/resources/rsinfo.c - ${COMP_DIR}/resources/rsio.c - ${COMP_DIR}/resources/rsirq.c - ${COMP_DIR}/resources/rslist.c - ${COMP_DIR}/resources/rsmemory.c - ${COMP_DIR}/resources/rsmisc.c - ${COMP_DIR}/resources/rsserial.c - ) -endif (CONFIG_ACPI_DSDT_SUPPORT) - zephyr_library_sources( - ${COMP_DIR}/tables/tbdata.c - ${COMP_DIR}/tables/tbfadt.c - ${COMP_DIR}/tables/tbfind.c - ${COMP_DIR}/tables/tbinstal.c - ${COMP_DIR}/tables/tbprint.c - ${COMP_DIR}/tables/tbutils.c - ${COMP_DIR}/tables/tbxface.c - ${COMP_DIR}/tables/tbxfload.c - ${COMP_DIR}/tables/tbxfroot.c - ${COMP_DIR}/utilities/utaddress.c - ${COMP_DIR}/utilities/utalloc.c - ${COMP_DIR}/utilities/utascii.c - ${COMP_DIR}/utilities/utbuffer.c - ${COMP_DIR}/utilities/utcache.c - ${COMP_DIR}/utilities/utcksum.c - ${COMP_DIR}/utilities/utcopy.c - ${COMP_DIR}/utilities/utdebug.c - ${COMP_DIR}/utilities/utdecode.c - ${COMP_DIR}/utilities/utdelete.c - ${COMP_DIR}/utilities/uterror.c - ${COMP_DIR}/utilities/uteval.c - ${COMP_DIR}/utilities/utexcep.c - ${COMP_DIR}/utilities/utglobal.c - ${COMP_DIR}/utilities/uthex.c - ${COMP_DIR}/utilities/utids.c - ${COMP_DIR}/utilities/utinit.c - ${COMP_DIR}/utilities/utlock.c - ${COMP_DIR}/utilities/utmath.c - ${COMP_DIR}/utilities/utmisc.c - ${COMP_DIR}/utilities/utmutex.c - ${COMP_DIR}/utilities/utobject.c - ${COMP_DIR}/utilities/utosi.c - ${COMP_DIR}/utilities/utownerid.c - ${COMP_DIR}/utilities/utnonansi.c - ${COMP_DIR}/utilities/utpredef.c - ${COMP_DIR}/utilities/utresrc.c - ${COMP_DIR}/utilities/utstate.c - ${COMP_DIR}/utilities/utstring.c - ${COMP_DIR}/utilities/utstrsuppt.c - ${COMP_DIR}/utilities/utstrtoul64.c - ${COMP_DIR}/utilities/utxface.c - ${COMP_DIR}/utilities/utxferror.c - ${COMP_DIR}/utilities/utxfinit.c - ${COMP_DIR}/utilities/utresdecode.c - ${COMP_DIR}/hardware/hwvalid.c - ${SRC_DIR}/os_specific/service_layers/oszephyr.c - ) -endif (CONFIG_ACPI) + if(CONFIG_ACPI_DSDT_SUPPORT) + zephyr_library_sources( + ${COMP_DIR}/dispatcher/dsargs.c + ${COMP_DIR}/dispatcher/dscontrol.c + ${COMP_DIR}/dispatcher/dsdebug.c + ${COMP_DIR}/dispatcher/dsfield.c + ${COMP_DIR}/dispatcher/dsinit.c + ${COMP_DIR}/dispatcher/dsmethod.c + ${COMP_DIR}/dispatcher/dsmthdat.c + ${COMP_DIR}/dispatcher/dsobject.c + ${COMP_DIR}/dispatcher/dsopcode.c + ${COMP_DIR}/dispatcher/dspkginit.c + ${COMP_DIR}/dispatcher/dsutils.c + ${COMP_DIR}/dispatcher/dswexec.c + ${COMP_DIR}/dispatcher/dswload.c + ${COMP_DIR}/dispatcher/dswload2.c + ${COMP_DIR}/dispatcher/dswscope.c + ${COMP_DIR}/dispatcher/dswstate.c + ${COMP_DIR}/events/evhandler.c + ${COMP_DIR}/events/evmisc.c + ${COMP_DIR}/events/evregion.c + ${COMP_DIR}/events/evrgnini.c + ${COMP_DIR}/events/evxface.c + ${COMP_DIR}/events/evxfregn.c + ${COMP_DIR}/executer/exconcat.c + ${COMP_DIR}/executer/exconfig.c + ${COMP_DIR}/executer/exconvrt.c + ${COMP_DIR}/executer/excreate.c + ${COMP_DIR}/executer/exdebug.c + ${COMP_DIR}/executer/exdump.c + ${COMP_DIR}/executer/exfield.c + ${COMP_DIR}/executer/exfldio.c + ${COMP_DIR}/executer/exmisc.c + ${COMP_DIR}/executer/exmutex.c + ${COMP_DIR}/executer/exnames.c + ${COMP_DIR}/executer/exoparg1.c + ${COMP_DIR}/executer/exoparg2.c + ${COMP_DIR}/executer/exoparg3.c + ${COMP_DIR}/executer/exoparg6.c + ${COMP_DIR}/executer/exprep.c + ${COMP_DIR}/executer/exregion.c + ${COMP_DIR}/executer/exresnte.c + ${COMP_DIR}/executer/exresolv.c + ${COMP_DIR}/executer/exresop.c + ${COMP_DIR}/executer/exserial.c + ${COMP_DIR}/executer/exstore.c + ${COMP_DIR}/executer/exstoren.c + ${COMP_DIR}/executer/exstorob.c + ${COMP_DIR}/executer/exsystem.c + ${COMP_DIR}/executer/extrace.c + ${COMP_DIR}/executer/exutils.c + ${COMP_DIR}/hardware/hwpci.c + ${COMP_DIR}/namespace/nsaccess.c + ${COMP_DIR}/namespace/nsalloc.c + ${COMP_DIR}/namespace/nsarguments.c + ${COMP_DIR}/namespace/nsconvert.c + ${COMP_DIR}/namespace/nsdump.c + ${COMP_DIR}/namespace/nseval.c + ${COMP_DIR}/namespace/nsinit.c + ${COMP_DIR}/namespace/nsload.c + ${COMP_DIR}/namespace/nsnames.c + ${COMP_DIR}/namespace/nsobject.c + ${COMP_DIR}/namespace/nsparse.c + ${COMP_DIR}/namespace/nspredef.c + ${COMP_DIR}/namespace/nsprepkg.c + ${COMP_DIR}/namespace/nsrepair.c + ${COMP_DIR}/namespace/nsrepair2.c + ${COMP_DIR}/namespace/nssearch.c + ${COMP_DIR}/namespace/nsutils.c + ${COMP_DIR}/namespace/nswalk.c + ${COMP_DIR}/namespace/nsxfeval.c + ${COMP_DIR}/namespace/nsxfname.c + ${COMP_DIR}/namespace/nsxfobj.c + ${COMP_DIR}/parser/psargs.c + ${COMP_DIR}/parser/psloop.c + ${COMP_DIR}/parser/psobject.c + ${COMP_DIR}/parser/psopcode.c + ${COMP_DIR}/parser/psopinfo.c + ${COMP_DIR}/parser/psparse.c + ${COMP_DIR}/parser/psscope.c + ${COMP_DIR}/parser/pstree.c + ${COMP_DIR}/parser/psutils.c + ${COMP_DIR}/parser/pswalk.c + ${COMP_DIR}/parser/psxface.c + ${COMP_DIR}/resources/rsxface.c + ${COMP_DIR}/resources/rsutils.c + ${COMP_DIR}/resources/rsaddr.c + ${COMP_DIR}/resources/rscalc.c + ${COMP_DIR}/resources/rscreate.c + ${COMP_DIR}/resources/rsdumpinfo.c + ${COMP_DIR}/resources/rsinfo.c + ${COMP_DIR}/resources/rsio.c + ${COMP_DIR}/resources/rsirq.c + ${COMP_DIR}/resources/rslist.c + ${COMP_DIR}/resources/rsmemory.c + ${COMP_DIR}/resources/rsmisc.c + ${COMP_DIR}/resources/rsserial.c + ) + endif() + zephyr_library_sources( + ${COMP_DIR}/tables/tbdata.c + ${COMP_DIR}/tables/tbfadt.c + ${COMP_DIR}/tables/tbfind.c + ${COMP_DIR}/tables/tbinstal.c + ${COMP_DIR}/tables/tbprint.c + ${COMP_DIR}/tables/tbutils.c + ${COMP_DIR}/tables/tbxface.c + ${COMP_DIR}/tables/tbxfload.c + ${COMP_DIR}/tables/tbxfroot.c + ${COMP_DIR}/utilities/utaddress.c + ${COMP_DIR}/utilities/utalloc.c + ${COMP_DIR}/utilities/utascii.c + ${COMP_DIR}/utilities/utbuffer.c + ${COMP_DIR}/utilities/utcache.c + ${COMP_DIR}/utilities/utcksum.c + ${COMP_DIR}/utilities/utcopy.c + ${COMP_DIR}/utilities/utdebug.c + ${COMP_DIR}/utilities/utdecode.c + ${COMP_DIR}/utilities/utdelete.c + ${COMP_DIR}/utilities/uterror.c + ${COMP_DIR}/utilities/uteval.c + ${COMP_DIR}/utilities/utexcep.c + ${COMP_DIR}/utilities/utglobal.c + ${COMP_DIR}/utilities/uthex.c + ${COMP_DIR}/utilities/utids.c + ${COMP_DIR}/utilities/utinit.c + ${COMP_DIR}/utilities/utlock.c + ${COMP_DIR}/utilities/utmath.c + ${COMP_DIR}/utilities/utmisc.c + ${COMP_DIR}/utilities/utmutex.c + ${COMP_DIR}/utilities/utobject.c + ${COMP_DIR}/utilities/utosi.c + ${COMP_DIR}/utilities/utownerid.c + ${COMP_DIR}/utilities/utnonansi.c + ${COMP_DIR}/utilities/utpredef.c + ${COMP_DIR}/utilities/utresrc.c + ${COMP_DIR}/utilities/utstate.c + ${COMP_DIR}/utilities/utstring.c + ${COMP_DIR}/utilities/utstrsuppt.c + ${COMP_DIR}/utilities/utstrtoul64.c + ${COMP_DIR}/utilities/utxface.c + ${COMP_DIR}/utilities/utxferror.c + ${COMP_DIR}/utilities/utxfinit.c + ${COMP_DIR}/utilities/utresdecode.c + ${COMP_DIR}/hardware/hwvalid.c + ${SRC_DIR}/os_specific/service_layers/oszephyr.c + ) +endif() diff --git a/modules/canopennode/CO_driver.c b/modules/canopennode/CO_driver.c index e8892e080f5fb77..4d161a49400a8db 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 3e76b5290b02c75..5dba56ef80002ee 100644 --- a/modules/canopennode/CO_driver_target.h +++ b/modules/canopennode/CO_driver_target.h @@ -22,6 +22,7 @@ extern "C" { #include #include #include +#include /* float32_t, float64_t */ /* Use static variables instead of calloc() */ #define CO_USE_GLOBALS @@ -46,12 +47,13 @@ extern "C" { #endif typedef bool bool_t; -typedef float float32_t; -typedef long double float64_t; typedef char char_t; typedef unsigned char oChar_t; typedef unsigned char domain_t; +BUILD_ASSERT(sizeof(float32_t) >= 4); +BUILD_ASSERT(sizeof(float64_t) >= 8); + typedef struct canopen_rx_msg { uint8_t data[8]; uint16_t ident; @@ -67,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/Kconfig b/modules/cmsis/Kconfig index 4b5a8ee285570b8..eff0be6f40c29c3 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 04e5566cc0a98b1..4f57c682138177f 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 880ff614b5b60de..e73826339453453 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 000000000000000..bef62665493df7a --- /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 bfed9b94d82e4f7..ddb2d0a8ed6afe9 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 7a4096bc4d2f074..3b887f654a98854 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 66132779eb17597..84f6532b251a14f 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_infineon/CMakeLists.txt b/modules/hal_infineon/CMakeLists.txt index aff4d21f0aaf6eb..27dbd71897f63f8 100644 --- a/modules/hal_infineon/CMakeLists.txt +++ b/modules/hal_infineon/CMakeLists.txt @@ -36,8 +36,13 @@ if (CONFIG_SOC_FAMILY_INFINEON_CAT1A) add_subdirectory(abstraction-rtos) endif() -## Add btstack-integration for CYW43xx BT devices -if (CONFIG_BT_CYW43XXX) +## Add Wi-Fi assets for AIROC devices +if (CONFIG_WIFI_AIROC) + add_subdirectory(wifi-host-driver) +endif() + +## Add BT assets for AIROC devices +if (CONFIG_BT_AIROC) add_subdirectory(btstack-integration) endif() diff --git a/modules/hal_infineon/Kconfig b/modules/hal_infineon/Kconfig index 0522c96769c3a2e..af92b98b3dc492e 100644 --- a/modules/hal_infineon/Kconfig +++ b/modules/hal_infineon/Kconfig @@ -27,6 +27,12 @@ config USE_INFINEON_SDIO Enable Secure Digital Input/Output interface (SDIO) HAL module for Infineon devices driver +config USE_INFINEON_SDHC + bool + help + Enable SDHC HAL module for Infineon devices + driver + config USE_INFINEON_SPI bool help @@ -66,9 +72,8 @@ config USE_INFINEON_WDT Enable WATCHDOG TIMER (WDT) HAL module driver for Infineon devices -config ABSTRACTION_RTOS_COMPONENT_ZEPHYR +config USE_INFINEON_ABSTRACTION_RTOS bool "Abstraction RTOS component (Zephyr support)" - default n help Enable Abstraction RTOS component with Zephyr support diff --git a/modules/hal_infineon/abstraction-rtos/CMakeLists.txt b/modules/hal_infineon/abstraction-rtos/CMakeLists.txt index cd61908659f2f5a..6b2b0e6449f8e50 100644 --- a/modules/hal_infineon/abstraction-rtos/CMakeLists.txt +++ b/modules/hal_infineon/abstraction-rtos/CMakeLists.txt @@ -5,7 +5,7 @@ zephyr_include_directories(${ZEPHYR_HAL_INFINEON_MODULE_DIR}/abstraction-rtos/include) # Enable Zephyr support -zephyr_include_directories_ifdef(CONFIG_ABSTRACTION_RTOS_COMPONENT_ZEPHYR +zephyr_include_directories_ifdef(CONFIG_USE_INFINEON_ABSTRACTION_RTOS include/COMPONENT_ZEPHYR) -zephyr_library_sources_ifdef(CONFIG_ABSTRACTION_RTOS_COMPONENT_ZEPHYR +zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_ABSTRACTION_RTOS source/COMPONENT_ZEPHYR/cyabs_rtos_zephyr.c) diff --git a/modules/hal_infineon/btstack-integration/CMakeLists.txt b/modules/hal_infineon/btstack-integration/CMakeLists.txt index ef6a64cff3ddb35..d82fe10662ddafb 100644 --- a/modules/hal_infineon/btstack-integration/CMakeLists.txt +++ b/modules/hal_infineon/btstack-integration/CMakeLists.txt @@ -30,13 +30,13 @@ if(CONFIG_CYW4373_STERLING_LWB5PLUS) set(blob_hcd_file ${hal_blobs_dir}/COMPONENT_4373/COMPONENT_STERLING-LWB5plus/bt_firmware.hcd) endif() -# use user provided FIRMWARE HCD file (path must be defined in CONFIG_CYW43XX_CUSTOM_FIRMWARE_HCD_BLOB) -if(CONFIG_CYW43XX_CUSTOM_FIRMWARE_HCD_BLOB) +# use user provided FIRMWARE HCD file (path must be defined in CONFIG_AIROC_CUSTOM_FIRMWARE_HCD_BLOB) +if(CONFIG_AIROC_CUSTOM_FIRMWARE_HCD_BLOB) # Allowed to pass absolute path to HCD blob file, or relative path from Application folder. - if(IS_ABSOLUTE ${CONFIG_CYW43XX_CUSTOM_FIRMWARE_HCD_BLOB}) - set(blob_hcd_file ${CONFIG_CYW43XX_CUSTOM_FIRMWARE_HCD_BLOB}) + if(IS_ABSOLUTE ${CONFIG_AIROC_CUSTOM_FIRMWARE_HCD_BLOB}) + set(blob_hcd_file ${CONFIG_AIROC_CUSTOM_FIRMWARE_HCD_BLOB}) else() - set(blob_hcd_file ${APPLICATION_SOURCE_DIR}/${CONFIG_CYW43XX_CUSTOM_FIRMWARE_HCD_BLOB}) + set(blob_hcd_file ${APPLICATION_SOURCE_DIR}/${CONFIG_AIROC_CUSTOM_FIRMWARE_HCD_BLOB}) endif() endif() diff --git a/modules/hal_infineon/wifi-host-driver/CMakeLists.txt b/modules/hal_infineon/wifi-host-driver/CMakeLists.txt new file mode 100644 index 000000000000000..afdb147676d6a5e --- /dev/null +++ b/modules/hal_infineon/wifi-host-driver/CMakeLists.txt @@ -0,0 +1,216 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +set(hal_dir ${ZEPHYR_HAL_INFINEON_MODULE_DIR}) +set(hal_wifi_dir ${hal_dir}/wifi-host-driver) +set(hal_wifi_dir_resources ${hal_dir}/wifi-host-driver/WiFi_Host_Driver/resources) + +set(hal_blobs_dir ${hal_dir}/zephyr/blobs/img/whd/resources) +set(blob_gen_dir ${ZEPHYR_BINARY_DIR}/include/generated) + +set(cyw43xx_fw_bin_gen_inc ${blob_gen_dir}/cyw43xx_fw_blob.inc) +set(cyw43xx_clm_bin_gen_inc ${blob_gen_dir}/cyw43xx_clm_blob.inc) + +######################################################################################### +# Wi-Fi Host driver +######################################################################################### +if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + zephyr_compile_definitions(WLAN_MFG_FIRMWARE) +endif() + +# Add WHD includes +zephyr_include_directories(${hal_wifi_dir}) +zephyr_include_directories(${hal_wifi_dir}/WiFi_Host_Driver/inc) +zephyr_include_directories(${hal_wifi_dir}/WiFi_Host_Driver/src) +zephyr_include_directories(${hal_wifi_dir}/WiFi_Host_Driver/src/include) +zephyr_include_directories(${hal_wifi_dir}/WiFi_Host_Driver/resources/resource_imp) + +# src +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_ap.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_buffer_api.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_cdc_bdc.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_chip.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_chip_constants.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_clm.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_debug.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_events.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_logging.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_management.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_network_if.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_resource_if.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_sdpcm.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_thread.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_utils.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_wifi.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_wifi_api.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_wifi_p2p.c) + +# src/bus_protocols +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/bus_protocols/whd_bus.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/bus_protocols/whd_bus_common.c) +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/bus_protocols/whd_bus_sdio_protocol.c) + +# resources/resource_imp +zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/resources/resource_imp/whd_resources.c) + +# CYW43012 firmware +if(CONFIG_CYW43012 AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir}/WiFi_Host_Driver/resources/firmware/COMPONENT_43012) + + # firmware + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_43012/43012C0-mfgtest.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_43012/43012C0-mfgtest_bin.c) + else() + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_43012/43012C0.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_43012/43012C0_bin.c) + endif() +endif() + +# CYW4343W firmware +if(CONFIG_CYW4343W AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir_resources}/firmware/COMPONENT_4343W) + + # firmware + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_4343W/4343WA1-mfgtest.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_4343W/4343WA1-mfgtest_bin.c) + else() + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_4343W/4343WA1.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_4343W/4343WA1_bin.c) + endif() +endif() + +# CYW43438 firmware/clm +if(CONFIG_CYW43438 AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir_resources}/firmware/COMPONENT_43438) + zephyr_include_directories(${hal_wifi_dir_resources}/clm/COMPONENT_43438) + + # firmware/clm + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_43438/43438A1-mfgtest.bin) + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_43438/43438A1-mfgtest.clm_blob) + + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_43438/43438A1-mfgtest_bin.c) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_43438/43438A1-mfgtest_clm_blob.c) + else() + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_43438/43438A1.bin) + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_43438/43438A1.clm_blob) + + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_43438/43438A1_bin.c) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_43438/43438A1_clm_blob.c) + endif() + +endif() + +# CYW43439 firmware +if(CONFIG_CYW43439 AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir_resources}/firmware/COMPONENT_43439) + + # firmware + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_43439/43439A0-mfgtest.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_43439/43439A0-mfgtest_bin.c) + else() + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_43439/43439A0.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_43439/43439A0_bin.c) + endif() +endif() + +# CYW4373 firmware +if(CONFIG_CYW4373 AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir_resources}/firmware/COMPONENT_4373) + + # firmware + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_4373/4373A0-mfgtest.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_4373/4373A0-mfgtest_bin.c) + else() + set(cyw43xx_fw_bin ${hal_blobs_dir}/firmware/COMPONENT_4373/4373A0.bin) + zephyr_library_sources(${hal_wifi_dir_resources}/firmware/COMPONENT_4373/4373A0_bin.c) + endif() +endif() + + +# CYW43012_MURATA_1LV clm/nvram +if(CONFIG_CYW43012_MURATA_1LV AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir}/WiFi_Host_Driver/resources/clm/COMPONENT_43012) + + # clm + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_43012/43012C0-mfgtest.clm_blob) + + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_43012/43012C0-mfgtest_clm_blob.c) + else() + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_43012/43012C0.clm_blob) + + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_43012/43012C0_clm_blob.c) + endif() + + # nvram + zephyr_include_directories(${hal_wifi_dir_resources}/nvram/COMPONENT_43012/COMPONENT_MURATA-1LV) +endif() + +# CYW4343W_MURATA_1DX clm/nvram +if(CONFIG_CYW4343W_MURATA_1DX AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir_resources}/clm/COMPONENT_4343W) + + # clm + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_4343W/4343WA1-mfgtest.clm_blob) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_4343W/4343WA1-mfgtest_clm_blob.c) + else() + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_4343W/4343WA1.clm_blob) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_4343W/4343WA1_clm_blob.c) + endif() + + # nvram + zephyr_include_directories(${hal_wifi_dir_resources}/nvram/COMPONENT_4343W/COMPONENT_MURATA-1DX) +endif() + +# CYW43439_MURATA_1YN +if(CONFIG_CYW43439_MURATA_1YN AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir_resources}/clm/COMPONENT_43439) + + # clm + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_43439/43439A0-mfgtest.clm_blob) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_43439/43439A0-mfgtest_clm_blob.c) + else() + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_43439/43439A0.clm_blob) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_43439/43439A0_clm_blob.c) + endif() + + # nvram + zephyr_include_directories(${hal_wifi_dir_resources}/nvram/COMPONENT_43439/COMPONENT_MURATA-1YN) +endif() + +# CYW4373_STERLING_LWB5PLUS +if(CONFIG_CYW4373_STERLING_LWB5PLUS AND NOT CONFIG_AIROC_WIFI_CUSTOM) + zephyr_include_directories(${hal_wifi_dir_resources}/clm/COMPONENT_4373/COMPONENT_STERLING-LWB5plus) + + # clm + if(CONFIG_AIROC_WLAN_MFG_FIRMWARE) + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_4373/COMPONENT_STERLING-LWB5plus/4373A0-mfgtest.clm_blob) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_4373/COMPONENT_STERLING-LWB5plus/4373A0-mfgtest_clm_blob.c) + else() + set(cyw43xx_clm_bin ${hal_blobs_dir}/clm/COMPONENT_4373/COMPONENT_STERLING-LWB5plus/4373A0.clm_blob) + zephyr_library_sources(${hal_wifi_dir_resources}/clm/COMPONENT_4373/COMPONENT_STERLING-LWB5plus/4373A0_clm_blob.c) + endif() + + # nvram + zephyr_include_directories_ifdef(${hal_wifi_dir_resources}/nvram/COMPONENT_4373/COMPONENT_STERLING-LWB5plus) +endif() + +# generate FW inc_blob from fw_bin +if(EXISTS ${cyw43xx_fw_bin}) + message(INFO " generate include of blob FW file: ${cyw43xx_fw_bin}") + generate_inc_file_for_target(app ${cyw43xx_fw_bin} ${cyw43xx_fw_bin_gen_inc}) +endif() + +# generate CLM inc_blob from clm_bin +if(EXISTS ${cyw43xx_clm_bin}) + message(INFO " generate include of blob CLM file: ${cyw43xx_clm_bin}") + generate_inc_file_for_target(app ${cyw43xx_clm_bin} ${cyw43xx_clm_bin_gen_inc}) +endif() diff --git a/modules/hal_nordic/Kconfig b/modules/hal_nordic/Kconfig index f842d2cb646b045..6f77bbea4275672 100644 --- a/modules/hal_nordic/Kconfig +++ b/modules/hal_nordic/Kconfig @@ -43,30 +43,6 @@ config NRF_802154_MULTIPROTOCOL_SUPPORT in the driver, this option must be enabled. Otherwise, the driver assumes that access to the radio peripheral is granted indefinitely. -config NRF_802154_ENCRYPTION - bool "nRF 802.15.4 AES-CCM* authentication & encryption" - depends on !CRYPTO_NRF_ECB - -choice NRF_802154_CCA_MODE - prompt "nRF IEEE 802.15.4 CCA mode" - default NRF_802154_CCA_MODE_ED - help - CCA mode - -config NRF_802154_CCA_MODE_ED - bool "Energy Above Threshold" - -config NRF_802154_CCA_MODE_CARRIER - bool "Carrier Seen" - -config NRF_802154_CCA_MODE_CARRIER_AND_ED - bool "Energy Above Threshold AND Carrier Seen" - -config NRF_802154_CCA_MODE_CARRIER_OR_ED - bool "Energy Above Threshold OR Carrier Seen" - -endchoice - choice NRF_802154_SL_TYPE prompt "nRF IEEE 802.15.4 Service Layer Type" @@ -77,43 +53,6 @@ config NRF_802154_SL_OPENSOURCE endchoice -config NRF_802154_CCA_ED_THRESHOLD - int "nRF IEEE 802.15.4 CCA Energy Detection threshold" - default 45 - help - If energy detected in a given channel is above the value then the - channel is deemed busy. The unit is defined as per 802.15.4-2006 spec. - -config NRF_802154_CCA_CORR_THRESHOLD - int "nRF IEEE 802.15.4 CCA Correlator threshold" - default 45 - -config NRF_802154_CCA_CORR_LIMIT - int "nRF IEEE 802.15.4 CCA Correlator limit" - default 2 - help - Limit for occurrences above correlator threshold. When not equal to - zero the correlator based signal detect is enabled. - -config NRF_802154_PENDING_SHORT_ADDRESSES - int "nRF 802.15.4 pending short addresses" - default 16 - help - Number of slots containing short addresses of nodes for which pending data is stored - -config NRF_802154_PENDING_EXTENDED_ADDRESSES - int "nRF 802.15.4 pending extended addresses" - default 16 - help - Number of slots containing extended addresses of nodes for which pending data is stored - -config NRF_802154_RX_BUFFERS - int "nRF 802.15.4 receive buffers" - default 16 - help - Number of buffers in nRF 802.15.4 driver receive queue. If this value is modified, - its serialization host counterpart must be set to the exact same value. - config NRF_802154_TEMPERATURE_UPDATE bool "nRF 802.15.4 temperature update" default y @@ -192,7 +131,47 @@ config NRF_802154_SER_DEFAULT_RESPONSE_TIMEOUT This option specifies default timeout of spinel status response in milliseconds. -if NRF_802154_SER_HOST +endmenu # NRF_802154_SER_HOST || NRF_802154_SER_RADIO + +if NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION + +choice NRF_802154_CCA_MODE + prompt "nRF IEEE 802.15.4 CCA mode" + default NRF_802154_CCA_MODE_ED + help + CCA mode + +config NRF_802154_CCA_MODE_ED + bool "Energy Above Threshold" + +config NRF_802154_CCA_MODE_CARRIER + bool "Carrier Seen" + +config NRF_802154_CCA_MODE_CARRIER_AND_ED + bool "Energy Above Threshold AND Carrier Seen" + +config NRF_802154_CCA_MODE_CARRIER_OR_ED + bool "Energy Above Threshold OR Carrier Seen" + +endchoice + +config NRF_802154_CCA_ED_THRESHOLD + int "nRF IEEE 802.15.4 CCA Energy Detection threshold" + default 45 + help + If energy detected in a given channel is above the value then the + channel is deemed busy. The unit is defined as per 802.15.4-2006 spec. + +config NRF_802154_CCA_CORR_THRESHOLD + int "nRF IEEE 802.15.4 CCA Correlator threshold" + default 45 + +config NRF_802154_CCA_CORR_LIMIT + int "nRF IEEE 802.15.4 CCA Correlator limit" + default 2 + help + Limit for occurrences above correlator threshold. When not equal to + zero the correlator based signal detect is enabled. config NRF_802154_RX_BUFFERS int "nRF 802.15.4 receive buffers" @@ -201,17 +180,59 @@ config NRF_802154_RX_BUFFERS Number of buffers in nRF 802.15.4 driver serialization host's receive queue. If this value is modified, its remote counterpart must be set to the exact same value. -endif +config NRF_802154_PENDING_SHORT_ADDRESSES + int "nRF 802.15.4 pending short addresses" + default 16 + help + Number of slots containing short addresses of nodes for which pending data is stored -endmenu # NRF_802154_SER_HOST || NRF_802154_SER_RADIO +config NRF_802154_PENDING_EXTENDED_ADDRESSES + int "nRF 802.15.4 pending extended addresses" + default 16 + help + Number of slots containing extended addresses of nodes for which pending data is stored + +config NRF_802154_ENCRYPTION + bool "nRF 802.15.4 AES-CCM* authentication & encryption" + depends on !CRYPTO_NRF_ECB + +config NRF_802154_SECURITY_KEY_STORAGE_SIZE + int "nRF 802.15.4 security key storage size" + default 3 + help + Number of encryption keys that the nRF 802.15.4 Radio Driver can store simultaneously. config NRF_802154_CARRIER_FUNCTIONS bool "nRF 802.15.4 carrier functions" - depends on NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION help This option enables functions such as modulated carrier and continuous carrier. If this option is modified on a multicore SoC, its remote counterpart must be set to the exact same value. +choice NRF_802154_ASSERT_CHOICE + prompt "nRF 802.15.4 assert implementation" + default NRF_802154_ASSERT_ZEPHYR_MINIMAL + +config NRF_802154_ASSERT_ZEPHYR_MINIMAL + bool "nRF 802.15.4 minimal assertions" + help + This option provides minimal run-time checking of the nRF 802.15.4 Radio Driver's operation, + even if kernel-wide CONFIG_ASSERT is disabled. In case of an abnormal condition the function + `nrf_802154_assert_handler()` is called. File and line debug information are not provided + to save memory of the image file. Default implementation of the `nrf_802154_assert_handler` + involves a call to `k_panic`/`k_oops` and allows further tweaking of the behavior. + You can also provide your own implementation of `nrf_802154_assert_handler`. + +config NRF_802154_ASSERT_ZEPHYR + bool "nRF 802.15.4 Radio Driver assertions as Zephyr's standard __ASERT_NO_MSG" + help + The run-time checking of the nRF 802.15.4 Radio Driver depends fully on the configuration + of the `__ASSERT_NO_MSG` macro, including the ability to completely turn off the run-time + checking. + +endchoice # NRF_802154_ASSERT_CHOICE + +endif # NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION + endmenu # HAS_NORDIC_DRIVERS rsource "nrfx/Kconfig" diff --git a/modules/hal_nordic/nrf_802154/CMakeLists.txt b/modules/hal_nordic/nrf_802154/CMakeLists.txt index c338981b651c50b..30c4c237a049eb7 100644 --- a/modules/hal_nordic/nrf_802154/CMakeLists.txt +++ b/modules/hal_nordic/nrf_802154/CMakeLists.txt @@ -12,24 +12,6 @@ if (CONFIG_NRF_802154_RADIO_DRIVER) sl_opensource/platform/nrf_802154_irq_zephyr.c sl_opensource/platform/nrf_802154_temperature_zephyr.c ) - - target_compile_definitions(zephyr-802154-interface - INTERFACE - # CCA mode options - NRF_802154_CCA_CORR_LIMIT_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_LIMIT} - NRF_802154_CCA_CORR_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_THRESHOLD} - NRF_802154_CCA_ED_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_ED_THRESHOLD} - ) - - if (CONFIG_NRF_802154_CCA_MODE_ED) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_ED) - elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER) - elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER_AND_ED) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER_AND_ED) - elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER_OR_ED) - target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER_OR_ED) - endif() endif () if (CONFIG_NRF_802154_SERIALIZATION) @@ -69,8 +51,26 @@ target_compile_definitions(zephyr-802154-interface # ACK timeout NRF_802154_ACK_TIMEOUT_ENABLED=1 + + # CCA mode options + NRF_802154_CCA_CORR_LIMIT_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_LIMIT} + NRF_802154_CCA_CORR_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_CORR_THRESHOLD} + NRF_802154_CCA_ED_THRESHOLD_DEFAULT=${CONFIG_NRF_802154_CCA_ED_THRESHOLD} + + # Key storage size + NRF_802154_SECURITY_KEY_STORAGE_SIZE=${CONFIG_NRF_802154_SECURITY_KEY_STORAGE_SIZE} ) +if (CONFIG_NRF_802154_CCA_MODE_ED) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_ED) +elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER) +elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER_AND_ED) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER_AND_ED) +elseif (CONFIG_NRF_802154_CCA_MODE_CARRIER_OR_ED) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_CARRIER_OR_ED) +endif() + if (CONFIG_NRF_802154_ENCRYPTION) target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_ENCRYPTION_ENABLED=1) target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_SECURITY_WRITER_ENABLED=1) @@ -93,8 +93,10 @@ else() target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CARRIER_FUNCTIONS_ENABLED=0) endif() -if (CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION) - 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\") + target_sources(nrf-802154-platform PRIVATE nrf_802154_assert_handler.c) endif() set(NRF52_SERIES ${CONFIG_SOC_SERIES_NRF52X}) diff --git a/modules/hal_nordic/nrf_802154/include/nrf_802154_assert_zephyr.h b/modules/hal_nordic/nrf_802154/include/nrf_802154_assert_zephyr.h new file mode 100644 index 000000000000000..ecd09de609ade6d --- /dev/null +++ b/modules/hal_nordic/nrf_802154/include/nrf_802154_assert_zephyr.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NRF_802154_ASSERT_ZEPHYR_H__ +#define NRF_802154_ASSERT_ZEPHYR_H__ + +#if defined(CONFIG_NRF_802154_ASSERT_ZEPHYR) + +#include + +#define NRF_802154_ASSERT(condition) __ASSERT_NO_MSG(condition) + +#elif defined(CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL) + +extern void nrf_802154_assert_handler(void); + +#define NRF_802154_ASSERT(condition) \ + do { \ + if (!(condition)) { \ + nrf_802154_assert_handler(); \ + } \ + } while (0) + +#endif /* CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL */ + +#endif /* NRF_802154_ASSERT_ZEPHYR_H__*/ diff --git a/modules/hal_nordic/nrf_802154/nrf_802154_assert_handler.c b/modules/hal_nordic/nrf_802154/nrf_802154_assert_handler.c new file mode 100644 index 000000000000000..14d964724c6de58 --- /dev/null +++ b/modules/hal_nordic/nrf_802154/nrf_802154_assert_handler.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "nrf_802154_assert_zephyr.h" + +#if defined(CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL) + +__weak void nrf_802154_assert_handler(void) +{ +#ifdef CONFIG_USERSPACE + /* User threads aren't allowed to induce kernel panics; generate + * an oops instead. + */ + if (k_is_user_context()) { + k_oops(); + } +#endif + + k_panic(); +} + +#endif /* CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL */ diff --git a/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c b/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c index 06ad1f003e6bf9f..b2629eef67b767a 100644 --- a/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c +++ b/modules/hal_nordic/nrf_802154/serialization/platform/nrf_802154_spinel_backend_ipc.c @@ -9,6 +9,7 @@ #include #include +#include "nrf_802154.h" #include "nrf_802154_spinel_backend_callouts.h" #include "nrf_802154_serialization_error.h" #include "../../spinel_base/spinel.h" @@ -71,9 +72,11 @@ nrf_802154_ser_err_t nrf_802154_backend_init(void) } /* Send packet thread details */ -#define RING_BUFFER_LEN 16 #define SEND_THREAD_STACK_SIZE 1024 +/* Make the ring buffer long enough to hold all notifications that the driver can produce */ +#define RING_BUFFER_LEN (NRF_802154_MAX_PENDING_NOTIFICATIONS + 1) + static K_SEM_DEFINE(send_sem, 0, RING_BUFFER_LEN); K_THREAD_STACK_DEFINE(send_thread_stack, SEND_THREAD_STACK_SIZE); struct k_thread send_thread_data; diff --git a/modules/hal_nordic/nrfx/CMakeLists.txt b/modules/hal_nordic/nrfx/CMakeLists.txt index 4d637ba43f1206e..cee9540c1e58e26 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,6 +36,8 @@ 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) @@ -64,6 +71,7 @@ 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_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 +87,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) @@ -104,7 +113,6 @@ zephyr_library_sources_ifdef(CONFIG_NRFX_TWIM ${SRC_DIR}/nrfx_twim.c) zephyr_library_sources_ifdef(CONFIG_NRFX_TWIS ${SRC_DIR}/nrfx_twis.c) zephyr_library_sources_ifdef(CONFIG_NRFX_UART ${SRC_DIR}/nrfx_uart.c) zephyr_library_sources_ifdef(CONFIG_NRFX_UARTE ${SRC_DIR}/nrfx_uarte.c) -zephyr_library_sources_ifdef(CONFIG_NRFX_USBD ${SRC_DIR}/nrfx_usbd.c) zephyr_library_sources_ifdef(CONFIG_NRFX_USBREG ${SRC_DIR}/nrfx_usbreg.c) zephyr_library_sources_ifdef(CONFIG_NRFX_WDT ${SRC_DIR}/nrfx_wdt.c) @@ -112,6 +120,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 @@ -129,3 +141,15 @@ 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() diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index 41b9c40c9a9997f..d4efbb7cac8d376 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 @@ -82,6 +115,11 @@ config NRFX_I2S0 depends on $(dt_nodelabel_has_compat,i2s0,$(DT_COMPAT_NORDIC_NRF_I2S)) select NRFX_I2S +config NRFX_I2S20 + bool "I2S20 driver instance" + depends on $(dt_nodelabel_has_compat,i2s20,$(DT_COMPAT_NORDIC_NRF_I2S)) + select NRFX_I2S + config NRFX_IPC bool "IPC driver" depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_IPC)) @@ -154,6 +192,26 @@ config NRFX_QDEC1 depends on $(dt_nodelabel_has_compat,qdec1,$(DT_COMPAT_NORDIC_NRF_QDEC)) select NRFX_QDEC +config NRFX_QDEC20 + bool "QDEC20 driver instance" + depends on $(dt_nodelabel_has_compat,qdec20,$(DT_COMPAT_NORDIC_NRF_QDEC)) + select NRFX_QDEC + +config NRFX_QDEC21 + bool "QDEC21 driver instance" + depends on $(dt_nodelabel_has_compat,qdec21,$(DT_COMPAT_NORDIC_NRF_QDEC)) + select NRFX_QDEC + +config NRFX_QDEC130 + bool "QDEC130 driver instance" + depends on $(dt_nodelabel_has_compat,qdec130,$(DT_COMPAT_NORDIC_NRF_QDEC)) + select NRFX_QDEC + +config NRFX_QDEC131 + bool "QDEC131 driver instance" + depends on $(dt_nodelabel_has_compat,qdec131,$(DT_COMPAT_NORDIC_NRF_QDEC)) + select NRFX_QDEC + config NRFX_QSPI bool "QSPI driver" depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_QSPI)) @@ -230,6 +288,81 @@ config NRFX_SPIM4 depends on $(dt_nodelabel_has_compat,spi4,$(DT_COMPAT_NORDIC_NRF_SPIM)) select NRFX_SPIM +config NRFX_SPIM00 + bool "SPIM00 driver instance" + depends on $(dt_nodelabel_has_compat,spi00,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + +config NRFX_SPIM20 + bool "SPIM20 driver instance" + depends on $(dt_nodelabel_has_compat,spi20,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + +config NRFX_SPIM21 + bool "SPIM21 driver instance" + depends on $(dt_nodelabel_has_compat,spi21,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + +config NRFX_SPIM22 + bool "SPIM22 driver instance" + depends on $(dt_nodelabel_has_compat,spi22,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + +config NRFX_SPIM30 + bool "SPIM30 driver instance" + depends on $(dt_nodelabel_has_compat,spi30,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + +config NRFX_SPIM120 + bool "SPIM120 driver instance" + depends on $(dt_nodelabel_has_compat,spi120,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + +config NRFX_SPIM121 + bool "SPIM121 driver instance" + depends on $(dt_nodelabel_has_compat,spi121,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + +config NRFX_SPIM130 + bool "SPIM130 driver instance" + depends on $(dt_nodelabel_has_compat,spi130,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + +config NRFX_SPIM131 + bool "SPIM131 driver instance" + depends on $(dt_nodelabel_has_compat,spi131,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + +config NRFX_SPIM132 + bool "SPIM132 driver instance" + depends on $(dt_nodelabel_has_compat,spi132,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + +config NRFX_SPIM133 + bool "SPIM133 driver instance" + depends on $(dt_nodelabel_has_compat,spi133,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + +config NRFX_SPIM134 + bool "SPIM134 driver instance" + depends on $(dt_nodelabel_has_compat,spi134,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + +config NRFX_SPIM135 + bool "SPIM135 driver instance" + depends on $(dt_nodelabel_has_compat,spi135,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + +config NRFX_SPIM136 + bool "SPIM136 driver instance" + depends on $(dt_nodelabel_has_compat,spi136,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + +config NRFX_SPIM137 + bool "SPIM137 driver instance" + depends on $(dt_nodelabel_has_compat,spi137,$(DT_COMPAT_NORDIC_NRF_SPIM)) + select NRFX_SPIM + config NRFX_SPIS bool @@ -289,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 @@ -325,6 +493,71 @@ config NRFX_TWIM3 depends on $(dt_nodelabel_has_compat,i2c3,$(DT_COMPAT_NORDIC_NRF_TWIM)) select NRFX_TWIM +config NRFX_TWIM20 + bool "TWIM20 driver instance" + depends on $(dt_nodelabel_has_compat,i2c20,$(DT_COMPAT_NORDIC_NRF_TWIM)) + select NRFX_TWIM + +config NRFX_TWIM21 + bool "TWIM21 driver instance" + depends on $(dt_nodelabel_has_compat,i2c21,$(DT_COMPAT_NORDIC_NRF_TWIM)) + select NRFX_TWIM + +config NRFX_TWIM22 + bool "TWIM22 driver instance" + depends on $(dt_nodelabel_has_compat,i2c22,$(DT_COMPAT_NORDIC_NRF_TWIM)) + select NRFX_TWIM + +config NRFX_TWIM30 + bool "TWIM30 driver instance" + depends on $(dt_nodelabel_has_compat,i2c30,$(DT_COMPAT_NORDIC_NRF_TWIM)) + select NRFX_TWIM + +config NRFX_TWIM120 + bool "TWIM120 driver instance" + depends on $(dt_nodelabel_has_compat,i2c120,$(DT_COMPAT_NORDIC_NRF_TWIM)) + select NRFX_TWIM + +config NRFX_TWIM130 + bool "TWIM130 driver instance" + depends on $(dt_nodelabel_has_compat,i2c130,$(DT_COMPAT_NORDIC_NRF_TWIM)) + select NRFX_TWIM + +config NRFX_TWIM131 + bool "TWIM131 driver instance" + depends on $(dt_nodelabel_has_compat,i2c131,$(DT_COMPAT_NORDIC_NRF_TWIM)) + select NRFX_TWIM + +config NRFX_TWIM132 + bool "TWIM132 driver instance" + depends on $(dt_nodelabel_has_compat,i2c132,$(DT_COMPAT_NORDIC_NRF_TWIM)) + select NRFX_TWIM + +config NRFX_TWIM133 + bool "TWIM133 driver instance" + depends on $(dt_nodelabel_has_compat,i2c133,$(DT_COMPAT_NORDIC_NRF_TWIM)) + select NRFX_TWIM + +config NRFX_TWIM134 + bool "TWIM134 driver instance" + depends on $(dt_nodelabel_has_compat,i2c134,$(DT_COMPAT_NORDIC_NRF_TWIM)) + select NRFX_TWIM + +config NRFX_TWIM135 + bool "TWIM135 driver instance" + depends on $(dt_nodelabel_has_compat,i2c135,$(DT_COMPAT_NORDIC_NRF_TWIM)) + select NRFX_TWIM + +config NRFX_TWIM136 + bool "TWIM136 driver instance" + depends on $(dt_nodelabel_has_compat,i2c136,$(DT_COMPAT_NORDIC_NRF_TWIM)) + select NRFX_TWIM + +config NRFX_TWIM137 + bool "TWIM137 driver instance" + depends on $(dt_nodelabel_has_compat,i2c137,$(DT_COMPAT_NORDIC_NRF_TWIM)) + select NRFX_TWIM + config NRFX_TWIS bool @@ -379,18 +612,51 @@ config NRFX_UARTE3 depends on $(dt_nodelabel_has_compat,uart3,$(DT_COMPAT_NORDIC_NRF_UARTE)) select NRFX_UARTE -config NRFX_USBD - bool "USBD driver" - depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_USBD)) +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_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_USBD_ISO_IN_ZLP - bool "Send ZLP on ISO IN when not ready" - depends on NRFX_USBD - default y +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 - Controls the response of the ISO IN endpoint to an IN token when no - data is ready to be sent. When enabled, ZLP is sent when no data is - ready. When disabled, no response is sent (bus timeout occurs). + 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" @@ -409,6 +675,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 41776380cdb3c15..b24d683d3de19e8 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 @@ -132,10 +136,6 @@ config NRFX_UARTE_LOG bool "UARTE driver logging" depends on NRFX_UARTE -config NRFX_USBD_LOG - bool "USBD driver logging" - depends on NRFX_USBD - config NRFX_USBREG_LOG bool "USBREG driver logging" depends on NRFX_USBREG diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index a843e96c3ba48d4..543329b4a300589 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,11 +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 #endif -#ifdef CONFIG_NRFX_GPIOTE_LOG -#define NRFX_GPIOTE_CONFIG_LOG_ENABLED 1 +#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_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 @@ -135,6 +151,9 @@ #ifdef CONFIG_NRFX_I2S0 #define NRFX_I2S0_ENABLED 1 #endif +#ifdef CONFIG_NRFX_I2S20 +#define NRFX_I2S20_ENABLED 1 +#endif #ifdef CONFIG_NRFX_IPC #define NRFX_IPC_ENABLED 1 @@ -238,6 +257,18 @@ #ifdef CONFIG_NRFX_QDEC1 #define NRFX_QDEC1_ENABLED 1 #endif +#ifdef CONFIG_NRFX_QDEC20 +#define NRFX_QDEC20_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_QDEC21 +#define NRFX_QDEC21_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_QDEC130 +#define NRFX_QDEC130_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_QDEC131 +#define NRFX_QDEC131_ENABLED 1 +#endif #ifdef CONFIG_NRFX_QSPI #define NRFX_QSPI_ENABLED 1 @@ -320,6 +351,51 @@ DT_PROP(DT_NODELABEL(spi4), rx_delay_supported)) #define NRFX_SPIM_EXTENDED_ENABLED 1 #endif +#ifdef CONFIG_NRFX_SPIM00 +#define NRFX_SPIM00_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIM20 +#define NRFX_SPIM20_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIM21 +#define NRFX_SPIM21_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIM22 +#define NRFX_SPIM22_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIM30 +#define NRFX_SPIM30_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIM120 +#define NRFX_SPIM120_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIM121 +#define NRFX_SPIM121_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIM130 +#define NRFX_SPIM130_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIM131 +#define NRFX_SPIM131_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIM132 +#define NRFX_SPIM132_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIM133 +#define NRFX_SPIM133_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIM134 +#define NRFX_SPIM134_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIM135 +#define NRFX_SPIM135_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIM136 +#define NRFX_SPIM136_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_SPIM137 +#define NRFX_SPIM137_ENABLED 1 +#endif #ifdef CONFIG_NRFX_SPIS #define NRFX_SPIS_ENABLED 1 @@ -375,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 @@ -407,6 +504,45 @@ #ifdef CONFIG_NRFX_TWIM3 #define NRFX_TWIM3_ENABLED 1 #endif +#ifdef CONFIG_NRFX_TWIM20 +#define NRFX_TWIM20_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TWIM21 +#define NRFX_TWIM21_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TWIM22 +#define NRFX_TWIM22_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TWIM30 +#define NRFX_TWIM30_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TWIM120 +#define NRFX_TWIM120_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TWIM130 +#define NRFX_TWIM130_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TWIM131 +#define NRFX_TWIM131_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TWIM132 +#define NRFX_TWIM132_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TWIM133 +#define NRFX_TWIM133_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TWIM134 +#define NRFX_TWIM134_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TWIM135 +#define NRFX_TWIM135_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TWIM136 +#define NRFX_TWIM136_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TWIM137 +#define NRFX_TWIM137_ENABLED 1 +#endif #ifdef CONFIG_NRFX_TWIS #define NRFX_TWIS_ENABLED 1 @@ -455,16 +591,32 @@ #ifdef CONFIG_NRFX_UARTE3 #define NRFX_UARTE3_ENABLED 1 #endif - -#ifdef CONFIG_NRFX_USBD -#define NRFX_USBD_ENABLED 1 +#ifdef CONFIG_NRFX_UARTE00 +#define NRFX_UARTE00_ENABLED 1 #endif -#ifdef CONFIG_NRFX_USBD_LOG -#define NRFX_USBD_CONFIG_LOG_ENABLED 1 +#ifdef CONFIG_NRFX_UARTE20 +#define NRFX_UARTE20_ENABLED 1 #endif - -#ifdef CONFIG_NRFX_USBD_ISO_IN_ZLP -#define NRFX_USBD_CONFIG_ISO_IN_ZLP 1 +#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_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 @@ -486,12 +638,23 @@ #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 #define NRFX_SPIS_NRF52_ANOMALY_109_WORKAROUND_ENABLED 1 #define NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED 1 #define NRFX_PWM_NRF52_ANOMALY_109_WORKAROUND_ENABLED 1 +#define NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE \ + CONFIG_NRF52_ANOMALY_109_WORKAROUND_EGU_INSTANCE #endif #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX) @@ -535,6 +698,8 @@ #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 8c0a58713a05ba5..88a1a8b95e80280 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 4a42f92ca98f531..18bcc40b2ac3afe 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_nrf54l15_enga_application.h b/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h new file mode 100644 index 000000000000000..46b0aa0eff740ac --- /dev/null +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h @@ -0,0 +1,1538 @@ +/* + * 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 GRTC CC channels ownership mask. + */ +#ifndef NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK +#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_grtc) +#if DT_NODE_HAS_PROP(DT_INST(0, nordic_nrf_grtc), owned_channels) +#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)) + +#if ((NRFX_CONFIG_GRTC_MASK_DT(owned_channels) | \ + NRFX_CONFIG_GRTC_MASK_DT(child_owned_channels)) != NRFX_CONFIG_GRTC_MASK_DT(owned_channels)) +#error "`child-owned-channels` property must be a subset of `owned-channels` property" +#endif +#else +#error "property `owned-channels` does not exist" +#endif /* DT_NODE_HAS_PROP(DT_INST(0, nordic_nrf_grtc), owned_channels) */ +#endif /* DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_grtc) */ + +#endif /* NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK */ + +/** + * @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 873be583a35b883..c6029a186284151 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 786004c05c3154c..2257ea879a3d7fd 100644 --- a/modules/hal_nordic/nrfx/nrfx_glue.h +++ b/modules/hal_nordic/nrfx/nrfx_glue.h @@ -357,7 +357,7 @@ void nrfx_busy_wait(uint32_t usec_to_wait); #define NRFX_PPI_GROUPS_USED_BY_MPSL 0 #endif -#if NRF_802154_VERIFY_PERIPHS_ALLOC_AGAINST_MPSL +#if defined(NRF_802154_VERIFY_PERIPHS_ALLOC_AGAINST_MPSL) BUILD_ASSERT( (NRFX_PPI_CHANNELS_USED_BY_802154_DRV & NRFX_PPI_CHANNELS_USED_BY_MPSL) == 0, "PPI channels used by the IEEE802.15.4 radio driver overlap with those " diff --git a/modules/hal_nxp/usb/usb_device_config.h b/modules/hal_nxp/usb/usb_device_config.h index ca2bc5d9373b646..31a62ffbfebc522 100644 --- a/modules/hal_nxp/usb/usb_device_config.h +++ b/modules/hal_nxp/usb/usb_device_config.h @@ -39,7 +39,15 @@ /* Whether device is self power. 1U supported, 0U not supported */ #define USB_DEVICE_CONFIG_SELF_POWER (1U) -#define DT_DRV_COMPAT nxp_mcux_usbd +#define NUM_INSTS DT_NUM_INST_STATUS_OKAY(nxp_ehci) + DT_NUM_INST_STATUS_OKAY(nxp_lpcip3511) +BUILD_ASSERT(NUM_INSTS <= 1, "Only one USB device supported"); +#if DT_HAS_COMPAT_STATUS_OKAY(nxp_lpcip3511) +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT nxp_lpcip3511 +#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_ehci) +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT nxp_ehci +#endif /* Number of endpoints supported */ #define USB_DEVICE_CONFIG_ENDPOINTS (DT_INST_PROP(0, num_bidir_endpoints)) diff --git a/modules/hal_rpi_pico/CMakeLists.txt b/modules/hal_rpi_pico/CMakeLists.txt index 3ae107449aeff11..6474b18055e1734 100644 --- a/modules/hal_rpi_pico/CMakeLists.txt +++ b/modules/hal_rpi_pico/CMakeLists.txt @@ -42,7 +42,7 @@ if(CONFIG_HAS_RPI_PICO) BUILD_ALWAYS TRUE ) - add_dependencies(${ZEPHYR_CURRENT_LIBRARY} second_stage_bootloader) + zephyr_library_add_dependencies(second_stage_bootloader) zephyr_library_sources(${rp2_bootloader_asm}) endif() @@ -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 000000000000000..020dbdc5d358105 --- /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 new file mode 100644 index 000000000000000..b24320acec5245e --- /dev/null +++ b/modules/hostap/CMakeLists.txt @@ -0,0 +1,366 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +if(CONFIG_WIFI_NM_WPA_SUPPLICANT) + +zephyr_library() + +set(HOSTAP_BASE ${ZEPHYR_HOSTAP_MODULE_DIR}) +set(WIFI_NM_WPA_SUPPLICANT_BASE ${HOSTAP_BASE}/wpa_supplicant) +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_include_directories( + ${HOSTAP_BASE}/ + ${WIFI_NM_WPA_SUPPLICANT_BASE}/ + ${HOSTAP_SRC_BASE}/ +) + +zephyr_library_compile_definitions( + TLS_DEFAULT_CIPHERS=\""DEFAULT:!EXP:!LOW"\" + CONFIG_SME + CONFIG_NO_CONFIG_WRITE + CONFIG_NO_CONFIG_BLOBS + CONFIG_CTRL_IFACE + 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( + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${HOSTAP_BASE}/ + ${HOSTAP_SRC_BASE}/utils + ${HOSTAP_SRC_BASE}/drivers + ${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( + ${HOSTAP_SRC_BASE}/common/wpa_common.c + ${HOSTAP_SRC_BASE}/common/ieee802_11_common.c + ${HOSTAP_SRC_BASE}/common/hw_features_common.c + ${HOSTAP_SRC_BASE}/common/wpa_ctrl.c + ${HOSTAP_SRC_BASE}/common/cli.c + + ${HOSTAP_SRC_BASE}/drivers/driver_common.c + ${HOSTAP_SRC_BASE}/drivers/drivers.c + ${HOSTAP_SRC_BASE}/utils/base64.c + ${HOSTAP_SRC_BASE}/utils/common.c + ${HOSTAP_SRC_BASE}/utils/wpabuf.c + ${HOSTAP_SRC_BASE}/utils/bitfield.c + ${HOSTAP_SRC_BASE}/utils/eloop.c + ${HOSTAP_SRC_BASE}/utils/os_zephyr.c + ${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 + ${WIFI_NM_WPA_SUPPLICANT_BASE}/eap_register.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/op_classes.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/rrm.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/wmm_ac.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/config_none.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/bssid_ignore.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/wpas_glue.c + ${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) + 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 new file mode 100644 index 000000000000000..61e21bee34ec32b --- /dev/null +++ b/modules/hostap/Kconfig @@ -0,0 +1,304 @@ +# WPA Supplicant configuration options +# +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: Apache-2.0 +# + +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 + select NET_L2_WIFI_MGMT + select WIFI_NM + select EXPERIMENTAL + help + WPA supplicant as a network management backend for WIFI_NM. + +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) +# z_wpa_event_sock - 1 socketpair = 2 +# Remaining left for the applications running in default configuration + +# Supplicant API is stack heavy (buffers + snprintfs) and control interface +# uses socketpair which pushes the stack usage causing overflow for 2048 bytes. +# So we set SYSTEM_WORKQUEUE_STACK_SIZE default to 2560 in kernel/Kconfig + +module = WIFI_NM_WPA_SUPPLICANT +module-str = WPA supplicant +source "subsys/logging/Kconfig.template.log_config" + +config WIFI_NM_WPA_SUPPLICANT_DEBUG_LEVEL + int "Min compiled-in debug message level for WPA supplicant" + default 0 if WIFI_NM_WPA_SUPPLICANT_LOG_LEVEL_DBG # MSG_EXCESSIVE + default 3 if WIFI_NM_WPA_SUPPLICANT_LOG_LEVEL_INF # MSG_INFO + default 4 if WIFI_NM_WPA_SUPPLICANT_LOG_LEVEL_WRN # MSG_WARNING + default 5 if WIFI_NM_WPA_SUPPLICANT_LOG_LEVEL_ERR # MSG_ERROR + default 6 + help + Minimum priority level of a debug message emitted by WPA supplicant that + is compiled-in the firmware. See wpa_debug.h file of the supplicant for + available levels and functions for emitting the messages. Note that + runtime filtering can also be configured in addition to the compile-time + filtering. + +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. + +config SME + bool + default y + +config NO_CONFIG_WRITE + bool + default y + +config NO_CONFIG_BLOBS + bool + default y + +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 if WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + +config NO_PBKDF2 + bool + default y + +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 + +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 000000000000000..3b78940a4f50052 --- /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 000000000000000..9be68e59d6e9860 --- /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 000000000000000..3fd6c2cb7005990 --- /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 000000000000000..41e64d57f54235c --- /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 000000000000000..34b91b65ed6b60f --- /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 000000000000000..24d9796d276a02a --- /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 000000000000000..2a61d274e33bec0 --- /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/liblc3/Kconfig b/modules/liblc3/Kconfig index aaca9d95d7bb4c8..11ce2e34a6c28df 100644 --- a/modules/liblc3/Kconfig +++ b/modules/liblc3/Kconfig @@ -7,5 +7,6 @@ config ZEPHYR_LIBLC3_MODULE config LIBLC3 bool "liblc3 Support" depends on FPU + select REQUIRES_FULL_LIBC help This option enables the Android liblc3 library for Bluetooth LE Audio diff --git a/modules/lvgl/CMakeLists.txt b/modules/lvgl/CMakeLists.txt index 51eb2bd11da7319..a78950e4322a1c7 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 b/modules/lvgl/Kconfig index 9b73705ddb07364..4bd00b1bc55cd65 100644 --- a/modules/lvgl/Kconfig +++ b/modules/lvgl/Kconfig @@ -22,6 +22,36 @@ config LV_CONF_SKIP bool default n +config LV_USE_LOG + bool + +config LV_LOG_LEVEL_NONE + bool + +config LV_LOG_LEVEL_ERROR + bool + +config LV_LOG_LEVEL_WARN + bool + +config LV_LOG_LEVEL_INFO + bool + +config LV_LOG_LEVEL_USER + bool + +config LV_LOG_LEVEL_TRACE + bool + +config LV_Z_LOG_LEVEL + int + default 0 if LV_LOG_LEVEL_NONE || !LV_USE_LOG + default 1 if LV_LOG_LEVEL_ERROR + default 2 if LV_LOG_LEVEL_WARN + default 3 if LV_LOG_LEVEL_INFO + default 3 if LV_LOG_LEVEL_USER + default 4 if LV_LOG_LEVEL_TRACE + config APP_LINK_WITH_LVGL bool "Link 'app' with LVGL" default y diff --git a/modules/lvgl/Kconfig.input b/modules/lvgl/Kconfig.input index b6cbdad0c283b80..4f76643aa8645c4 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 efd74540466789a..6cb1b197d9df3c4 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. @@ -40,6 +41,7 @@ config LV_Z_MEM_POOL_SIZE config LV_Z_VDB_SIZE int "Rendering buffer size" + default 100 if LV_Z_FULL_REFRESH default 10 range 1 100 help diff --git a/modules/lvgl/include/lvgl_keypad_input.h b/modules/lvgl/include/lvgl_keypad_input.h new file mode 100644 index 000000000000000..f1d6e925f1242ee --- /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_button_input.c b/modules/lvgl/input/lvgl_button_input.c index f9c9d59f4d53655..8ac96b7fed53213 100644 --- a/modules/lvgl/input/lvgl_button_input.c +++ b/modules/lvgl/input/lvgl_button_input.c @@ -11,7 +11,7 @@ #include -LOG_MODULE_DECLARE(lvgl); +LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL); struct lvgl_button_input_config { struct lvgl_common_input_config common_config; /* Needs to be first member */ diff --git a/modules/lvgl/input/lvgl_common_input.c b/modules/lvgl/input/lvgl_common_input.c index f91b01bacd38ac5..2f2e1d32bd1abc7 100644 --- a/modules/lvgl/input/lvgl_common_input.c +++ b/modules/lvgl/input/lvgl_common_input.c @@ -12,8 +12,9 @@ #include "lvgl_pointer_input.h" #include "lvgl_button_input.h" #include "lvgl_encoder_input.h" +#include "lvgl_keypad_input.h" -LOG_MODULE_DECLARE(lvgl); +LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL); lv_indev_t *lvgl_input_get_indev(const struct device *dev) { @@ -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_encoder_input.c b/modules/lvgl/input/lvgl_encoder_input.c index a49f1eeca299e36..b68ca67b87149e2 100644 --- a/modules/lvgl/input/lvgl_encoder_input.c +++ b/modules/lvgl/input/lvgl_encoder_input.c @@ -11,7 +11,7 @@ #include -LOG_MODULE_DECLARE(lvgl); +LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL); struct lvgl_encoder_input_config { struct lvgl_common_input_config common_config; /* Needs to be first member */ diff --git a/modules/lvgl/input/lvgl_keypad_input.c b/modules/lvgl/input/lvgl_keypad_input.c new file mode 100644 index 000000000000000..08fd8a37a4ec63d --- /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/lvgl/input/lvgl_pointer_input.c b/modules/lvgl/input/lvgl_pointer_input.c index 19c71eb197217d4..1abfd69d29ac460 100644 --- a/modules/lvgl/input/lvgl_pointer_input.c +++ b/modules/lvgl/input/lvgl_pointer_input.c @@ -12,7 +12,7 @@ #include #include -LOG_MODULE_DECLARE(lvgl); +LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL); struct lvgl_pointer_input_config { struct lvgl_common_input_config common_config; /* Needs to be first member */ diff --git a/modules/lvgl/input/lvgl_pointer_kscan.c b/modules/lvgl/input/lvgl_pointer_kscan.c index 197106e4f2c3a5b..43c309349ed755f 100644 --- a/modules/lvgl/input/lvgl_pointer_kscan.c +++ b/modules/lvgl/input/lvgl_pointer_kscan.c @@ -10,7 +10,7 @@ #include "lvgl_display.h" #include -LOG_MODULE_DECLARE(lvgl); +LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL); static lv_indev_drv_t indev_drv; #define KSCAN_NODE DT_CHOSEN(zephyr_keyboard_scan) diff --git a/modules/lvgl/lvgl.c b/modules/lvgl/lvgl.c index 0f4c24e9a34f257..76df359e7fc7361 100644 --- a/modules/lvgl/lvgl.c +++ b/modules/lvgl/lvgl.c @@ -17,9 +17,8 @@ #endif #include LV_MEM_CUSTOM_INCLUDE -#define LOG_LEVEL CONFIG_LV_LOG_LEVEL #include -LOG_MODULE_REGISTER(lvgl); +LOG_MODULE_REGISTER(lvgl, CONFIG_LV_Z_LOG_LEVEL); static lv_disp_drv_t disp_drv; struct lvgl_disp_data disp_data = { @@ -61,7 +60,7 @@ static uint8_t buf1[BUFFER_SIZE] #endif /* CONFIG_LV_Z_BUFFER_ALLOC_STATIC */ -#if CONFIG_LV_LOG_LEVEL != 0 +#if CONFIG_LV_Z_LOG_LEVEL != 0 /* * In LVGLv8 the signature of the logging callback has changes and it no longer * takes the log level as an integer argument. Instead, the log level is now @@ -83,7 +82,7 @@ static void lvgl_log(const char *buf) LOG_ERR("%s", buf + strlen("[Error] ")); break; case 'W': - LOG_WRN("%s", buf + strlen("Warn] ")); + LOG_WRN("%s", buf + strlen("[Warn] ")); break; case 'I': LOG_INF("%s", buf + strlen("[Info] ")); @@ -91,6 +90,9 @@ static void lvgl_log(const char *buf) case 'T': LOG_DBG("%s", buf + strlen("[Trace] ")); break; + case 'U': + LOG_INF("%s", buf + strlen("[User] ")); + break; } } #endif @@ -207,7 +209,7 @@ static int lvgl_init(void) lvgl_heap_init(); #endif -#if CONFIG_LV_LOG_LEVEL != 0 +#if CONFIG_LV_Z_LOG_LEVEL != 0 lv_log_register_print_cb(lvgl_log); #endif diff --git a/modules/mbedtls/CMakeLists.txt b/modules/mbedtls/CMakeLists.txt index f061605c0270f4b..929ea17eceae7b8 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/psa_util.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ripemd160.c @@ -86,6 +91,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 ) @@ -107,11 +113,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 @@ -119,11 +125,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/configs/config-mini-tls1_1.h b/modules/mbedtls/configs/config-mini-tls1_1.h index 2bce8647caf22d0..da8bf795c1d828c 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 b5295bf1fb7b01d..b3406a394b4284b 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 6f2cc963bd1404c..7468f7633580b9f 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 7cf85731c857c02..59d98f650675e9d 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,19 +487,4 @@ #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 - #endif /* MBEDTLS_CONFIG_H */ diff --git a/modules/mbedtls/zephyr_init.c b/modules/mbedtls/zephyr_init.c index d882b0aedb8f65f..28a6a40fdc5451a 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 ddcdb5f61d195c5..5158090aae92583 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/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 826d9b3159057a8..5b64d3be2f5f37c 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -3,10 +3,19 @@ if(CONFIG_OPENTHREAD_SOURCES) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +macro(kconfig_to_ot_option kconfig_option ot_config description) + if(${kconfig_option}) + set(${ot_config} ON CACHE BOOL "${description}" FORCE) + else() + set(${ot_config} OFF CACHE BOOL "${description}" FORCE) + endif() +endmacro() + # OpenThread options set(OT_BUILD_EXECUTABLES OFF CACHE BOOL "Disable OpenThread samples") set(OT_BUILTIN_MBEDTLS_MANAGEMENT OFF CACHE BOOL "Use Zephyr's mbedTLS heap") set(OT_PLATFORM "zephyr" CACHE STRING "Zephyr as a target platform") +set(OT_PLATFORM_POWER_CALIBRATION OFF CACHE BOOL "Use Zephyr's power calibration handled by Radio Driver") set(OT_THREAD_VERSION ${CONFIG_OPENTHREAD_THREAD_VERSION} CACHE STRING "User selected Thread stack version") set(OT_CLI_TRANSPORT "CONSOLE" CACHE STRING "Set CLI to use console interpreter") @@ -28,470 +37,96 @@ elseif(CONFIG_OPENTHREAD_MTD) set(OT_MTD ON CACHE BOOL "Enable MTD" FORCE) endif() -if(CONFIG_OPENTHREAD_ANYCAST_LOCATOR) - set(OT_ANYCAST_LOCATOR ON CACHE BOOL "Enable anycast locator" FORCE) -else() - set(OT_ANYCAST_LOCATOR OFF CACHE BOOL "Enable anycast locator" FORCE) -endif() - -if(CONFIG_ASSERT) - set(OT_ASSERT ON CACHE BOOL "Enable assert function OT_ASSERT()" FORCE) -else() - set(OT_ASSERT OFF CACHE BOOL "Enable assert function OT_ASSERT()" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BACKBONE_ROUTER) - set(OT_BACKBONE_ROUTER ON CACHE BOOL "Enable backbone router functionality" FORCE) -else() - set(OT_BACKBONE_ROUTER OFF CACHE BOOL "Enable backbone router functionality" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BACKBONE_ROUTER_DUA_NDPROXYING) - set(OT_BACKBONE_ROUTER_DUA_NDPROXYING ON CACHE BOOL "Enable BBR DUA ND Proxy support" FORCE) -else() - set(OT_BACKBONE_ROUTER_DUA_NDPROXYING OFF CACHE BOOL "Enable BBR DUA ND Proxy support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BACKBONE_ROUTER_MULTICAST_ROUTING) - set(OT_BACKBONE_ROUTER_MULTICAST_ROUTING ON CACHE BOOL "Enable BBR MR support" FORCE) -else() - set(OT_BACKBONE_ROUTER_MULTICAST_ROUTING OFF CACHE BOOL "Enable BBR MR support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BORDER_AGENT) - set(OT_BORDER_AGENT ON CACHE BOOL "Enable Border Agent" FORCE) -else() - set(OT_BORDER_AGENT OFF CACHE BOOL "Enable Border Agent" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BORDER_ROUTER) - set(OT_BORDER_ROUTER ON CACHE BOOL "Enable Border Router" FORCE) -else() - set(OT_BORDER_ROUTER OFF CACHE BOOL "Enable Border Router" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BORDER_ROUTING) - set(OT_BORDER_ROUTING ON CACHE BOOL "Enable Border routing" FORCE) -else() - set(OT_BORDER_ROUTING OFF CACHE BOOL "Enable Border routing" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BORDER_ROUTING_COUNTERS) - set(OT_BORDER_ROUTING_COUNTERS ON CACHE BOOL "Enable Border routing counters" FORCE) -else() - set(OT_BORDER_ROUTING_COUNTERS OFF CACHE BOOL "Enable Border routing counters" FORCE) -endif() - -if(CONFIG_OPENTHREAD_BORDER_ROUTING_DHCP6_PD) - set(OT_BORDER_ROUTING_DHCP6_PD ON CACHE BOOL "DHCPv6-PD support in border routing" FORCE) -else() - set(OT_BORDER_ROUTING_DHCP6_PD OFF CACHE BOOL "DHCPv6-PD support in border routing" FORCE) -endif() - -if(CONFIG_OPENTHREAD_CHANNEL_MANAGER) - set(OT_CHANNEL_MANAGER ON CACHE BOOL "Enable channel manager support" FORCE) -else() - set(OT_CHANNEL_MANAGER OFF CACHE BOOL "Enable channel manager support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_CHANNEL_MONITOR) - set(OT_CHANNEL_MONITOR ON CACHE BOOL "Enable channel monitor support" FORCE) -else() - set(OT_CHANNEL_MONITOR OFF CACHE BOOL "Enable channel monitor support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_COAP) - set(OT_COAP ON CACHE BOOL "Enable CoAP API" FORCE) -else() - set(OT_COAP OFF CACHE BOOL "Enable CoAP API" FORCE) -endif() - -if(CONFIG_OPENTHREAD_COAP_BLOCK) - set(OT_COAP_BLOCK ON CACHE BOOL "Enable CoAP Block-wise option support" FORCE) -else() - set(OT_COAP_BLOCK OFF CACHE BOOL "Enable CoAP Block-wise option support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_COAP_OBSERVE) - set(OT_COAP_OBSERVE ON CACHE BOOL "Enable CoAP Observe option support" FORCE) -else() - set(OT_COAP_OBSERVE OFF CACHE BOOL "Enable CoAP Observe option support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_COAPS) - set(OT_COAPS ON CACHE BOOL "Enable secure CoAP API support" FORCE) -else() - set(OT_COAPS OFF CACHE BOOL "Enable secure CoAP API support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_COMMISSIONER) - set(OT_COMMISSIONER ON CACHE BOOL "Enable Commissioner" FORCE) -else() - set(OT_COMMISSIONER OFF CACHE BOOL "Enable Commissioner" FORCE) -endif() - -if(CONFIG_OPENTHREAD_CSL_AUTO_SYNC) - set(OT_CSL_AUTO_SYNC ON CACHE BOOL "Enable csl autosync" FORCE) -else() - set(OT_CSL_AUTO_SYNC OFF CACHE BOOL "Enable csl autosync" FORCE) -endif() - -if(CONFIG_OPENTHREAD_CSL_DEBUG) - set(OT_CSL_DEBUG ON CACHE BOOL "Enable CSL debug" FORCE) -else() - set(OT_CSL_DEBUG OFF CACHE BOOL "Enable CSL debug" FORCE) -endif() - -if(CONFIG_OPENTHREAD_CSL_RECEIVER) - set(OT_CSL_RECEIVER ON CACHE BOOL "Enable CSL receiver feature for Thread 1.2" FORCE) -else() - set(OT_CSL_RECEIVER OFF CACHE BOOL "Enable CSL receiver feature for Thread 1.2" FORCE) -endif() +kconfig_to_ot_option(CONFIG_OPENTHREAD_ANYCAST_LOCATOR OT_ANYCAST_LOCATOR "Enable anycast locator") +kconfig_to_ot_option(CONFIG_ASSERT OT_ASSERT "Enable assert function OT_ASSERT()") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BACKBONE_ROUTER OT_BACKBONE_ROUTER "Enable backbone router functionality") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BACKBONE_ROUTER_DUA_NDPROXYING OT_BACKBONE_ROUTER_DUA_NDPROXYING "Enable BBR DUA ND Proxy support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BACKBONE_ROUTER_MULTICAST_ROUTING OT_BACKBONE_ROUTER_MULTICAST_ROUTING "Enable BBR MR support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BLE_TCAT OT_BLE_TCAT "Enable BLE TCAT support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_AGENT OT_BORDER_AGENT "Enable Border Agent") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_ROUTER OT_BORDER_ROUTER "Enable Border Router") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_ROUTING OT_BORDER_ROUTING "Enable Border routing") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_ROUTING_COUNTERS OT_BORDER_ROUTING_COUNTERS "Enable Border routing counters") +kconfig_to_ot_option(CONFIG_OPENTHREAD_BORDER_ROUTING_DHCP6_PD OT_BORDER_ROUTING_DHCP6_PD "DHCPv6-PD support in border routing") +kconfig_to_ot_option(CONFIG_OPENTHREAD_CHANNEL_MANAGER OT_CHANNEL_MANAGER "Enable channel manager support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_CHANNEL_MONITOR OT_CHANNEL_MONITOR "Enable channel monitor support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_COAP OT_COAP "Enable CoAP API") +kconfig_to_ot_option(CONFIG_OPENTHREAD_COAP_BLOCK OT_COAP_BLOCK "Enable CoAP Block-wise option support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_COAP_OBSERVE OT_COAP_OBSERVE "Enable CoAP Observe option support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_COAPS OT_COAPS "Enable secure CoAP API support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_COMMISSIONER OT_COMMISSIONER "Enable Commissioner") +kconfig_to_ot_option(CONFIG_OPENTHREAD_CSL_AUTO_SYNC OT_CSL_AUTO_SYNC "Enable csl autosync") +kconfig_to_ot_option(CONFIG_OPENTHREAD_CSL_DEBUG OT_CSL_DEBUG "Enable CSL debug") +kconfig_to_ot_option(CONFIG_OPENTHREAD_CSL_RECEIVER OT_CSL_RECEIVER "Enable CSL receiver feature for Thread 1.2") +kconfig_to_ot_option(CONFIG_OPENTHREAD_CSL_RECEIVER_LOCAL_TIME_SYNC OT_CSL_RECEIVER_LOCAL_TIME_SYNC "Use local time for CSL sync") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DATASET_UPDATER OT_DATASET_UPDATER "Enable Dataset updater") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DEVICE_PROP_LEADER_WEIGHT OT_DEVICE_PROP_LEADER_WEIGHT "Enable device props for leader weight") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DHCP6_CLIENT OT_DHCP6_CLIENT "Enable DHCPv6 Client") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DHCP6_SERVER OT_DHCP6_SERVER "Enable DHCPv6 Server") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DIAG OT_DIAGNOSTIC "Enable Diagnostics support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DNS_CLIENT OT_DNS_CLIENT "Enable DNS client support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DNS_CLIENT_OVER_TCP OT_DNS_CLIENT_OVER_TCP "Enable dns query over tcp") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DNS_DSO OT_DNS_DSO "Enable DNS Stateful Operations (DSO) support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DNS_UPSTREAM_QUERY OT_DNS_UPSTREAM_QUERY "Enable forwarding DNS queries to upstream") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DNSSD_SERVER OT_DNSSD_SERVER "Enable DNS-SD server support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_DUA OT_DUA "Enable Domain Unicast Address feature for Thread 1.2") +kconfig_to_ot_option(CONFIG_OPENTHREAD_ECDSA OT_ECDSA "Enable ECDSA support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_ENABLE_SERVICE OT_SERVICE "Enable Service entries in Thread Network Data") +kconfig_to_ot_option(CONFIG_OPENTHREAD_EXTERNAL_HEAP OT_EXTERNAL_HEAP "Enable external heap support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_FIREWALL OT_FIREWALL "Enable firewall") +kconfig_to_ot_option(CONFIG_OPENTHREAD_FULL_LOGS OT_FULL_LOGS "Enable full logs") +kconfig_to_ot_option(CONFIG_OPENTHREAD_HISTORY_TRACKER OT_HISTORY_TRACKER "Enable history tracker support.") +kconfig_to_ot_option(CONFIG_OPENTHREAD_IP6_FRAGM OT_IP6_FRAGM "Enable IPv6 fragmentation support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_JAM_DETECTION OT_JAM_DETECTION "Enable Jam Detection") +kconfig_to_ot_option(CONFIG_OPENTHREAD_JOINER OT_JOINER "Enable Joiner") +kconfig_to_ot_option(CONFIG_OPENTHREAD_LEGACY OT_LEGACY "Enable legacy network support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_LINK_METRICS_INITIATOR OT_LINK_METRICS_INITIATOR "Enable Link Metrics initiator for Thread 1.2") +kconfig_to_ot_option(CONFIG_OPENTHREAD_LINK_METRICS_MANAGER OT_LINK_METRICS_MANAGER "Enable Link Metrics manager for Thread 1.2") +kconfig_to_ot_option(CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT OT_LINK_METRICS_SUBJECT "Enable Link Metrics subject for Thread 1.2") +kconfig_to_ot_option(CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC OT_LOG_LEVEL_DYNAMIC "Enable dynamic log level control") +kconfig_to_ot_option(CONFIG_OPENTHREAD_MAC_FILTER OT_MAC_FILTER "Enable MAC filter support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_MESH_DIAG OT_MESH_DIAG "Enable Mesh Diagnostics") +kconfig_to_ot_option(CONFIG_OPENTHREAD_MESSAGE_USE_HEAP OT_MESSAGE_USE_HEAP "Enable heap allocator for message buffers") +kconfig_to_ot_option(CONFIG_OPENTHREAD_MLE_LONG_ROUTES OT_MLE_LONG_ROUTES "Enable MLE long routes support (Experimental)") +kconfig_to_ot_option(CONFIG_OPENTHREAD_MLR OT_MLR "Enable Multicast Listener Registration feature for Thread 1.2") +kconfig_to_ot_option(CONFIG_OPENTHREAD_MULTIPAN_RCP OT_MULTIPAN_RCP "Enable Multi-PAN RCP") +kconfig_to_ot_option(CONFIG_OPENTHREAD_MULTIPLE_INSTANCE OT_MULTIPLE_INSTANCE "Enable multiple instances") +kconfig_to_ot_option(CONFIG_OPENTHREAD_NAT64_BORDER_ROUTING OT_NAT64_BORDER_ROUTING "Enable border routing NAT64 support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_NAT64_TRANSLATOR OT_NAT64_TRANSLATOR "Enable NAT64 translator") +kconfig_to_ot_option(CONFIG_OPENTHREAD_NEIGHBOR_DISCOVERY_AGENT OT_NEIGHBOR_DISCOVERY_AGENT "Enable neighbor discovery agent support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_NETDIAG_CLIENT OT_NETDIAG_CLIENT "Enable TMF network diagnostics on clients") +kconfig_to_ot_option(CONFIG_OPENTHREAD_NETDATA_PUBLISHER OT_NETDATA_PUBLISHER "Enable Thread Network Data publisher") +kconfig_to_ot_option(CONFIG_OPENTHREAD_OPERATIONAL_DATASET_AUTO_INIT OT_OPERATIONAL_DATASET_AUTO_INIT "Enable operational dataset auto init") +kconfig_to_ot_option(CONFIG_OPENTHREAD_OTNS OT_OTNS "Enable OTNS support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_PING_SENDER OT_PING_SENDER "Enable ping sender support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE OT_PLATFORM_BOOTLOADER_MODE "Enable platform bootloader mode support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_KEY_REF OT_PLATFORM_KEY_REF "Enable platform key reference support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_NETIF OT_PLATFORM_NETIF "Enable platform netif support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_PLATFORM_UDP OT_PLATFORM_UDP "Enable platform UDP support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_RADIO_LINK_IEEE_802_15_4_ENABLE OT_15_4 "Enable 802.15.4 radio") +kconfig_to_ot_option(CONFIG_OPENTHREAD_RAW OT_LINK_RAW "Enable Link Raw") +kconfig_to_ot_option(CONFIG_OPENTHREAD_REFERENCE_DEVICE OT_REFERENCE_DEVICE "Enable Thread Certification Reference Device") +kconfig_to_ot_option(CONFIG_OPENTHREAD_SETTINGS_RAM OT_SETTINGS_RAM "Enable volatile-only storage of settings") +kconfig_to_ot_option(CONFIG_OPENTHREAD_SLAAC OT_SLAAC "Enable SLAAC") +kconfig_to_ot_option(CONFIG_OPENTHREAD_SNTP_CLIENT OT_SNTP_CLIENT "Enable SNTP Client support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_SRP_CLIENT OT_SRP_CLIENT "Enable SRP Client support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_SRP_SERVER OT_SRP_SERVER "Enable SRP Server support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_TCP_ENABLE OT_TCP "Enable TCP support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_TIME_SYNC OT_TIME_SYNC "Enable the time synchronization service feature") +kconfig_to_ot_option(CONFIG_OPENTHREAD_TREL OT_TREL "Enable TREL radio link for Thread over Infrastructure feature") +kconfig_to_ot_option(CONFIG_OPENTHREAD_TX_BEACON_PAYLOAD OT_TX_BEACON_PAYLOAD "Enable tx beacon payload support") +kconfig_to_ot_option(CONFIG_OPENTHREAD_TX_QUEUE_STATISTICS OT_TX_QUEUE_STATS "Enable tx queue statistics") +kconfig_to_ot_option(CONFIG_OPENTHREAD_UDP_FORWARD OT_UDP_FORWARD "Enable UDP forward feature") +kconfig_to_ot_option(CONFIG_OPENTHREAD_UPTIME OT_UPTIME "Enable support for tracking OpenThread instance's uptime") -if(CONFIG_OPENTHREAD_DATASET_UPDATER) - set(OT_DATASET_UPDATER ON CACHE BOOL "Enable Dataset updater" FORCE) -else() - set(OT_DATASET_UPDATER OFF CACHE BOOL "Enable Dataset updater" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DEVICE_PROP_LEADER_WEIGHT) - set(OT_DEVICE_PROP_LEADER_WEIGHT ON CACHE BOOL "Enable device props for leader weight" FORCE) -else() - set(OT_DEVICE_PROP_LEADER_WEIGHT OFF CACHE BOOL "Enable device props for leader weight" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DHCP6_CLIENT) - set(OT_DHCP6_CLIENT ON CACHE BOOL "Enable DHCPv6 Client" FORCE) -else() - set(OT_DHCP6_CLIENT OFF CACHE BOOL "Enable DHCPv6 Client" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DHCP6_SERVER) - set(OT_DHCP6_SERVER ON CACHE BOOL "Enable DHCPv6 Server" FORCE) -else() - set(OT_DHCP6_SERVER OFF CACHE BOOL "Enable DHCPv6 Server" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DIAG) - set(OT_DIAGNOSTIC ON CACHE BOOL "Enable Diagnostics support" FORCE) -else() - set(OT_DIAGNOSTIC OFF CACHE BOOL "Enable Diagnostics support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DNS_CLIENT) - set(OT_DNS_CLIENT ON CACHE BOOL "Enable DNS client support" FORCE) -else() - set(OT_DNS_CLIENT OFF CACHE BOOL "Enable DNS client support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DNS_CLIENT_OVER_TCP) - set(OT_DNS_CLIENT_OVER_TCP ON CACHE BOOL "Enable dns query over tcp" FORCE) -else() - set(OT_DNS_CLIENT_OVER_TCP OFF CACHE BOOL "Enable dns query over tcp" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DNS_DSO) - set(OT_DNS_DSO ON CACHE BOOL "Enable DNS Stateful Operations (DSO) support" FORCE) -else() - set(OT_DNS_DSO OFF CACHE BOOL "Enable DNS Stateful Operations (DSO) support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DNS_UPSTREAM_QUERY) - set(OT_DNS_UPSTREAM_QUERY ON CACHE BOOL "Enable forwarding DNS queries to upstream" FORCE) -else() - set(OT_DNS_UPSTREAM_QUERY OFF CACHE BOOL "Enable forwarding DNS queries to upstream" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DNSSD_SERVER) - set(OT_DNSSD_SERVER ON CACHE BOOL "Enable DNS-SD server support" FORCE) -else() - set(OT_DNSSD_SERVER OFF CACHE BOOL "Enable DNS-SD server support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_DUA) - set(OT_DUA ON CACHE BOOL "Enable Domain Unicast Address feature for Thread 1.2" FORCE) -else() - set(OT_DUA OFF CACHE BOOL "Enable Domain Unicast Address feature for Thread 1.2" FORCE) -endif() - -if(CONFIG_OPENTHREAD_ECDSA) - set(OT_ECDSA ON CACHE BOOL "Enable ECDSA support" FORCE) -else() - set(OT_ECDSA OFF CACHE BOOL "Enable ECDSA support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_ENABLE_SERVICE) - set(OT_SERVICE ON CACHE BOOL "Enable Service entries in Thread Network Data" FORCE) -else() - set(OT_SERVICE OFF CACHE BOOL "Enable Service entries in Thread Network Data" FORCE) -endif() - -if(CONFIG_OPENTHREAD_EXTERNAL_HEAP) - set(OT_EXTERNAL_HEAP ON CACHE BOOL "Enable external heap support" FORCE) -else() - set(OT_EXTERNAL_HEAP OFF CACHE BOOL "Enable external heap support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_FIREWALL) - set(OT_FIREWALL ON CACHE BOOL "Enable firewall" FORCE) -else() - set(OT_FIREWALL OFF CACHE BOOL "Enable firewall" FORCE) -endif() - -if(CONFIG_OPENTHREAD_FULL_LOGS) - set(OT_FULL_LOGS ON CACHE BOOL "Enable full logs" FORCE) -else() - set(OT_FULL_LOGS OFF CACHE BOOL "Enable full logs" FORCE) -endif() - -if(CONFIG_OPENTHREAD_HISTORY_TRACKER) - set(OT_HISTORY_TRACKER ON CACHE BOOL "Enable history tracker support." FORCE) -else() - set(OT_HISTORY_TRACKER OFF CACHE BOOL "Enable history tracker support." FORCE) -endif() - -if(CONFIG_OPENTHREAD_IP6_FRAGM) - set(OT_IP6_FRAGM ON CACHE BOOL "Enable IPv6 fragmentation support" FORCE) -else() - set(OT_IP6_FRAGM OFF CACHE BOOL "Enable IPv6 fragmentation support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_JAM_DETECTION) - set(OT_JAM_DETECTION ON CACHE BOOL "Enable Jam Detection" FORCE) -else() - set(OT_JAM_DETECTION OFF CACHE BOOL "Enable Jam Detection" FORCE) -endif() - -if(CONFIG_OPENTHREAD_JOINER) - set(OT_JOINER ON CACHE BOOL "Enable Joiner" FORCE) -else() - set(OT_JOINER OFF CACHE BOOL "Enable Joiner" FORCE) -endif() - -if(CONFIG_OPENTHREAD_LEGACY) - set(OT_LEGACY ON CACHE BOOL "Enable legacy network support" FORCE) -else() - set(OT_LEGACY OFF CACHE BOOL "Enable legacy network support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_LINK_METRICS_INITIATOR) - set(OT_LINK_METRICS_INITIATOR ON CACHE BOOL "Enable Link Metrics initiator for Thread 1.2" FORCE) -else() - set(OT_LINK_METRICS_INITIATOR OFF CACHE BOOL "Enable Link Metrics initiator for Thread 1.2" FORCE) -endif() - -if(CONFIG_OPENTHREAD_LINK_METRICS_MANAGER) - set(OT_LINK_METRICS_MANAGER ON CACHE BOOL "Enable Link Metrics manager for Thread 1.2" FORCE) -else() - set(OT_LINK_METRICS_MANAGER OFF CACHE BOOL "Enable Link Metrics manager for Thread 1.2" FORCE) -endif() - -if(CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT) - set(OT_LINK_METRICS_SUBJECT ON CACHE BOOL "Enable Link Metrics subject for Thread 1.2" FORCE) -else() - set(OT_LINK_METRICS_SUBJECT OFF CACHE BOOL "Enable Link Metrics subject for Thread 1.2" FORCE) -endif() - -if(CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC) - set(OT_LOG_LEVEL_DYNAMIC ON CACHE BOOL "Enable dynamic log level control" FORCE) -else() - set(OT_LOG_LEVEL_DYNAMIC OFF CACHE BOOL "Enable dynamic log level control" FORCE) -endif() - -if(CONFIG_OPENTHREAD_MAC_FILTER) - set(OT_MAC_FILTER ON CACHE BOOL "Enable MAC filter support" FORCE) -else() - set(OT_MAC_FILTER OFF CACHE BOOL "Enable MAC filter support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_MESH_DIAG) - set(OT_MESH_DIAG ON CACHE BOOL "Enable Mesh Diagnostics" FORCE) -else() - set(OT_MESH_DIAG OFF CACHE BOOL "Enable Mesh Diagnostics" FORCE) -endif() - -if(CONFIG_OPENTHREAD_MESSAGE_USE_HEAP) - set(OT_MESSAGE_USE_HEAP ON CACHE BOOL "Enable heap allocator for message buffers" FORCE) -else() - set(OT_MESSAGE_USE_HEAP OFF CACHE BOOL "Enable heap allocator for message buffers" FORCE) -endif() - -if(CONFIG_OPENTHREAD_MLE_LONG_ROUTES) - set(OT_MLE_LONG_ROUTES ON CACHE BOOL "Enable MLE long routes support (Experimental)" FORCE) -else() - set(OT_MLE_LONG_ROUTES OFF CACHE BOOL "Enable MLE long routes support (Experimental)" FORCE) -endif() - -if(CONFIG_OPENTHREAD_MLR) - set(OT_MLR ON CACHE BOOL "Enable Multicast Listener Registration feature for Thread 1.2" FORCE) -else() - set(OT_MLR OFF CACHE BOOL "Enable Multicast Listener Registration feature for Thread 1.2" FORCE) -endif() - -if(CONFIG_OPENTHREAD_MULTIPLE_INSTANCE) - set(OT_MULTIPLE_INSTANCE ON CACHE BOOL "Enable multiple instances" FORCE) -else() - set(OT_MULTIPLE_INSTANCE OFF CACHE BOOL "Enable multiple instances" FORCE) -endif() - -if(CONFIG_OPENTHREAD_NAT64_BORDER_ROUTING) - set(OT_NAT64_BORDER_ROUTING ON CACHE BOOL "Enable border routing NAT64 support" FORCE) -else() - set(OT_NAT64_BORDER_ROUTING OFF CACHE BOOL "Enable border routing NAT64 support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_NAT64_TRANSLATOR) - set(OT_NAT64_TRANSLATOR ON CACHE BOOL "Enable NAT64 translator" FORCE) -else() - set(OT_NAT64_TRANSLATOR OFF CACHE BOOL "Enable NAT64 translator" FORCE) -endif() - -if(CONFIG_OPENTHREAD_NEIGHBOR_DISCOVERY_AGENT) - set(OT_NEIGHBOR_DISCOVERY_AGENT ON CACHE BOOL "Enable neighbor discovery agent support" FORCE) -else() - set(OT_NEIGHBOR_DISCOVERY_AGENT OFF CACHE BOOL "Enable neighbor discovery agent support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_NETDIAG_CLIENT) - set(OT_NETDIAG_CLIENT ON CACHE BOOL "Enable TMF network diagnostics on clients" FORCE) -else() - set(OT_NETDIAG_CLIENT OFF CACHE BOOL "Enable TMF network diagnostics on clients" FORCE) -endif() - -if(CONFIG_OPENTHREAD_NETDATA_PUBLISHER) - set(OT_NETDATA_PUBLISHER ON CACHE BOOL "Enable Thread Network Data publisher" FORCE) -else() - set(OT_NETDATA_PUBLISHER OFF CACHE BOOL "Enable Thread Network Data publisher" FORCE) -endif() - -if(CONFIG_OPENTHREAD_OPERATIONAL_DATASET_AUTO_INIT) - set(OT_OPERATIONAL_DATASET_AUTO_INIT ON CACHE BOOL "Enable operational dataset auto init" FORCE) -else() - set(OT_OPERATIONAL_DATASET_AUTO_INIT OFF CACHE BOOL "Enable operational dataset auto init" FORCE) -endif() - -if(CONFIG_OPENTHREAD_OTNS) - set(OT_OTNS ON CACHE BOOL "Enable OTNS support" FORCE) -else() - set(OT_OTNS OFF CACHE BOOL "Enable OTNS support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_PING_SENDER) - set(OT_PING_SENDER ON CACHE BOOL "Enable ping sender support" FORCE) -else() - set(OT_PING_SENDER OFF CACHE BOOL "Enable ping sender support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_PLATFORM_NETIF) - set(OT_PLATFORM_NETIF ON CACHE BOOL "Enable platform netif support" FORCE) -else() - set(OT_PLATFORM_NETIF OFF CACHE BOOL "Enable platform netif support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_PLATFORM_UDP) - set(OT_PLATFORM_UDP ON CACHE BOOL "Enable platform UDP support" FORCE) -else() - set(OT_PLATFORM_UDP OFF CACHE BOOL "Enable platform UDP support" FORCE) +if(CONFIG_OPENTHREAD_COPROCESSOR_VENDOR_HOOK_SOURCE) + set(OT_NCP_VENDOR_HOOK_SOURCE ${CONFIG_OPENTHREAD_COPROCESSOR_VENDOR_HOOK_SOURCE} CACHE STRING "NCP vendor hook source file name" FORCE) endif() if(CONFIG_OPENTHREAD_POWER_SUPPLY) set(OT_POWER_SUPPLY ${CONFIG_OPENTHREAD_POWER_SUPPLY} CACHE STRING "Power supply configuration" FORCE) endif() -if(CONFIG_OPENTHREAD_RADIO_LINK_IEEE_802_15_4_ENABLE) - set(OT_15_4 ON CACHE BOOL "Enable 802.15.4 radio" FORCE) -else() - set(OT_15_4 OFF CACHE BOOL "Enable 802.15.4 radio" FORCE) -endif() - -if(CONFIG_OPENTHREAD_RAW) - set(OT_LINK_RAW ON CACHE BOOL "Enable Link Raw" FORCE) -else() - set(OT_LINK_RAW OFF CACHE BOOL "Enable Link Raw" FORCE) -endif() - -if(CONFIG_OPENTHREAD_REFERENCE_DEVICE) - set(OT_REFERENCE_DEVICE ON CACHE BOOL "Enable Thread Certification Reference Device" FORCE) -else() - set(OT_REFERENCE_DEVICE OFF CACHE BOOL "Enable Thread Certification Reference Device" FORCE) -endif() - -if(CONFIG_OPENTHREAD_SETTINGS_RAM) - set(OT_SETTINGS_RAM ON CACHE BOOL "Enable volatile-only storage of settings" FORCE) -else() - set(OT_SETTINGS_RAM OFF CACHE BOOL "Enable volatile-only storage of settings" FORCE) -endif() - -if(CONFIG_OPENTHREAD_SLAAC) - set(OT_SLAAC ON CACHE BOOL "Enable SLAAC" FORCE) -else() - set(OT_SLAAC OFF CACHE BOOL "Enable SLAAC" FORCE) -endif() - -if(CONFIG_OPENTHREAD_SNTP_CLIENT) - set(OT_SNTP_CLIENT ON CACHE BOOL "Enable SNTP Client support" FORCE) -else() - set(OT_SNTP_CLIENT OFF CACHE BOOL "Enable SNTP Client support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_SRP_CLIENT) - set(OT_SRP_CLIENT ON CACHE BOOL "Enable SRP Client support" FORCE) -else() - set(OT_SRP_CLIENT OFF CACHE BOOL "Enable SRP Client support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_SRP_SERVER) - set(OT_SRP_SERVER ON CACHE BOOL "Enable SRP Server support" FORCE) -else() - set(OT_SRP_SERVER OFF CACHE BOOL "Enable SRP Server support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_TCP_ENABLE) - set(OT_TCP ON CACHE BOOL "Enable TCP support" FORCE) -else() - set(OT_TCP OFF CACHE BOOL "Enable TCP support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_TIME_SYNC) - set(OT_TIME_SYNC ON CACHE BOOL "Enable the time synchronization service feature" FORCE) -else() - set(OT_TIME_SYNC OFF CACHE BOOL "Enable the time synchronization service feature" FORCE) -endif() - -if(CONFIG_OPENTHREAD_TREL) - set(OT_TREL ON CACHE BOOL "Enable TREL radio link for Thread over Infrastructure feature" FORCE) -else() - set(OT_TREL OFF CACHE BOOL "Enable TREL radio link for Thread over Infrastructure feature" FORCE) -endif() - -if(CONFIG_OPENTHREAD_TX_BEACON_PAYLOAD) - set(OT_TX_BEACON_PAYLOAD ON CACHE BOOL "Enable tx beacon payload support" FORCE) -else() - set(OT_TX_BEACON_PAYLOAD OFF CACHE BOOL "Enable tx beacon payload support" FORCE) -endif() - -if(CONFIG_OPENTHREAD_TX_QUEUE_STATISTICS) - set(OT_TX_QUEUE_STATS ON CACHE BOOL "Enable tx queue statistics" FORCE) -else() - set(OT_TX_QUEUE_STATS OFF CACHE BOOL "Enable tx queue statistics" FORCE) -endif() - -if(CONFIG_OPENTHREAD_UDP_FORWARD) - set(OT_UDP_FORWARD ON CACHE BOOL "Enable UDP forward feature" FORCE) -else() - set(OT_UDP_FORWARD OFF CACHE BOOL "Enable UDP forward feature" FORCE) -endif() - -if(CONFIG_OPENTHREAD_UPTIME) - set(OT_UPTIME ON CACHE BOOL "Enable support for tracking OpenThread instance's uptime" FORCE) -else() - set(OT_UPTIME OFF CACHE BOOL "Enable support for tracking OpenThread instance's uptime" FORCE) -endif() - -if(CONFIG_OPENTHREAD_COPROCESSOR_VENDOR_HOOK_SOURCE) - set(OT_NCP_VENDOR_HOOK_SOURCE ${CONFIG_OPENTHREAD_COPROCESSOR_VENDOR_HOOK_SOURCE} CACHE STRING "NCP vendor hook source file name" FORCE) -endif() - set(BUILD_TESTING OFF CACHE BOOL "Disable openthread cmake testing targets" FORCE) # Zephyr logging options @@ -541,7 +176,8 @@ target_compile_definitions(ot-config INTERFACE # libraries do not include this header. So we add the defines to all # OpenThread files through the gcc flag -imacros instead. target_compile_options(ot-config INTERFACE - $ -fno-builtin + $ + $ -imacros ${AUTOCONF_H} ) @@ -594,7 +230,8 @@ endif() if(CONFIG_OPENTHREAD_SETTINGS_RAM) target_compile_options(openthread-platform-utils PRIVATE - $ -fno-builtin) + $ + $) add_dependencies(openthread-platform-utils syscall_list_h_target) list(APPEND ot_libs openthread-platform-utils-static) diff --git a/modules/openthread/Kconfig.features b/modules/openthread/Kconfig.features index 87c220944a49806..ba3990a348d9523 100644 --- a/modules/openthread/Kconfig.features +++ b/modules/openthread/Kconfig.features @@ -17,7 +17,7 @@ config OPENTHREAD_THREAD_VERSION_1_3 bool "Version 1.3" config OPENTHREAD_THREAD_VERSION_1_3_1 bool "Version 1.3.1" -endchoice +endchoice # OPENTHREAD_STACK_VERSION config OPENTHREAD_THREAD_VERSION string @@ -39,6 +39,10 @@ config OPENTHREAD_BACKBONE_ROUTER_DUA_NDPROXYING config OPENTHREAD_BACKBONE_ROUTER_MULTICAST_ROUTING bool "BBR MR support" +config OPENTHREAD_BLE_TCAT + bool "BLE TCAT support" + select EXPERIMENTAL + config OPENTHREAD_BORDER_AGENT bool "Border Agent support" @@ -92,6 +96,13 @@ config OPENTHREAD_CSL_RECEIVER help Enable CSL Receiver support for Thread 1.2 +config OPENTHREAD_CSL_RECEIVER_LOCAL_TIME_SYNC + bool "Use local time for CSL synchronization" + help + Use host time rather than radio platform time to track elapsed time + since last CSL synchronization. This reduces the usage of radio API + calls, and it is useful for platforms in which those are costly. + config OPENTHREAD_DEVICE_PROP_LEADER_WEIGHT bool "Device props for leader weight" default n if (OPENTHREAD_THREAD_VERSION_1_1 || \ @@ -207,6 +218,9 @@ config OPENTHREAD_MLR help Enable Multicast Listener Registration support for Thread 1.2 +config OPENTHREAD_MULTIPAN_RCP + bool "OpenThread multipan rcp" + config OPENTHREAD_MULTIPLE_INSTANCE bool "OpenThread multiple instances" @@ -235,6 +249,31 @@ config OPENTHREAD_OTNS config OPENTHREAD_PING_SENDER bool "Ping sender support" +config OPENTHREAD_PLATFORM_KEY_REF + bool "Platform cryptographic key reference support" + help + Enable usage of cryptographic key references instead of literal keys. + This requires a crypto backend library that supports key references. + +choice OPENTHREAD_PLATFORM_BOOTLOADER_MODE_CHOICE + prompt "Platform bootloader mode configuration" + optional + +config OPENTHREAD_PLATFORM_BOOTLOADER_MODE_RETENTION + bool "Bootloader mode support with boot mode retention API" + depends on RETENTION_BOOT_MODE && REBOOT + select OPENTHREAD_PLATFORM_BOOTLOADER_MODE + +config OPENTHREAD_PLATFORM_BOOTLOADER_MODE_GPIO + bool "Bootloader mode support with GPIO pin trigger" + select OPENTHREAD_PLATFORM_BOOTLOADER_MODE +endchoice # OPENTHREAD_PLATFORM_BOOTLOADER_MODE + +config OPENTHREAD_PLATFORM_BOOTLOADER_MODE + bool + help + Platform bootloader mode support + config OPENTHREAD_PLATFORM_NETIF bool "Platform netif support" @@ -256,7 +295,7 @@ config OPENTHREAD_POWER_SUPPLY_EXTERNAL_STABLE config OPENTHREAD_POWER_SUPPLY_EXTERNAL_UNSTABLE bool "OT_POWER_SUPPLY_EXTERNAL_UNSTABLE" -endchoice +endchoice # OPENTHREAD_POWER_SUPPLY_CHOICE config OPENTHREAD_POWER_SUPPLY string diff --git a/modules/openthread/Kconfig.thread b/modules/openthread/Kconfig.thread index 73c547919a7f9a7..542992e7fa1809c 100644 --- a/modules/openthread/Kconfig.thread +++ b/modules/openthread/Kconfig.thread @@ -68,7 +68,6 @@ config OPENTHREAD_MAX_IP_ADDR_PER_CHILD int "The maximum number of IPv6 address registrations per child" range 4 255 default 6 - depends on OPENTHREAD_FTD config OPENTHREAD_CONFIG_PLATFORM_INFO string "The platform-specific string to insert into the OpenThread version string" @@ -182,3 +181,16 @@ config OPENTHREAD_DEFAULT_TX_POWER default 0 help Set the default TX output power [dBm] in radio driver for OpenThread purpose. + +config OPENTHREAD_BLE_TCAT_THREAD_STACK_SIZE + int "Openthread default TCAT stack size" + default 5120 if OPENTHREAD_CRYPTO_PSA + default 4200 + help + Openthread default TCAT stack size. + +config OPENTHREAD_BLE_TCAT_RING_BUF_SIZE + int "Openthread BLE ringbuffer size" + default 512 + help + Openthread BLE TCAT ringbuffer size. diff --git a/modules/openthread/platform/CMakeLists.txt b/modules/openthread/platform/CMakeLists.txt index d363bcda7dfb889..542aa5186ea2425 100644 --- a/modules/openthread/platform/CMakeLists.txt +++ b/modules/openthread/platform/CMakeLists.txt @@ -10,6 +10,7 @@ zephyr_library_sources( spi.c ) +zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_BLE_TCAT ble.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_DIAG diag.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_COPROCESSOR uart.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_CRYPTO_PSA crypto_psa.c) diff --git a/modules/openthread/platform/ble.c b/modules/openthread/platform/ble.c new file mode 100644 index 000000000000000..7b41556b6173a19 --- /dev/null +++ b/modules/openthread/platform/ble.c @@ -0,0 +1,458 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Zephyr OpenThread integration Library */ +#include + +/* OpenThread BLE driver API */ +#include + +/* Zephyr Logging */ + +#define LOG_MODULE_NAME net_openthread_tcat +#define LOG_LEVEL CONFIG_OPENTHREAD_LOG_LEVEL + +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#define DEVICE_NAME CONFIG_BT_DEVICE_NAME +#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) + +/* BLE connection constants as defined in thread specification. */ +#define TOBLE_SERVICE_UUID 0xfffb +#define RX_CHARACTERISTIC_UUID \ + BT_UUID_128_ENCODE(0x6bd10d8b, 0x85a7, 0x4e5a, 0xba2d, 0xc83558a5f220) +#define TX_CHARACTERISTIC_UUID \ + BT_UUID_128_ENCODE(0x7fddf61f, 0x280a, 0x4773, 0xb448, 0xba1b8fe0dd69) + +#define BT_UUID_TCAT_SERVICE BT_UUID_DECLARE_16(TOBLE_SERVICE_UUID) +#define BT_UUID_TCAT_SERVICE_RX BT_UUID_DECLARE_128(RX_CHARACTERISTIC_UUID) +#define BT_UUID_TCAT_SERVICE_TX BT_UUID_DECLARE_128(TX_CHARACTERISTIC_UUID) + +#define PLAT_BLE_THREAD_DEALY 500 +#define PLAT_BLE_MSG_DATA_MAX CONFIG_BT_L2CAP_TX_MTU /* must match the maximum MTU size used */ + +#define PLAT_BLE_MSG_CONNECT (PLAT_BLE_MSG_DATA_MAX + 1U) +#define PLAT_BLE_MSG_DISCONNECT (PLAT_BLE_MSG_CONNECT + 1U) + +/* Zephyr Kernel Objects */ + +static void ot_plat_ble_thread(void *, void *, void *); +static uint8_t ot_plat_ble_msg_buf[PLAT_BLE_MSG_DATA_MAX]; + +static K_SEM_DEFINE(ot_plat_ble_init_semaphore, 0, 1); +static K_SEM_DEFINE(ot_plat_ble_event_semaphore, 0, K_SEM_MAX_LIMIT); +RING_BUF_DECLARE(ot_plat_ble_ring_buf, CONFIG_OPENTHREAD_BLE_TCAT_RING_BUF_SIZE); +static K_THREAD_DEFINE(ot_plat_ble_tid, CONFIG_OPENTHREAD_BLE_TCAT_THREAD_STACK_SIZE, + ot_plat_ble_thread, NULL, NULL, NULL, 5, 0, PLAT_BLE_THREAD_DEALY); + +/* OpenThread Objects */ + +static otInstance *ble_openthread_instance; + +/* BLE service Objects */ + +/* forward declaration for callback functions */ +static ssize_t on_receive(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, + uint16_t len, uint16_t offset, uint8_t flags); +static void on_cccd_changed(const struct bt_gatt_attr *attr, uint16_t value); + +/* Service Declaration and Registration */ +BT_GATT_SERVICE_DEFINE(my_service, BT_GATT_PRIMARY_SERVICE(BT_UUID_TCAT_SERVICE), + BT_GATT_CHARACTERISTIC(BT_UUID_TCAT_SERVICE_RX, + BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, NULL, + on_receive, NULL), + BT_GATT_CHARACTERISTIC(BT_UUID_TCAT_SERVICE_TX, BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ, NULL, NULL, NULL), + BT_GATT_CCC(on_cccd_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),); + +/* Zephyr BLE Objects */ + +/* forward declaration for callback functions */ +static void connected(struct bt_conn *conn, uint8_t err); +static void disconnected(struct bt_conn *conn, uint8_t reason); +static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param); +static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, + uint16_t timeout); + +static struct bt_conn *ot_plat_ble_connection; + +static struct bt_conn_cb conn_callbacks = {.connected = connected, + .disconnected = disconnected, + .le_param_req = le_param_req, + .le_param_updated = le_param_updated}; + +static const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), +}; + +static const struct bt_data sd[] = { + BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(TOBLE_SERVICE_UUID)), +}; + +/* Zephyr BLE Message Queue and Thread */ + +static bool ot_plat_ble_queue_msg(const uint8_t *aData, uint16_t aLen, int8_t aRssi) +{ + otError error = OT_ERROR_NONE; + uint16_t len = 0; + + if (aLen <= PLAT_BLE_MSG_DATA_MAX && aData == NULL) { + return OT_ERROR_INVALID_ARGS; + } + + k_sched_lock(); + + len = sizeof(aLen) + sizeof(aRssi) + ((aLen <= PLAT_BLE_MSG_DATA_MAX) ? aLen : 0); + + if (ring_buf_space_get(&ot_plat_ble_ring_buf) >= len) { + ring_buf_put(&ot_plat_ble_ring_buf, (uint8_t *)&aLen, sizeof(aLen)); + ring_buf_put(&ot_plat_ble_ring_buf, &aRssi, sizeof(aRssi)); + if (aLen <= PLAT_BLE_MSG_DATA_MAX) { + ring_buf_put(&ot_plat_ble_ring_buf, aData, aLen); + } + k_sem_give(&ot_plat_ble_event_semaphore); + } else { + error = OT_ERROR_NO_BUFS; + } + + k_sched_unlock(); + + return error; +} + +static void ot_plat_ble_thread(void *unused1, void *unused2, void *unused3) +{ + ARG_UNUSED(unused1); + ARG_UNUSED(unused2); + ARG_UNUSED(unused3); + + uint16_t len; + int8_t rssi; + otBleRadioPacket my_packet; + + LOG_INF("%s started", __func__); + + while (1) { + k_sem_take(&ot_plat_ble_event_semaphore, K_FOREVER); + ring_buf_get(&ot_plat_ble_ring_buf, (uint8_t *)&len, sizeof(len)); + ring_buf_get(&ot_plat_ble_ring_buf, &rssi, sizeof(rssi)); + if (len <= PLAT_BLE_MSG_DATA_MAX) { + ring_buf_get(&ot_plat_ble_ring_buf, ot_plat_ble_msg_buf, len); + } + + openthread_api_mutex_lock(openthread_get_default_context()); + + if (len <= PLAT_BLE_MSG_DATA_MAX) { + /* The packet parameter in otPlatBleGattServerOnWriteRequest is not const. + * Re-write all members. + */ + my_packet.mValue = ot_plat_ble_msg_buf; + my_packet.mPower = rssi; + my_packet.mLength = len; + otPlatBleGattServerOnWriteRequest(ble_openthread_instance, 0, &my_packet); + } else if (len == PLAT_BLE_MSG_CONNECT) { + otPlatBleGapOnConnected(ble_openthread_instance, 0); + } else if (len == PLAT_BLE_MSG_DISCONNECT) { + otPlatBleGapOnDisconnected(ble_openthread_instance, 0); + } + openthread_api_mutex_unlock(openthread_get_default_context()); + } +} + +/* Zephyr BLE service callbacks */ + +/* This function is called whenever the RX Characteristic has been written to by a Client */ +static ssize_t on_receive(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, + uint16_t len, uint16_t offset, uint8_t flags) +{ + LOG_DBG("Received data, handle %" PRIu16 ", len %" PRIu16, attr->handle, len); + + otError error = ot_plat_ble_queue_msg(buf, len, 0); + + if (error != OT_ERROR_NONE) { + LOG_WRN("Error queuing message: %s", otThreadErrorToString(error)); + } + + return len; +} + +/* This function is called whenever a Notification has been sent by the TX Characteristic */ +static void on_sent(struct bt_conn *conn, void *user_data) +{ + ARG_UNUSED(conn); + ARG_UNUSED(user_data); + + LOG_DBG("Data sent"); +} + +/* This function is called whenever the CCCD register has been changed by the client */ +void on_cccd_changed(const struct bt_gatt_attr *attr, uint16_t value) +{ + uint16_t mtu; + otError error = OT_ERROR_NONE; + + ARG_UNUSED(attr); + + switch (value) { + case BT_GATT_CCC_NOTIFY: + + error = ot_plat_ble_queue_msg(NULL, PLAT_BLE_MSG_CONNECT, 0); + if (error != OT_ERROR_NONE) { + LOG_WRN("Error queuing message: %s", otThreadErrorToString(error)); + } + + error = otPlatBleGattMtuGet(ble_openthread_instance, &mtu); + if (error != OT_ERROR_NONE) { + LOG_WRN("Error retrieving mtu: %s", otThreadErrorToString(error)); + } + + LOG_INF("CCCD update (mtu=%" PRIu16 ")!", mtu); + + break; + + default: + break; + } +} + +otError otPlatBleGattServerIndicate(otInstance *aInstance, uint16_t aHandle, + const otBleRadioPacket *aPacket) +{ + ARG_UNUSED(aInstance); + + /* TO DO change to indications. */ + const struct bt_gatt_attr *attr = &my_service.attrs[3]; + + struct bt_gatt_notify_params params = {.uuid = BT_UUID_TCAT_SERVICE_TX, + .attr = attr, + .data = aPacket->mValue, + .len = aPacket->mLength, + .func = on_sent}; + + LOG_DBG("Send data, handle %d, len %d", attr->handle, aPacket->mLength); + + /* Only one connection supported */ + if (aHandle != 0) { + return OT_ERROR_INVALID_ARGS; + } + + if (ot_plat_ble_connection == NULL) { + return OT_ERROR_INVALID_STATE; + } + + /* Check whether notifications are enabled or not */ + if (bt_gatt_is_subscribed(ot_plat_ble_connection, attr, BT_GATT_CCC_NOTIFY)) { + if (bt_gatt_notify_cb(ot_plat_ble_connection, ¶ms)) { + LOG_WRN("Error, unable to send notification"); + return OT_ERROR_INVALID_ARGS; + } + } else { + LOG_WRN("Warning, notification not enabled on the selected attribute"); + return OT_ERROR_INVALID_STATE; + } + + return OT_ERROR_NONE; +} + +otError otPlatBleGattMtuGet(otInstance *aInstance, uint16_t *aMtu) +{ + ARG_UNUSED(aInstance); + + if (ot_plat_ble_connection == NULL) { + return OT_ERROR_FAILED; + } + + if (aMtu != NULL) { + *aMtu = bt_gatt_get_mtu(ot_plat_ble_connection); + } + + return OT_ERROR_NONE; +} + +otError otPlatBleGapDisconnect(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + + if (ot_plat_ble_connection == NULL) { + return OT_ERROR_INVALID_STATE; + } + + if (bt_conn_disconnect(ot_plat_ble_connection, BT_HCI_ERR_REMOTE_USER_TERM_CONN)) { + return OT_ERROR_INVALID_STATE; + } + + return OT_ERROR_NONE; +} + +/* Zephyr BLE callbacks */ + +static void connected(struct bt_conn *conn, uint8_t err) +{ + struct bt_conn_info info; + char addr[BT_ADDR_LE_STR_LEN]; + uint16_t mtu; + otError error = OT_ERROR_NONE; + + ot_plat_ble_connection = bt_conn_ref(conn); + + if (err) { + LOG_WRN("Connection failed (err %u)", err); + return; + } else if (bt_conn_get_info(conn, &info)) { + LOG_WRN("Could not parse connection info"); + } else { + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + error = otPlatBleGattMtuGet(ble_openthread_instance, &mtu); + if (error != OT_ERROR_NONE) { + LOG_WRN("Error retrieving mtu: %s", otThreadErrorToString(error)); + } + + LOG_INF("Connection established (mtu=%" PRIu16 ")!", mtu); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + otError error = OT_ERROR_NONE; + + LOG_INF("Disconnected (reason %" PRIu8 ")", reason); + + if (ot_plat_ble_connection) { + bt_conn_unref(ot_plat_ble_connection); + ot_plat_ble_connection = NULL; + + error = ot_plat_ble_queue_msg(NULL, PLAT_BLE_MSG_DISCONNECT, 0); + if (error != OT_ERROR_NONE) { + LOG_WRN("Error queuing message: %s", otThreadErrorToString(error)); + } + } +} + +static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param) +{ + return true; +} + +static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, + uint16_t timeout) +{ + struct bt_conn_info info; + char addr[BT_ADDR_LE_STR_LEN]; + uint16_t mtu; + otError error = OT_ERROR_NONE; + + if (bt_conn_get_info(conn, &info)) { + LOG_INF("Could not parse connection info"); + } else { + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + error = otPlatBleGattMtuGet(ble_openthread_instance, &mtu); + + if (error != OT_ERROR_NONE) { + LOG_WRN("Error retrieving mtu: %s", otThreadErrorToString(error)); + } + + LOG_INF("Connection parameters updated (mtu=%" PRIu16 ")!", mtu); + } +} + +static void bt_ready(int err) +{ + if (err) { + LOG_WRN("BLE init failed with error code %d", err); + return; + } + + bt_conn_cb_register(&conn_callbacks); + k_sem_give(&ot_plat_ble_init_semaphore); /* BLE stack up an running */ +} + +otError otPlatBleGapAdvStart(otInstance *aInstance, uint16_t aInterval) +{ + ARG_UNUSED(aInstance); + ARG_UNUSED(aInterval); + + /* TO DO advertisement format change */ + int err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); + + if (err != 0 && err != -EALREADY) { + LOG_WRN("Advertising failed to start (err %d)", err); + return OT_ERROR_INVALID_STATE; + } + + LOG_INF("Advertising successfully started"); + + return OT_ERROR_NONE; +} + +otError otPlatBleGapAdvStop(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + + int err = bt_le_adv_stop(); + + if (err != 0 && err != -EALREADY) { + LOG_WRN("Advertisement failed to stop (err %d)", err); + return OT_ERROR_FAILED; + } + return OT_ERROR_NONE; +} + +/* Zephyr BLE initialization */ + +otError otPlatBleEnable(otInstance *aInstance) +{ + int err; + + ble_openthread_instance = aInstance; + err = bt_enable(bt_ready); + + if (err != 0 && err != -EALREADY) { + LOG_WRN("BLE enable failed with error code %d", err); + return OT_ERROR_FAILED; + } else if (err == -EALREADY) { + err = k_sem_take(&ot_plat_ble_init_semaphore, K_MSEC(500)); + return OT_ERROR_NONE; + } + + err = k_sem_take(&ot_plat_ble_init_semaphore, K_MSEC(500)); + + if (!err) { + LOG_INF("Bluetooth initialized"); + } else { + LOG_INF("BLE initialization did not complete in time"); + return OT_ERROR_FAILED; + } + + return OT_ERROR_NONE; +} + +otError otPlatBleDisable(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + /* This function intentionally does nothing since disabling advertisement disables BLE + * stack. + */ + return OT_ERROR_NONE; +} diff --git a/modules/openthread/platform/crypto_psa.c b/modules/openthread/platform/crypto_psa.c index e5b234ce0307593..6ad286f3734f961 100644 --- a/modules/openthread/platform/crypto_psa.c +++ b/modules/openthread/platform/crypto_psa.c @@ -16,6 +16,7 @@ #if defined(CONFIG_OPENTHREAD_ECDSA) #include +#include #endif static otError psaToOtError(psa_status_t aStatus) @@ -41,6 +42,8 @@ static psa_key_type_t toPsaKeyType(otCryptoKeyType aType) return PSA_KEY_TYPE_AES; case OT_CRYPTO_KEY_TYPE_HMAC: return PSA_KEY_TYPE_HMAC; + case OT_CRYPTO_KEY_TYPE_ECDSA: + return PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); default: return PSA_KEY_TYPE_NONE; } @@ -53,12 +56,14 @@ static psa_algorithm_t toPsaAlgorithm(otCryptoKeyAlgorithm aAlgorithm) return PSA_ALG_ECB_NO_PADDING; case OT_CRYPTO_KEY_ALG_HMAC_SHA_256: return PSA_ALG_HMAC(PSA_ALG_SHA_256); + case OT_CRYPTO_KEY_ALG_ECDSA: + return PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256); default: /* * There is currently no constant like PSA_ALG_NONE, but 0 is used * to indicate an unknown algorithm. */ - return (psa_algorithm_t) 0; + return (psa_algorithm_t)0; } } @@ -82,16 +87,19 @@ static psa_key_usage_t toPsaKeyUsage(int aUsage) usage |= PSA_KEY_USAGE_SIGN_HASH; } + if (aUsage & OT_CRYPTO_KEY_USAGE_VERIFY_HASH) { + usage |= PSA_KEY_USAGE_VERIFY_HASH; + } + return usage; } static bool checkKeyUsage(int aUsage) { /* Check if only supported flags have been passed */ - int supported_flags = OT_CRYPTO_KEY_USAGE_EXPORT | - OT_CRYPTO_KEY_USAGE_ENCRYPT | - OT_CRYPTO_KEY_USAGE_DECRYPT | - OT_CRYPTO_KEY_USAGE_SIGN_HASH; + int supported_flags = OT_CRYPTO_KEY_USAGE_EXPORT | OT_CRYPTO_KEY_USAGE_ENCRYPT | + OT_CRYPTO_KEY_USAGE_DECRYPT | OT_CRYPTO_KEY_USAGE_SIGN_HASH | + OT_CRYPTO_KEY_USAGE_VERIFY_HASH; return (aUsage & ~supported_flags) == 0; } @@ -102,31 +110,6 @@ static bool checkContext(otCryptoContext *aContext, size_t aMinSize) return aContext != NULL && aContext->mContext != NULL && aContext->mContextSize >= aMinSize; } -static void ensureKeyIsLoaded(otCryptoKeyRef aKeyRef) -{ - /* - * The workaround below will no longer be need after updating TF-M version used in Zephyr - * to 1.5.0 (see upstream commit 42e77b561fcfe19819ff1e63cb7c0b672ee8ba41). - * In the recent versions of TF-M the concept of key handles and psa_open_key()/ - * psa_close_key() APIs have been being deprecated, but the version currently used in Zephyr - * is in the middle of that transition. Consequently, psa_destroy_key() and lots of other - * functions will fail when a key ID that they take as a parameter is not loaded from the - * persistent storage. That may occur when a given persistent key is created via - * psa_generate_key() or psa_import_key(), and then the device reboots. - * - * Use psa_open_key() when the key has not been loaded yet to work around the issue. - */ - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_status_t status = psa_get_key_attributes(aKeyRef, &attributes); - psa_key_id_t key_handle; - - if (status == PSA_ERROR_INVALID_HANDLE) { - psa_open_key(aKeyRef, &key_handle); - } - - psa_reset_key_attributes(&attributes); -} - void otPlatCryptoInit(void) { psa_crypto_init(); @@ -137,26 +120,57 @@ void otPlatCryptoInit(void) * PSA with emulated TFM, Settings have to be initialized at the end of otPlatCryptoInit(), * to be available before storing Network Key. */ - __ASSERT_EVAL((void) settings_subsys_init(), int err = settings_subsys_init(), - !err, "Failed to initialize settings"); + __ASSERT_EVAL((void)settings_subsys_init(), int err = settings_subsys_init(), !err, + "Failed to initialize settings"); #endif } -otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef, - otCryptoKeyType aKeyType, - otCryptoKeyAlgorithm aKeyAlgorithm, - int aKeyUsage, - otCryptoKeyStorage aKeyPersistence, - const uint8_t *aKey, +otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef, otCryptoKeyType aKeyType, + otCryptoKeyAlgorithm aKeyAlgorithm, int aKeyUsage, + otCryptoKeyStorage aKeyPersistence, const uint8_t *aKey, size_t aKeyLen) { +#if defined(CONFIG_OPENTHREAD_ECDSA) + int version; + size_t len; + unsigned char *p = (unsigned char *)aKey; + unsigned char *end; +#endif + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_status_t status; + psa_status_t status = 0; if (aKeyRef == NULL || aKey == NULL || !checkKeyUsage(aKeyUsage)) { return OT_ERROR_INVALID_ARGS; } +#if defined(CONFIG_OPENTHREAD_ECDSA) + /* Check if key is ECDSA pair and extract private key from it since PSA expects it. */ + if (aKeyType == OT_CRYPTO_KEY_TYPE_ECDSA) { + + end = p + aKeyLen; + status = mbedtls_asn1_get_tag(&p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); + if (status != 0) { + return OT_ERROR_FAILED; + } + + end = p + len; + status = mbedtls_asn1_get_int(&p, end, &version); + if (status != 0) { + return OT_ERROR_FAILED; + } + + status = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); + if (status != 0 || len != 32) { + return OT_ERROR_FAILED; + } + + aKey = p; + aKeyLen = len; + } +#endif + psa_set_key_type(&attributes, toPsaKeyType(aKeyType)); psa_set_key_algorithm(&attributes, toPsaAlgorithm(aKeyAlgorithm)); psa_set_key_usage_flags(&attributes, toPsaKeyUsage(aKeyUsage)); @@ -177,24 +191,18 @@ otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef, return psaToOtError(status); } -otError otPlatCryptoExportKey(otCryptoKeyRef aKeyRef, - uint8_t *aBuffer, - size_t aBufferLen, +otError otPlatCryptoExportKey(otCryptoKeyRef aKeyRef, uint8_t *aBuffer, size_t aBufferLen, size_t *aKeyLen) { if (aBuffer == NULL) { return OT_ERROR_INVALID_ARGS; } - ensureKeyIsLoaded(aKeyRef); - return psaToOtError(psa_export_key(aKeyRef, aBuffer, aBufferLen, aKeyLen)); } otError otPlatCryptoDestroyKey(otCryptoKeyRef aKeyRef) { - ensureKeyIsLoaded(aKeyRef); - return psaToOtError(psa_destroy_key(aKeyRef)); } @@ -203,7 +211,6 @@ bool otPlatCryptoHasKey(otCryptoKeyRef aKeyRef) psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_status_t status; - ensureKeyIsLoaded(aKeyRef); status = psa_get_key_attributes(aKeyRef, &attributes); psa_reset_key_attributes(&attributes); @@ -246,15 +253,13 @@ otError otPlatCryptoHmacSha256Start(otCryptoContext *aContext, const otCryptoKey return OT_ERROR_INVALID_ARGS; } - ensureKeyIsLoaded(aKey->mKeyRef); operation = aContext->mContext; status = psa_mac_sign_setup(operation, aKey->mKeyRef, PSA_ALG_HMAC(PSA_ALG_SHA_256)); return psaToOtError(status); } -otError otPlatCryptoHmacSha256Update(otCryptoContext *aContext, - const void *aBuf, +otError otPlatCryptoHmacSha256Update(otCryptoContext *aContext, const void *aBuf, uint16_t aBufLength) { psa_mac_operation_t *operation; @@ -265,7 +270,7 @@ otError otPlatCryptoHmacSha256Update(otCryptoContext *aContext, operation = aContext->mContext; - return psaToOtError(psa_mac_update(operation, (const uint8_t *) aBuf, aBufLength)); + return psaToOtError(psa_mac_update(operation, (const uint8_t *)aBuf, aBufLength)); } otError otPlatCryptoHmacSha256Finish(otCryptoContext *aContext, uint8_t *aBuf, size_t aBufLength) @@ -291,7 +296,7 @@ otError otPlatCryptoAesInit(otCryptoContext *aContext) } key_ref = aContext->mContext; - *key_ref = (psa_key_id_t) 0; /* In TF-M 1.5.0 this can be replaced with PSA_KEY_ID_NULL */ + *key_ref = (psa_key_id_t)0; /* In TF-M 1.5.0 this can be replaced with PSA_KEY_ID_NULL */ return OT_ERROR_NONE; } @@ -314,7 +319,6 @@ otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uint8_t *aInput, { const size_t block_size = PSA_BLOCK_CIPHER_BLOCK_LENGTH(PSA_KEY_TYPE_AES); psa_status_t status = PSA_SUCCESS; - psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_key_id_t *key_ref; size_t cipher_length; @@ -322,37 +326,10 @@ otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uint8_t *aInput, return OT_ERROR_INVALID_ARGS; } - /* - * The code below can be simplified after updating TF-M version used in Zephyr to 1.5.0 - * (see upstream commit: 045ec4abfc73152a0116684ba9127d0a97cc8d34), using - * psa_cipher_encrypt() function which will replace the setup-update-finish sequence below. - */ key_ref = aContext->mContext; - ensureKeyIsLoaded(*key_ref); - status = psa_cipher_encrypt_setup(&operation, *key_ref, PSA_ALG_ECB_NO_PADDING); - - if (status != PSA_SUCCESS) { - goto out; - } - - status = psa_cipher_update(&operation, - aInput, - block_size, - aOutput, - block_size, - &cipher_length); + status = psa_cipher_encrypt(*key_ref, PSA_ALG_ECB_NO_PADDING, aInput, block_size, aOutput, + block_size, &cipher_length); - if (status != PSA_SUCCESS) { - goto out; - } - - status = psa_cipher_finish(&operation, - aOutput + cipher_length, - block_size - cipher_length, - &cipher_length); - -out: - psa_cipher_abort(&operation); return psaToOtError(status); } @@ -411,7 +388,7 @@ otError otPlatCryptoSha256Update(otCryptoContext *aContext, const void *aBuf, ui operation = aContext->mContext; - return psaToOtError(psa_hash_update(operation, (const uint8_t *) aBuf, aBufLength)); + return psaToOtError(psa_hash_update(operation, (const uint8_t *)aBuf, aBufLength)); } otError otPlatCryptoSha256Finish(otCryptoContext *aContext, uint8_t *aHash, uint16_t aHashSize) @@ -475,38 +452,6 @@ otError otPlatCryptoEcdsaGenerateKey(otPlatCryptoEcdsaKeyPair *aKeyPair) return psaToOtError(status); } -otError otPlatCryptoEcdsaGetPublicKey(const otPlatCryptoEcdsaKeyPair *aKeyPair, - otPlatCryptoEcdsaPublicKey *aPublicKey) -{ - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_key_id_t key_id = 0; - psa_status_t status; - size_t exported_length; - uint8_t buffer[1 + OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE]; - - psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)); - psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); - psa_set_key_bits(&attributes, 256); - - status = psa_import_key(&attributes, aKeyPair->mDerBytes, aKeyPair->mDerLength, &key_id); - if (status != PSA_SUCCESS) { - goto out; - } - - status = psa_export_public_key(key_id, buffer, sizeof(buffer), &exported_length); - if (status != PSA_SUCCESS) { - goto out; - } - __ASSERT_NO_MSG(exported_length == sizeof(buffer)); - memcpy(aPublicKey->m8, buffer + 1, OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE); - -out: - psa_reset_key_attributes(&attributes); - psa_destroy_key(key_id); - - return psaToOtError(status); -} - otError otPlatCryptoEcdsaSign(const otPlatCryptoEcdsaKeyPair *aKeyPair, const otPlatCryptoSha256Hash *aHash, otPlatCryptoEcdsaSignature *aSignature) @@ -658,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/misc.c b/modules/openthread/platform/misc.c index 7f57dddb9e3eb97..5f9043dfa27b7f5 100644 --- a/modules/openthread/platform/misc.c +++ b/modules/openthread/platform/misc.c @@ -9,6 +9,24 @@ #include #include +#if defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_RETENTION) + +#include + +#elif defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_GPIO) + +BUILD_ASSERT(DT_HAS_COMPAT_STATUS_OKAY(openthread_config), + "`openthread,config` compatible node not found"); +BUILD_ASSERT(DT_NODE_HAS_PROP(DT_COMPAT_GET_ANY_STATUS_OKAY(openthread_config), bootloader_gpios), + "`bootloader-gpios` property missing from `openthread,config` compatible node"); + +#include + +static const struct gpio_dt_spec bootloader_gpio = + GPIO_DT_SPEC_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(openthread_config), + bootloader_gpios); +#endif + #include "platform-zephyr.h" void otPlatReset(otInstance *aInstance) @@ -19,6 +37,54 @@ void otPlatReset(otInstance *aInstance) sys_reboot(SYS_REBOOT_WARM); } +#if defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE) +otError otPlatResetToBootloader(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + +#if defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_RETENTION) + if (bootmode_set(BOOT_MODE_TYPE_BOOTLOADER)) { + return OT_ERROR_NOT_CAPABLE; + } + sys_reboot(SYS_REBOOT_WARM); + +#elif defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_GPIO) + /* + * To enable resetting to bootloader by triggering gpio pin, + * select `CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE_GPIO=y`, + * and in Devicetree create `openthread` node in `/options/` path with + * `compatible = "openthread,config"` property and `bootloader-gpios` property, + * which should represent GPIO pin's configuration, + * containing controller phandle, pin number and pin flags. e.g: + * + * options { + * openthread { + * compatible = "openthread,config"; + * bootloader-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + * }; + * }; + * + * Note: in below implementation, chosen GPIO pin is configured as output + * and initialized to active state (logical value ‘1’). + * Configuring pin flags in `bootloader-gpios` allows to choose + * if pin should be active in high or in low state. + */ + + if (!gpio_is_ready_dt(&bootloader_gpio)) { + return OT_ERROR_NOT_CAPABLE; + } + gpio_pin_configure_dt(&bootloader_gpio, GPIO_OUTPUT_ACTIVE); + +#endif + + /* + * Return OT_ERROR_NOT_CAPABLE if resetting has been unsuccessful (invalid configuration or + * triggering reset had no effect) + */ + return OT_ERROR_NOT_CAPABLE; +} +#endif /* defined(CONFIG_OPENTHREAD_PLATFORM_BOOTLOADER_MODE) */ + otPlatResetReason otPlatGetResetReason(otInstance *aInstance) { ARG_UNUSED(aInstance); @@ -33,5 +99,10 @@ void otPlatWakeHost(void) void otPlatAssertFail(const char *aFilename, int aLineNumber) { - __ASSERT(false, "OpenThread ASSERT @ %s:%d", aFilename, aLineNumber); + /* + * The code below is used instead of __ASSERT(false) to print the actual assert + * location instead of __FILE__:__LINE__, which would point to this function. + */ + __ASSERT_PRINT("OpenThread ASSERT @ %s:%d\n", aFilename, aLineNumber); + __ASSERT_POST_ACTION(); } diff --git a/modules/openthread/platform/openthread-core-zephyr-config.h b/modules/openthread/platform/openthread-core-zephyr-config.h index 8d6b5e54fd0857d..71a087ca0b501a9 100644 --- a/modules/openthread/platform/openthread-core-zephyr-config.h +++ b/modules/openthread/platform/openthread-core-zephyr-config.h @@ -60,6 +60,18 @@ CONFIG_OPENTHREAD_TMF_ADDRESS_CACHE_ENTRIES #endif +/** + * @def CONFIG_OPENTHREAD_TMF_ADDRESS_CACHE_MAX_SNOOP_ENTRIES + * + * The maximum number of EID-to-RLOC cache entries that can be used for + * "snoop optimization" where an entry is created by inspecting a received message. + * + */ +#ifdef CONFIG_OPENTHREAD_TMF_ADDRESS_CACHE_MAX_SNOOP_ENTRIES +#define OPENTHREAD_CONFIG_TMF_ADDRESS_CACHE_MAX_SNOOP_ENTRIES \ + CONFIG_OPENTHREAD_TMF_ADDRESS_CACHE_MAX_SNOOP_ENTRIES +#endif + /** * @def OPENTHREAD_CONFIG_LOG_PREPEND_LEVEL * @@ -384,16 +396,6 @@ #define OPENTHREAD_CONFIG_CRYPTO_LIB OPENTHREAD_CONFIG_CRYPTO_LIB_PSA #endif -/** - * @def OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - * - * Set to 1 if you want to enable key reference usage support. - * - */ -#ifdef CONFIG_OPENTHREAD_PLATFORM_KEY_REFERENCES_ENABLE -#define OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 1 -#endif - /** * @def OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE * @@ -436,17 +438,6 @@ #define OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE 0 #endif -/** - * @def OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE - * - * In Zephyr, power calibration is handled by Radio Driver, so it can't be handled on OT level. - * - */ -#ifndef OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE -#define OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE 0 -#endif - - /** * @def OPENTHREAD_CONFIG_RADIO_STATS * diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index 17753ee852d7595..64effaef337b378 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -58,6 +58,13 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_OPENTHREAD_L2_LOG_LEVEL); #define CHANNEL_COUNT OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX - OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN + 1 +/* PHY header duration in us (i.e. 2 symbol periods @ 62.5k symbol rate), see + * IEEE 802.15.4, sections 12.1.3.1, 12.2.5 and 12.3.3. + */ +#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 */ @@ -224,7 +231,7 @@ void handle_radio_event(const struct device *dev, enum ieee802154_event evt, set_pending_event(PENDING_EVENT_RX_FAILED); } break; - case IEEE802154_EVENT_SLEEP: + case IEEE802154_EVENT_RX_OFF: set_pending_event(PENDING_EVENT_SLEEP); break; default: @@ -375,13 +382,8 @@ void transmit_message(struct k_work *tx_job) channel = sTransmitFrame.mChannel; - radio_api->set_channel(radio_dev, sTransmitFrame.mChannel); - -#if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) - net_pkt_set_ieee802154_txpwr(tx_pkt, get_transmit_power_for_channel(channel)); -#else + radio_api->set_channel(radio_dev, channel); radio_api->set_txpower(radio_dev, get_transmit_power_for_channel(channel)); -#endif /* CONFIG_IEEE802154_SELECTIVE_TXPOWER */ net_pkt_set_ieee802154_frame_secured(tx_pkt, sTransmitFrame.mInfo.mTxInfo.mIsSecurityProcessed); @@ -473,14 +475,9 @@ static void openthread_handle_received_frame(otInstance *instance, recv_frame.mInfo.mRxInfo.mTimestamp = net_pkt_timestamp_ns(pkt) / NSEC_PER_USEC; #endif - if (net_pkt_ieee802154_arb(pkt) && net_pkt_ieee802154_fv2015(pkt)) { - recv_frame.mInfo.mRxInfo.mAckedWithSecEnhAck = - net_pkt_ieee802154_ack_seb(pkt); - recv_frame.mInfo.mRxInfo.mAckFrameCounter = - net_pkt_ieee802154_ack_fc(pkt); - recv_frame.mInfo.mRxInfo.mAckKeyId = - net_pkt_ieee802154_ack_keyid(pkt); - } + recv_frame.mInfo.mRxInfo.mAckedWithSecEnhAck = net_pkt_ieee802154_ack_seb(pkt); + recv_frame.mInfo.mRxInfo.mAckFrameCounter = net_pkt_ieee802154_ack_fc(pkt); + recv_frame.mInfo.mRxInfo.mAckKeyId = net_pkt_ieee802154_ack_keyid(pkt); if (IS_ENABLED(CONFIG_OPENTHREAD_DIAG) && otPlatDiagModeGet()) { otPlatDiagRadioReceiveDone(instance, &recv_frame, OT_ERROR_NONE); @@ -890,9 +887,26 @@ otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) caps |= OT_RADIO_CAPS_RECEIVE_TIMING; } + if (radio_caps & IEEE802154_RX_ON_WHEN_IDLE) { + caps |= OT_RADIO_CAPS_RX_ON_WHEN_IDLE; + } + return caps; } +void otPlatRadioSetRxOnWhenIdle(otInstance *aInstance, bool aRxOnWhenIdle) +{ + struct ieee802154_config config = { + .rx_on_when_idle = aRxOnWhenIdle + }; + + ARG_UNUSED(aInstance); + + LOG_DBG("RxOnWhenIdle=%d", aRxOnWhenIdle ? 1 : 0); + + radio_api->configure(radio_dev, IEEE802154_CONFIG_RX_ON_WHEN_IDLE, &config); +} + bool otPlatRadioGetPromiscuous(otInstance *aInstance) { ARG_UNUSED(aInstance); @@ -1094,7 +1108,7 @@ int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) { ARG_UNUSED(aInstance); - return -100; + return DEFAULT_SENSITIVITY; } otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower) @@ -1171,20 +1185,14 @@ void otPlatRadioSetMacKey(otInstance *aInstance, uint8_t aKeyIdMode, uint8_t aKe struct ieee802154_key keys[] = { { .key_id_mode = key_id_mode, - .key_index = aKeyId == 1 ? 0x80 : aKeyId - 1, - .key_value = (uint8_t *)aPrevKey->mKeyMaterial.mKey.m8, .frame_counter_per_key = false, }, { .key_id_mode = key_id_mode, - .key_index = aKeyId, - .key_value = (uint8_t *)aCurrKey->mKeyMaterial.mKey.m8, .frame_counter_per_key = false, }, { .key_id_mode = key_id_mode, - .key_index = aKeyId == 0x80 ? 1 : aKeyId + 1, - .key_value = (uint8_t *)aNextKey->mKeyMaterial.mKey.m8, .frame_counter_per_key = false, }, { @@ -1198,9 +1206,24 @@ void otPlatRadioSetMacKey(otInstance *aInstance, uint8_t aKeyIdMode, uint8_t aKe }, }; - /* aKeyId in range: (1, 0x80) means valid keys - * aKeyId == 0 is used only to clear keys for stack reset in RCP - */ + if (key_id_mode == 1) { + /* aKeyId in range: (1, 0x80) means valid keys */ + uint8_t prev_key_id = aKeyId == 1 ? 0x80 : aKeyId - 1; + uint8_t next_key_id = aKeyId == 0x80 ? 1 : aKeyId + 1; + + keys[0].key_id = &prev_key_id; + keys[0].key_value = (uint8_t *)aPrevKey->mKeyMaterial.mKey.m8; + + keys[1].key_id = &aKeyId; + keys[1].key_value = (uint8_t *)aCurrKey->mKeyMaterial.mKey.m8; + + keys[2].key_id = &next_key_id; + keys[2].key_value = (uint8_t *)aNextKey->mKeyMaterial.mKey.m8; + } else { + /* aKeyId == 0 is used only to clear keys for stack reset in RCP */ + __ASSERT_NO_MSG((key_id_mode == 0) && (aKeyId == 0)); + } + struct ieee802154_config config = { .mac_keys = aKeyId == 0 ? clear_keys : keys, }; @@ -1234,29 +1257,57 @@ void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacF otError otPlatRadioEnableCsl(otInstance *aInstance, uint32_t aCslPeriod, otShortAddress aShortAddr, const otExtAddress *aExtAddr) { + struct ieee802154_config config = { 0 }; int result; - uint8_t ie_header[OT_IE_HEADER_SIZE + OT_CSL_IE_SIZE]; - struct ieee802154_config config; ARG_UNUSED(aInstance); - ie_header[0] = CSL_IE_HEADER_BYTES_LO; - ie_header[1] = CSL_IE_HEADER_BYTES_HI; - /* Leave CSL Phase empty intentionally */ - sys_put_le16(aCslPeriod, &ie_header[OT_IE_HEADER_SIZE + 2]); - config.ack_ie.data = ie_header; + /* Configure the CSL period first to give drivers a chance to validate + * the IE for consistency if they wish to. + */ + config.csl_period = aCslPeriod; + result = radio_api->configure(radio_dev, IEEE802154_CONFIG_CSL_PERIOD, &config); + if (result) { + return OT_ERROR_FAILED; + } config.ack_ie.short_addr = aShortAddr; - config.ack_ie.ext_addr = aExtAddr->m8; + config.ack_ie.ext_addr = aExtAddr != NULL ? aExtAddr->m8 : NULL; + /* Configure the CSL IE. */ if (aCslPeriod > 0) { - config.ack_ie.data_len = OT_IE_HEADER_SIZE + OT_CSL_IE_SIZE; + uint8_t header_ie_buf[OT_IE_HEADER_SIZE + OT_CSL_IE_SIZE] = { + CSL_IE_HEADER_BYTES_LO, + CSL_IE_HEADER_BYTES_HI, + }; + struct ieee802154_header_ie *header_ie = + (struct ieee802154_header_ie *)header_ie_buf; + + /* Write CSL period and leave CSL phase empty as it will be + * injected on-the-fly by the driver. + */ + header_ie->content.csl.reduced.csl_period = sys_cpu_to_le16(aCslPeriod); + config.ack_ie.header_ie = header_ie; } else { - config.ack_ie.data_len = 0; + config.ack_ie.header_ie = NULL; } + result = radio_api->configure(radio_dev, IEEE802154_CONFIG_ENH_ACK_HEADER_IE, &config); - config.csl_period = aCslPeriod; - result += radio_api->configure(radio_dev, IEEE802154_CONFIG_CSL_PERIOD, &config); + return result ? OT_ERROR_FAILED : OT_ERROR_NONE; +} + +otError otPlatRadioResetCsl(otInstance *aInstance) +{ + struct ieee802154_config config = { 0 }; + int result; + + result = radio_api->configure(radio_dev, IEEE802154_CONFIG_CSL_PERIOD, &config); + if (result) { + return OT_ERROR_FAILED; + } + + config.ack_ie.purge_ie = true; + result = radio_api->configure(radio_dev, IEEE802154_CONFIG_ENH_ACK_HEADER_IE, &config); return result ? OT_ERROR_FAILED : OT_ERROR_NONE; } @@ -1265,10 +1316,15 @@ void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTi { ARG_UNUSED(aInstance); + /* CSL sample time points to "start of MAC" while the expected RX time + * refers to "end of SFD". + */ struct ieee802154_config config = { - .csl_rx_time = convert_32bit_us_wrapped_to_64bit_ns(aCslSampleTime)}; + .expected_rx_time = + convert_32bit_us_wrapped_to_64bit_ns(aCslSampleTime - PHR_DURATION_US), + }; - (void)radio_api->configure(radio_dev, IEEE802154_CONFIG_CSL_RX_TIME, &config); + (void)radio_api->configure(radio_dev, IEEE802154_CONFIG_EXPECTED_RX_TIME, &config); } #endif /* CONFIG_OPENTHREAD_CSL_RECEIVER */ @@ -1309,7 +1365,7 @@ uint8_t otPlatRadioGetCslUncertainty(otInstance *aInstance) * | IE_VENDOR_THREAD_ACK_PROBING_ID | LINK_METRIC_TOKEN | LINK_METRIC_TOKEN| * |---------------------------------|-------------------|------------------| */ -static uint8_t set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, uint8_t *ie_header) +static void set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, uint8_t *ie_header) { /* Vendor-specific IE identifier */ const uint8_t ie_vendor_id = 0x00; @@ -1323,7 +1379,6 @@ static uint8_t set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, ui const uint8_t ie_vendor_thread_margin_token = 0x02; /* Thread Vendor-specific ACK Probing IE LQI value placeholder */ const uint8_t ie_vendor_thread_lqi_token = 0x03; - const uint8_t ie_header_size = 2; const uint8_t oui_size = 3; const uint8_t sub_type = 1; const uint8_t id_offset = 7; @@ -1341,7 +1396,8 @@ static uint8_t set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, ui __ASSERT(ie_header, "Invalid argument"); if (link_metrics_data_len == 0) { - return 0; + ie_header[0] = 0; + return; } /* Set Element ID */ @@ -1376,28 +1432,24 @@ static uint8_t set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, ui if (rssi) { ie_header[link_metrics_idx++] = ie_vendor_thread_rssi_token; } - - return ie_header_size + content_len; } otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, otLinkMetrics aLinkMetrics, const otShortAddress aShortAddress, const otExtAddress *aExtAddress) { - int result; - uint8_t ie_header[OT_ACK_IE_MAX_SIZE]; - uint16_t ie_header_len; struct ieee802154_config config = { .ack_ie.short_addr = aShortAddress, .ack_ie.ext_addr = aExtAddress->m8, }; + uint8_t header_ie_buf[OT_ACK_IE_MAX_SIZE]; + int result; ARG_UNUSED(aInstance); - ie_header_len = set_vendor_ie_header_lm(aLinkMetrics.mLqi, aLinkMetrics.mLinkMargin, - aLinkMetrics.mRssi, ie_header); - config.ack_ie.data = ie_header; - config.ack_ie.data_len = ie_header_len; + set_vendor_ie_header_lm(aLinkMetrics.mLqi, aLinkMetrics.mLinkMargin, + aLinkMetrics.mRssi, header_ie_buf); + config.ack_ie.header_ie = (struct ieee802154_header_ie *)header_ie_buf; result = radio_api->configure(radio_dev, IEEE802154_CONFIG_ENH_ACK_HEADER_IE, &config); return result ? OT_ERROR_FAILED : OT_ERROR_NONE; diff --git a/modules/openthread/platform/uart.c b/modules/openthread/platform/uart.c index dd62d36ee11eb9a..ebf156ded1563c5 100644 --- a/modules/openthread/platform/uart.c +++ b/modules/openthread/platform/uart.c @@ -170,7 +170,6 @@ otError otPlatUartEnable(void) if (DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_ot_uart), zephyr_cdc_acm_uart)) { int ret; - uint32_t dtr = 0U; ret = usb_enable(NULL); if (ret != 0 && ret != -EALREADY) { @@ -178,20 +177,6 @@ otError otPlatUartEnable(void) return OT_ERROR_FAILED; } - LOG_INF("Waiting for host to be ready to communicate"); - - /* Data Terminal Ready - check if host is ready to communicate */ - while (!dtr) { - ret = uart_line_ctrl_get(ot_uart.dev, - UART_LINE_CTRL_DTR, &dtr); - if (ret) { - LOG_ERR("Failed to get Data Terminal Ready line state: %d", - ret); - continue; - } - k_msleep(100); - } - /* Data Carrier Detect Modem - mark connection as established */ (void)uart_line_ctrl_set(ot_uart.dev, UART_LINE_CTRL_DCD, 1); /* Data Set Ready - the NCP SoC is ready to communicate */ diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index 0c01858f34d52cc..f647e385dcf1011 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) @@ -95,12 +78,37 @@ if (CONFIG_BUILD_WITH_TFM) list(APPEND TFM_CMAKE_ARGS -DMCUBOOT_IMAGE_NUMBER=${CONFIG_TFM_MCUBOOT_IMAGE_NUMBER}) endif() + if (CONFIG_TFM_DUMMY_PROVISIONING) + list(APPEND TFM_CMAKE_ARGS -DTFM_DUMMY_PROVISIONING=ON) + else() + list(APPEND TFM_CMAKE_ARGS -DTFM_DUMMY_PROVISIONING=OFF) + endif() + if (CONFIG_TFM_EXCEPTION_INFO_DUMP) list(APPEND TFM_CMAKE_ARGS -DTFM_EXCEPTION_INFO_DUMP=ON) else() list(APPEND TFM_CMAKE_ARGS -DTFM_EXCEPTION_INFO_DUMP=OFF) endif() + if (CONFIG_TFM_BL2) + if (CONFIG_TFM_BL2_LOG_LEVEL_DEBUG) + set(TFM_BL2_LOG_LEVEL "DEBUG") + elseif (CONFIG_TFM_BL2_LOG_LEVEL_INFO) + set(TFM_BL2_LOG_LEVEL "INFO") + elseif (CONFIG_TFM_BL2_LOG_LEVEL_WARNING) + set(TFM_BL2_LOG_LEVEL "WARNING") + elseif (CONFIG_TFM_BL2_LOG_LEVEL_ERROR) + set(TFM_BL2_LOG_LEVEL "ERROR") + elseif (CONFIG_TFM_BL2_LOG_LEVEL_OFF OR CONFIG_TFM_LOG_LEVEL_SILENCE) + set(TFM_BL2_LOG_LEVEL "OFF") + endif() + + if (DEFINED TFM_BL2_LOG_LEVEL) + # BL2 uses MCUBOOT_LOG_LEVEL configuration + list(APPEND TFM_CMAKE_ARGS -DMCUBOOT_LOG_LEVEL=${TFM_BL2_LOG_LEVEL}) + endif() + endif() + if (CONFIG_TFM_PARTITION_LOG_LEVEL_DEBUG) set(TFM_PARTITION_LOG_LEVEL "TFM_PARTITION_LOG_LEVEL_DEBUG") elseif (CONFIG_TFM_PARTITION_LOG_LEVEL_INFO) @@ -156,22 +164,9 @@ if (CONFIG_BUILD_WITH_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) @@ -182,38 +177,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 @@ -238,25 +228,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() + string(REPLACE "toolchain" "toolchain_ns" TFM_TOOLCHAIN_NS_FILE ${TFM_TOOLCHAIN_FILE}) if (CONFIG_TFM_QCBOR_PATH STREQUAL "DOWNLOAD") # Change CMake cache type to string to avoid QCBOR_PATH=/absolute/path/DOWNLOAD being set. @@ -281,13 +253,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. @@ -312,6 +277,7 @@ 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}> @@ -354,6 +320,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) @@ -390,48 +361,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() + 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(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_tz_psa_ns_api.c) - zephyr_library_sources(${TFM_INTERFACE_SOURCE_DIR}/tfm_psa_ns_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() - - else() - zephyr_library_link_libraries( - ${TFM_API_NS_PATH} - ${PLATFORM_NS_FILE} - ) + 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. @@ -560,4 +510,13 @@ if (CONFIG_BUILD_WITH_TFM) ${MERGED_FILE} ) endif() -endif() + + if(CONFIG_TFM_DUMMY_PROVISIONING) + message(WARNING + "TFM_DUMMY_PROVISIONING is enabled: + The device will be provisioned using dummy keys and is NOT secure! + This is not suitable for production" + ) + endif() + +endif() # CONFIG_BUILD_WITH_TFM diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index a7276d79374c25c..277dd8a8d09cbe5 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -9,9 +9,6 @@ config ZEPHYR_TRUSTED_FIRMWARE_M_MODULE config TFM_BOARD string - default "nordic_nrf/nrf9160dk_nrf9160" if BOARD_NRF9160DK_NRF9160_NS - default "nordic_nrf/nrf9161dk_nrf9161" if BOARD_NRF9161DK_NRF9161_NS - default "nordic_nrf/nrf5340dk_nrf5340_cpuapp" if BOARD_NRF5340DK_NRF5340_CPUAPP_NS default "nxp/lpcxpresso55s69" if BOARD_LPCXPRESSO55S69_CPU0 default "arm/mps2/an521" if BOARD_MPS2_AN521_CPU0_NS default "arm/mps3/an547" if BOARD_MPS3_AN547 @@ -20,7 +17,9 @@ 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 help The board name used for building TFM. Building with TFM requires that TFM has been ported to the given board/SoC. @@ -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" @@ -177,6 +180,25 @@ config TFM_PARTITION_PLATFORM_CUSTOM_REBOOT Instead the application will have to override the weak ARM implementation of sys_arch_reset(). +config TFM_DUMMY_PROVISIONING + bool "Provision with dummy values. NOT to be used in production" + select TFM_INITIAL_ATTESTATION_KEY + default y + help + If this option is enabled (as it is by default), a set of dummy + keys / data will be provisioned. The dummy IAK matches the IAK tested + by the TF-M tests, and the dummy bl2 ROTPKs match the dummy bl2 keys + used by default. + This option MUST not be used in production hardware, as the keys are + insecure. + +config TFM_INITIAL_ATTESTATION_KEY + bool + help + Hidden option to mark that the TF-M platform has an initial + attestation key, which is a requirement for the Initial Attestation + partition. + config TFM_BL2_NOT_SUPPORTED bool help @@ -207,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 @@ -302,6 +313,7 @@ endif # TFM_BL2 choice TFM_MODEL prompt "TF-M Firmware Framework model" + default TFM_SFN if TFM_PROFILE_TYPE_SMALL default TFM_IPC help The Firmware Framework M (FF-M) provides different programming models @@ -397,6 +409,21 @@ config ROM_START_OFFSET needs to be updated if TF-M switches to use a different header size for BL2. +choice TFM_BL2_LOG_LEVEL + prompt "BL2 Log Level" if !TFM_LOG_LEVEL_SILENCE + default TFM_BL2_LOG_LEVEL_INFO + config TFM_BL2_LOG_LEVEL_DEBUG + bool "Debug" + config TFM_BL2_LOG_LEVEL_INFO + bool "Info" + config TFM_BL2_LOG_LEVEL_WARNING + bool "Warning" + config TFM_BL2_LOG_LEVEL_ERROR + bool "Error" + config TFM_BL2_LOG_LEVEL_OFF + bool "Off" +endchoice + endif # !TFM_BL2 # Option to instruct flashing a merged binary consisting of BL2 (optionally), @@ -431,6 +458,7 @@ endchoice config TFM_EXCEPTION_INFO_DUMP bool "TF-M exception info dump" + default y help On fatal errors in the secure firmware, capture info about the exception. Print the info if the SPM log level is sufficient. diff --git a/modules/trusted-firmware-m/Kconfig.tfm.partitions b/modules/trusted-firmware-m/Kconfig.tfm.partitions index cd9aaadb1ec4190..67b46f5328ba99d 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm.partitions +++ b/modules/trusted-firmware-m/Kconfig.tfm.partitions @@ -44,6 +44,7 @@ config TFM_PARTITION_CRYPTO config TFM_PARTITION_INITIAL_ATTESTATION bool "Secure partition 'Initial Attestation'" depends on TFM_PARTITION_CRYPTO + depends on TFM_INITIAL_ATTESTATION_KEY default n help Setting this option will cause '-DTFM_PARTITION_INITIAL_ATTESTATION' diff --git a/modules/trusted-firmware-m/interface/interface.c b/modules/trusted-firmware-m/interface/interface.c index ad0ed1abdfe654f..d949a9dc027af21 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 new file mode 100644 index 000000000000000..d75b34a8109889a --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt @@ -0,0 +1,63 @@ +# +# 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(partition_includes + ${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/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_sources(platform_s + PRIVATE + $<$:${CMAKE_CURRENT_SOURCE_DIR}/src/tfm_platform_system.c> +) + +target_include_directories(platform_s + PUBLIC + services/include + include + ${partition_includes} + ${board_includes} +) + +if(BL2) + target_include_directories(platform_bl2 + PUBLIC + include + include/util + ${partition_includes} + ${board_includes} + ) +endif() + +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/RTE_Device.h b/modules/trusted-firmware-m/nordic_nrf/include/RTE_Device.h new file mode 100644 index 000000000000000..ca886583fa92501 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/include/RTE_Device.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __RTE_DEVICE_H +#define __RTE_DEVICE_H + +#include + +/* ARRAY_SIZE causes a conflict as it is defined both by TF-M and indirectly by devicetree.h */ +#undef ARRAY_SIZE +#include + +#define UART_PIN_INIT(node_id, prop, idx) \ + DT_PROP_BY_IDX(node_id, prop, idx), + +/* Configuration settings for Driver_USART0. */ +#if DOMAIN_NS == 1U + +#define RTE_USART0 1 + +#define RTE_USART0_PINS \ +{ \ + DT_FOREACH_CHILD_VARGS( \ + DT_PINCTRL_BY_NAME(DT_NODELABEL(uart0), default, 0), \ + DT_FOREACH_PROP_ELEM, psels, UART_PIN_INIT \ + ) \ +} + +#endif + +/* Configuration settings for Driver_USART1. */ +#if DT_PINCTRL_HAS_NAME(DT_NODELABEL(uart1), default) && DOMAIN_NS != 1U + +#define RTE_USART1 1 + +#define RTE_USART1_PINS \ +{ \ + DT_FOREACH_CHILD_VARGS( \ + DT_PINCTRL_BY_NAME(DT_NODELABEL(uart1), default, 0), \ + DT_FOREACH_PROP_ELEM, psels, UART_PIN_INIT \ + ) \ +} + +#endif + +/* Configuration settings for Driver_FLASH0. */ +#define RTE_FLASH0 1 + +#endif /* __RTE_DEVICE_H */ diff --git a/modules/trusted-firmware-m/nordic_nrf/include/device_cfg.h b/modules/trusted-firmware-m/nordic_nrf/include/device_cfg.h new file mode 100644 index 000000000000000..9b766a35eb95645 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/include/device_cfg.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef DEVICE_CFG_H__ +#define DEVICE_CFG_H__ + +#include + +/* ARRAY_SIZE causes a conflict as it is defined both by TF-M and indirectly by devicetree.h */ +#undef ARRAY_SIZE +#include + +#if DOMAIN_NS == 1U +#define TFM_UART uart0 +#endif + +#if DOMAIN_NS != 1U +#define TFM_UART uart1 +#endif + +#define DEFAULT_UART_BAUDRATE DT_PROP_OR(DT_NODELABEL(TFM_UART), current_speed, 115200) + +#if DT_PROP(DT_NODELABEL(TFM_UART), hw_flow_control) +#define DEFAULT_UART_CONTROL ARM_USART_FLOW_CONTROL_RTS_CTS +#else +#define DEFAULT_UART_CONTROL 0 +#endif + +#endif /* DEVICE_CFG_H__ */ 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 new file mode 100644 index 000000000000000..3fade10525af04a --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/include/tfm_ioctl_api.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TFM_IOCTL_API_H__ +#define TFM_IOCTL_API_H__ + +#include +#include +#include + +/* Include core IOCTL services */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Board specific IOCTL services can be added here */ + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* TFM_IOCTL_API_H__ */ diff --git a/modules/trusted-firmware-m/nordic_nrf/include/tfm_peripherals_config.h b/modules/trusted-firmware-m/nordic_nrf/include/tfm_peripherals_config.h new file mode 100644 index 000000000000000..577b583ad033995 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/include/tfm_peripherals_config.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TFM_PERIPHERALS_CONFIG_H__ +#define TFM_PERIPHERALS_CONFIG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef SECURE_UART1 +#define TFM_PERIPHERAL_UARTE1_SECURE 1 +#endif + +#if TEST_NS_SLIH_IRQ || TEST_NS_FLIH_IRQ +#define TFM_PERIPHERAL_TIMER0_SECURE 1 +#endif + +#ifdef PSA_API_TEST_IPC +#define TFM_PERIPHERAL_EGU5_SECURE 1 + +#define TFM_PERIPHERAL_WDT_SECURE 1 +#endif + +#if defined(NRF91_SERIES) + #include +#elif defined(NRF5340_XXAA_APPLICATION) + #include +#else + #error "Unknown device." +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* TFM_PERIPHERAL_CONFIG_H__ */ diff --git a/modules/trusted-firmware-m/nordic_nrf/include/tfm_read_ranges.h b/modules/trusted-firmware-m/nordic_nrf/include/tfm_read_ranges.h new file mode 100644 index 000000000000000..43468c7fa319f5d --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/include/tfm_read_ranges.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TFM_READ_RANGES_H__ +#define TFM_READ_RANGES_H__ + +#include + +#include + +#ifdef NRF_FICR_S_BASE + +#define FICR_BASE NRF_FICR_S_BASE + +#define FICR_INFO_ADDR (FICR_BASE + offsetof(NRF_FICR_Type, INFO)) +#define FICR_INFO_SIZE (sizeof(FICR_INFO_Type)) + +#if defined(FICR_NFC_TAGHEADER0_MFGID_Msk) +#define FICR_NFC_ADDR (FICR_BASE + offsetof(NRF_FICR_Type, NFC)) +#define FICR_NFC_SIZE (sizeof(FICR_NFC_Type)) +#endif + +#if defined(FICR_XOSC32MTRIM_SLOPE_Msk) +#define FICR_XOSC32MTRIM_ADDR (FICR_BASE + offsetof(NRF_FICR_Type, XOSC32MTRIM)) +#define FICR_XOSC32MTRIM_SIZE (sizeof(uint32_t)) +#endif + +/* Used by nrf_erratas.h */ +#define FICR_RESTRICTED_ADDR (FICR_BASE + 0x130) +#define FICR_RESTRICTED_SIZE 0x8 + +#if defined(FICR_SIPINFO_PARTNO_PARTNO_Pos) +#define FICR_SIPINFO_ADDR (FICR_BASE + offsetof(NRF_FICR_Type, SIPINFO)) +#define FICR_SIPINFO_SIZE (sizeof(FICR_SIPINFO_Type)) +#endif + +#endif /* NRF_FICR_S_BASE */ + +static const struct tfm_read_service_range ranges[] = { +#if defined(FICR_INFO_ADDR) + { .start = FICR_INFO_ADDR, .size = FICR_INFO_SIZE }, +#endif +#if defined(FICR_NFC_ADDR) + { .start = FICR_NFC_ADDR, .size = FICR_NFC_SIZE }, +#endif +#if defined(FICR_RESTRICTED_ADDR) + { .start = FICR_RESTRICTED_ADDR, .size = FICR_RESTRICTED_SIZE }, +#endif +#if defined(FICR_XOSC32MTRIM_ADDR) + { .start = FICR_XOSC32MTRIM_ADDR, .size = FICR_XOSC32MTRIM_SIZE }, +#endif +#if defined(FICR_SIPINFO_ADDR) + { .start = FICR_SIPINFO_ADDR, .size = FICR_SIPINFO_SIZE }, +#endif +}; + +#endif /* TFM_READ_RANGES_H__ */ diff --git a/modules/trusted-firmware-m/nordic_nrf/include/util/array.h b/modules/trusted-firmware-m/nordic_nrf/include/util/array.h new file mode 100644 index 000000000000000..dc9a1f3dddf87a3 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/include/util/array.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ARRAY_H__ +#define __ARRAY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +} +#endif + +#endif /* __ARRAY_H__ */ diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt new file mode 100644 index 000000000000000..b74620fe2d51c85 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set(NRF_BOARD_SELECTED True) + +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 new file mode 100644 index 000000000000000..ae50a4846dd51fc --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/config.cmake @@ -0,0 +1,9 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +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 000000000000000..f19d7f43c673015 --- /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 000000000000000..077e88bd37b4cba --- /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/nrf9120/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/nrf9120/CMakeLists.txt new file mode 100644 index 000000000000000..64fff7cdb860f8b --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9120/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set(NRF_BOARD_SELECTED True) + +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 new file mode 100644 index 000000000000000..e858eda3a270dd5 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9120/config.cmake @@ -0,0 +1,9 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +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 000000000000000..9f0886c7a51e4db --- /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 000000000000000..c53d684d7e881d1 --- /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/nrf9160/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/nrf9160/CMakeLists.txt new file mode 100644 index 000000000000000..aa2ef83103152ad --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9160/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set(NRF_BOARD_SELECTED True) + +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 new file mode 100644 index 000000000000000..e858eda3a270dd5 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9160/config.cmake @@ -0,0 +1,9 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +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 000000000000000..f728014d3f72127 --- /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 000000000000000..902e7fe7ef49891 --- /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/ns/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/ns/CMakeLists.txt new file mode 100644 index 000000000000000..5bb8cb5bd94ae14 --- /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/nordic_nrf/src/tfm_hal_platform.c b/modules/trusted-firmware-m/nordic_nrf/src/tfm_hal_platform.c new file mode 100644 index 000000000000000..508c19459106c55 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/src/tfm_hal_platform.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "tfm_hal_defs.h" +#include "tfm_hal_platform_common.h" + +enum tfm_hal_status_t tfm_hal_platform_init(void) +{ + return tfm_hal_platform_common_init(); +} diff --git a/modules/trusted-firmware-m/nordic_nrf/src/tfm_platform_system.c b/modules/trusted-firmware-m/nordic_nrf/src/tfm_platform_system.c new file mode 100644 index 000000000000000..b96e1fe11887f2e --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/src/tfm_platform_system.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "platform/include/tfm_platform_system.h" +#include "cmsis.h" +#include "tfm_platform_hal_ioctl.h" +#include "tfm_ioctl_core_api.h" + +void tfm_platform_hal_system_reset(void) +{ + /* Reset the system */ + NVIC_SystemReset(); +} + +enum tfm_platform_err_t tfm_platform_hal_ioctl(tfm_platform_ioctl_req_t request, + psa_invec *in_vec, + psa_outvec *out_vec) +{ + /* Core IOCTL services */ + switch (request) { + case TFM_PLATFORM_IOCTL_READ_SERVICE: + return tfm_platform_hal_read_service(in_vec, out_vec); +#if defined(GPIO_PIN_CNF_MCUSEL_Msk) + case TFM_PLATFORM_IOCTL_GPIO_SERVICE: + return tfm_platform_hal_gpio_service(in_vec, out_vec); +#endif /* defined(GPIO_PIN_CNF_MCUSEL_Msk) */ + + + /* Board specific IOCTL services */ + + /* Not a supported IOCTL service.*/ + default: + return TFM_PLATFORM_ERR_NOT_SUPPORTED; + } +} 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 d7d68f9db67324c..000000000000000 --- 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 e23ad7da2e674d2..aaf842e392ca668 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 33b60bdfbcb4dcd..45535fc8594ac56 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 5b71f8f45ae57a4..655fb2ed2a84a7f 100644 --- a/modules/zcbor/Kconfig +++ b/modules/zcbor/Kconfig @@ -6,6 +6,7 @@ config ZEPHYR_ZCBOR_MODULE config ZCBOR bool "zcbor CBOR library" + depends on ZEPHYR_ZCBOR_MODULE help zcbor CBOR encoder/decoder library @@ -32,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/application_development/code_relocation_nocopy/linker_arm_nocopy.ld b/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld index 916b1efe7fa6956..7ead7f6bae48314 100644 --- a/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld +++ b/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld @@ -32,7 +32,7 @@ * Add another fake portion of FLASH to simulate a secondary or external FLASH * that we can do XIP from. */ -#define EXTFLASH_ADDR 0x5000 +#define EXTFLASH_ADDR 0x7000 #define EXTFLASH_SIZE (CONFIG_FLASH_SIZE * 1K - EXTFLASH_ADDR) #endif diff --git a/samples/application_development/external_lib/sample.yaml b/samples/application_development/external_lib/sample.yaml index dc06cb4c903ec85..69cbd486e23fcd6 100644 --- a/samples/application_development/external_lib/sample.yaml +++ b/samples/application_development/external_lib/sample.yaml @@ -3,7 +3,7 @@ sample: tests: sample.app_dev.external_lib: integration_platforms: - - native_posix + - native_sim tags: external harness: console harness_config: diff --git a/samples/arch/smp/pi/src/main.c b/samples/arch/smp/pi/src/main.c index e141f8f5f1b4a48..f5797c43f79b1de 100644 --- a/samples/arch/smp/pi/src/main.c +++ b/samples/arch/smp/pi/src/main.c @@ -90,7 +90,7 @@ int main(void) for (i = 0; i < THREADS_NUM; i++) { k_thread_create(&tthread[i], tstack[i], STACK_SIZE, - (k_thread_entry_t)test_thread, + test_thread, (void *)&th_counter, (void *)th_buffer[i], NULL, K_PRIO_COOP(10), 0, K_NO_WAIT); } diff --git a/samples/arch/smp/pktqueue/src/main.c b/samples/arch/smp/pktqueue/src/main.c index 11d3ea36c73d38e..07363a8d2341d6d 100644 --- a/samples/arch/smp/pktqueue/src/main.c +++ b/samples/arch/smp/pktqueue/src/main.c @@ -101,7 +101,6 @@ void test_thread(void *arg1, void *arg2, void *arg3) /* Thread that processes one pair of sender/receiver queue */ void queue_thread(void *arg1, void *arg2, void *arg3) { - ARG_UNUSED(arg1); ARG_UNUSED(arg2); ARG_UNUSED(arg3); @@ -117,7 +116,7 @@ void queue_thread(void *arg1, void *arg2, void *arg3) for (int i = 0; i < THREADS_NUM; i++) k_thread_create(&tthread[i+THREADS_NUM*queue_num], tstack[i+THREADS_NUM*queue_num], STACK_SIZE, - (k_thread_entry_t)test_thread, + test_thread, (void *)&sender[queue_num], (void *)&receiver[queue_num], (void *)&queue_num, K_PRIO_PREEMPT(10), 0, K_NO_WAIT); @@ -156,7 +155,7 @@ int main(void) for (int i = 0; i < QUEUE_NUM; i++) k_thread_create(&qthread[i], qstack[i], STACK_SIZE, - (k_thread_entry_t)queue_thread, + queue_thread, (void *)&sender[i], (void *)&receiver[i], (void *)&i, K_PRIO_PREEMPT(11), 0, K_NO_WAIT); diff --git a/samples/basic/blinky/README.rst b/samples/basic/blinky/README.rst index 893d00b51032b89..ec23fe5403f149b 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 fb86da1abdca103..4cab4969d94b5fc 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 fc5466c9cbe4a39..a9a1d685e9961d0 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 a438cc5246b4e60..a9a1d685e9961d0 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 a438cc5246b4e60..a9a1d685e9961d0 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 a438cc5246b4e60..a9a1d685e9961d0 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 5709c54d1803141..a9a1d685e9961d0 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 c6ca7b5a52b4b7f..99d9e2d9bfdb115 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 61152f82f94d521..70069ad3b1013fe 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 61152f82f94d521..70069ad3b1013fe 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 000000000000000..cf60fe058b7b70e --- /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 045056613e08043..86ffa3dcdf00015 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/README.rst b/samples/basic/hash_map/README.rst index 403ef297923352d..0c5d91a3dae77ce 100644 --- a/samples/basic/hash_map/README.rst +++ b/samples/basic/hash_map/README.rst @@ -16,16 +16,16 @@ This is a simple example that repeatedly: Building ******** -This application can be built on native_posix as follows: +This application can be built on :ref:`native_sim ` as follows: .. zephyr-app-commands:: :zephyr-app: samples/basic/hash_map :host-os: unix - :board: native_posix + :board: native_sim :goals: build :compact: -To build for another board, change "native_posix" above to that board's name. +To build for another board, change "native_sim" above to that board's name. Additionally, it is possible to use one of the other Hashmap implementations by specifying diff --git a/samples/basic/hash_map/sample.yaml b/samples/basic/hash_map/sample.yaml index 40dec267473c0a3..9e1ee6558cab547 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/basic/sys_heap/README.rst b/samples/basic/sys_heap/README.rst index 2b124400cde7e70..74eb2b9e3320e03 100644 --- a/samples/basic/sys_heap/README.rst +++ b/samples/basic/sys_heap/README.rst @@ -10,18 +10,18 @@ A simple sample that can be used with any :ref:`supported board ` and prints system heap usage to the console. Building -******************** +******** -This application can be built on native_posix as follows: +This application can be built on :ref:`native_sim ` as follows: .. zephyr-app-commands:: :zephyr-app: samples/basic/sys_heap :host-os: unix - :board: native_posix + :board: native_sim :goals: build :compact: -To build for another board, change "native_posix" above to that board's name. +To build for another board, change "native_sim" above to that board's name. Running ******* diff --git a/samples/basic/sys_heap/sample.yaml b/samples/basic/sys_heap/sample.yaml index 9e9f45c90ca71b0..d6179247991d490 100644 --- a/samples/basic/sys_heap/sample.yaml +++ b/samples/basic/sys_heap/sample.yaml @@ -3,7 +3,7 @@ sample: name: Basic system heap sample common: integration_platforms: - - native_posix + - native_sim harness: console harness_config: type: multi_line diff --git a/samples/bluetooth/bluetooth.rst b/samples/bluetooth/bluetooth.rst index e9c44451d363589..0b59b9626b4ea81 100644 --- a/samples/bluetooth/bluetooth.rst +++ b/samples/bluetooth/bluetooth.rst @@ -6,13 +6,13 @@ Bluetooth samples To build any of the Bluetooth samples, follow the same steps as building any other Zephyr application. Refer to :ref:`bluetooth-dev` for more information. -Many Bluetooth samples can be run on QEMU or Native POSIX with support for +Many Bluetooth samples can be run on QEMU or :ref:`native_sim ` with support for external Bluetooth Controllers. Refer to the :ref:`bluetooth-hw-setup` section for further details. Several of the bluetooth samples will build a Zephyr-based Controller that can then be used with any external Host (including Zephyr running natively or with -QEMU or Native POSIX), those are named accordingly with an "HCI" prefix in the +QEMU or ``native_sim``), those are named accordingly with an "HCI" prefix in the documentation and are prefixed with :literal:`hci_` in their folder names. .. note:: @@ -20,7 +20,7 @@ documentation and are prefixed with :literal:`hci_` in their folder names. ``-DBOARD=nrf5340dk_nrf5340_cpuapp`` or ``-DBOARD=nrf5340dk_nrf5340_cpuapp_ns``) you must also build and program the corresponding sample for the nRF5340 network core - :ref:`bluetooth-hci-rpmsg-sample` which implements the Bluetooth + :ref:`bluetooth-hci-ipc-sample` which implements the Bluetooth Low Energy controller. .. note:: diff --git a/samples/bluetooth/broadcast_audio_sink/Kconfig b/samples/bluetooth/broadcast_audio_sink/Kconfig index 7a61a7b64fc6076..b70a42e2d995488 100644 --- a/samples/bluetooth/broadcast_audio_sink/Kconfig +++ b/samples/bluetooth/broadcast_audio_sink/Kconfig @@ -28,4 +28,19 @@ config SCAN_DELAY Time to advertise connectable for a Broadcast Assistant to connect before starting scanning for Broadcast Sources. +config TARGET_BROADCAST_NAME + string "Target Broadcast Device Name" + default "" + help + Name of target broadcast device. If not empty string, sink device + will only listen to the specified broadcast source. Not case sensitive. + +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) + select LIBLC3 + select FPU + source "Kconfig.zephyr" diff --git a/samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild b/samples/bluetooth/broadcast_audio_sink/Kconfig.sysbuild new file mode 100644 index 000000000000000..f434010f81d27ce --- /dev/null +++ b/samples/bluetooth/broadcast_audio_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/broadcast_audio_sink/README.rst b/samples/bluetooth/broadcast_audio_sink/README.rst index cb0aabc970d618e..aca5d18bb94a880 100644 --- a/samples/bluetooth/broadcast_audio_sink/README.rst +++ b/samples/bluetooth/broadcast_audio_sink/README.rst @@ -1,7 +1,8 @@ -.. _bluetooth_broadcast_audio_sink: +.. zephyr:code-sample:: bluetooth_broadcast_audio_sink + :name: Bluetooth: Broadcast Audio Sink + :relevant-api: bluetooth -Bluetooth: Broadcast Audio Sink -############################### + Bluetooth: Broadcast Audio Sink Overview ******** @@ -10,6 +11,15 @@ Application demonstrating the LE Audio broadcast sink functionality. Starts by scanning for LE Audio broadcast sources and then synchronizes to the first found and listens to it until the source is (potentially) stopped. +This sample can be found under +:zephyr_file:`samples/bluetooth/broadcast_audio_sink` in the Zephyr tree. + +Check the :ref:`bluetooth samples section ` for general information. + +Use `CONFIG_TARGET_BROADCAST_NAME` Kconfig to specify the name (CONFIG_BT_DEVICE_NAME) +of a broadcast source to listen to. With default value (empty string), sink +device will listen to all available broadcast sources. + Requirements ************ @@ -18,9 +28,53 @@ Requirements Building and Running ******************** -This sample can be found under -:zephyr_file:`samples/bluetooth/broadcast_audio_sink` in the Zephyr tree. -Use `-DEXTRA_CONF_FILE=overlay-bt_ll_sw_split.conf` to enable required ISO -feature support in Zephyr Bluetooth Controller on supported boards. -See :ref:`bluetooth samples section ` for details. +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/broadcast_audio_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/broadcast_audio_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/broadcast_audio_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/broadcast_audio_sink/ + :board: nrf52_bsim + :goals: build + :gen-args: -DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf 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 new file mode 100644 index 000000000000000..8ab7a163fb664e3 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -0,0 +1,3 @@ +# 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 diff --git a/samples/bluetooth/broadcast_audio_sink/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/bluetooth/broadcast_audio_sink/boards/nrf5340dk_nrf5340_cpuapp.conf new file mode 100644 index 000000000000000..8ab7a163fb664e3 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_sink/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -0,0 +1,3 @@ +# 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 diff --git a/samples/bluetooth/broadcast_audio_sink/overlay-bt_ll_sw_split.conf b/samples/bluetooth/broadcast_audio_sink/overlay-bt_ll_sw_split.conf index bc0ba2c6cddb578..e336dae38e1f15b 100644 --- a/samples/bluetooth/broadcast_audio_sink/overlay-bt_ll_sw_split.conf +++ b/samples/bluetooth/broadcast_audio_sink/overlay-bt_ll_sw_split.conf @@ -10,3 +10,7 @@ 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/broadcast_audio_sink/prj.conf b/samples/bluetooth/broadcast_audio_sink/prj.conf index 11e0971638a06ea..c8adced28cebca5 100644 --- a/samples/bluetooth/broadcast_audio_sink/prj.conf +++ b/samples/bluetooth/broadcast_audio_sink/prj.conf @@ -10,5 +10,9 @@ CONFIG_BT_ISO_MAX_CHAN=2 CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT=2 CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT=2 CONFIG_BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS=2 +CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_SIZE=251 CONFIG_BT_DEVICE_NAME="Broadcast Audio Sink" + +CONFIG_BT_TINYCRYPT_ECC=y diff --git a/samples/bluetooth/broadcast_audio_sink/sample.yaml b/samples/bluetooth/broadcast_audio_sink/sample.yaml index a423dbcde180e2a..e81b86de3e0b600 100644 --- a/samples/bluetooth/broadcast_audio_sink/sample.yaml +++ b/samples/bluetooth/broadcast_audio_sink/sample.yaml @@ -8,10 +8,12 @@ tests: - qemu_cortex_m3 - qemu_x86 - nrf5340dk_nrf5340_cpuapp + - nrf5340bsim_nrf5340_cpuapp integration_platforms: - qemu_x86 - nrf5340dk_nrf5340_cpuapp tags: bluetooth + sysbuild: true sample.bluetooth.broadcast_audio_sink.bt_ll_sw_split: harness: bluetooth platform_allow: diff --git a/samples/bluetooth/broadcast_audio_sink/src/main.c b/samples/bluetooth/broadcast_audio_sink/src/main.c index 1d8613386fbe988..587cb59dc51ff2e 100644 --- a/samples/bluetooth/broadcast_audio_sink/src/main.c +++ b/samples/bluetooth/broadcast_audio_sink/src/main.c @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include +#include + #include #include #include @@ -25,6 +28,7 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_SCAN_SELF) || IS_ENABLED(CONFIG_SCAN_OFFLOAD), #define INVALID_BROADCAST_ID (BT_AUDIO_BROADCAST_ID_MAX + 1) #define SYNC_RETRY_COUNT 6 /* similar to retries for connections */ #define PA_SYNC_SKIP 5 +#define NAME_LEN sizeof(CONFIG_TARGET_BROADCAST_NAME) + 1 static K_SEM_DEFINE(sem_connected, 0U, 1U); static K_SEM_DEFINE(sem_disconnected, 0U, 1U); @@ -46,7 +50,19 @@ static struct bt_le_scan_recv_info broadcaster_info; static bt_addr_le_t broadcaster_addr; static struct bt_le_per_adv_sync *pa_sync; static uint32_t broadcaster_broadcast_id; -static struct bt_bap_stream streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; +static struct broadcast_sink_stream { + struct bt_bap_stream stream; + size_t recv_cnt; + size_t loss_cnt; + size_t error_cnt; + size_t valid_cnt; +#if defined(CONFIG_LIBLC3) + struct net_buf *in_buf; + struct k_work_delayable lc3_decode_work; +/* Internal lock for protecting net_buf from multiple access */ + struct k_mutex lc3_decoder_mutex; +#endif /* defined(CONFIG_LIBLC3) */ +} 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; static struct bt_le_ext_adv *ext_adv; @@ -65,10 +81,118 @@ static uint32_t requested_bis_sync; static uint32_t bis_index_bitfield; 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) + +#include "lc3.h" + +#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 int16_t audio_buf[MAX_NUM_SAMPLES]; +static lc3_decoder_t lc3_decoder; +static lc3_decoder_mem_16k_t lc3_decoder_mem; +static int frames_per_sdu; + +static int lc3_enable(const struct bt_audio_codec_cfg *codec_cfg) +{ + int ret; + int freq_hz; + int frame_duration_us; + + printk("Enable: stream with codec %p\n", codec_cfg); + + 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; + } + + 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; + } + + 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; + } + + return 0; +} + +static void lc3_decode_handler(struct k_work *work) +{ + 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); + + 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; + } + + ptr_net_buf = net_buf_ref(sink_stream->in_buf); + net_buf_unref(sink_stream->in_buf); + sink_stream->in_buf = NULL; + k_mutex_unlock(&sink_stream->lc3_decoder_mutex); + + buf_data = ptr_net_buf->data; + 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); + + if (err == 1) { + printk(" decoder performed PLC\n"); + } else if (err < 0) { + printk(" decoder failed - wrong parameters?\n"); + } + + offset += octets_per_frame; + } + + net_buf_unref(ptr_net_buf); +} + +#endif /* defined(CONFIG_LIBLC3) */ + static void stream_started_cb(struct bt_bap_stream *stream) { + struct broadcast_sink_stream *sink_stream = + CONTAINER_OF(stream, struct broadcast_sink_stream, stream); + printk("Stream %p started\n", stream); + total_rx_iso_packet_count = 0U; + sink_stream->recv_cnt = 0U; + sink_stream->loss_cnt = 0U; + 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) */ k_sem_give(&sem_bis_synced); } @@ -84,51 +208,115 @@ static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) } } -static void stream_recv_cb(struct bt_bap_stream *stream, - const struct bt_iso_recv_info *info, +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; + struct broadcast_sink_stream *sink_stream = + CONTAINER_OF(stream, struct broadcast_sink_stream, stream); if (info->flags & BT_ISO_FLAGS_ERROR) { - printk("ISO receive error\n"); - return; + sink_stream->error_cnt++; } if (info->flags & BT_ISO_FLAGS_LOST) { - printk("ISO receive lost\n"); - return; + sink_stream->loss_cnt++; } - recv_cnt++; - if ((recv_cnt % 1000U) == 0U) { - printk("Received %u total ISO packets\n", recv_cnt); + if (info->flags & BT_ISO_FLAGS_VALID) { + sink_stream->valid_cnt++; +#if defined(CONFIG_LIBLC3) + k_mutex_lock(&sink_stream->lc3_decoder_mutex, K_FOREVER); + if (sink_stream->in_buf != NULL) { + net_buf_unref(sink_stream->in_buf); + sink_stream->in_buf = NULL; + } + + 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); +#endif /* defined(CONFIG_LIBLC3) */ + } + + total_rx_iso_packet_count++; + sink_stream->recv_cnt++; + if ((sink_stream->recv_cnt % 1000U) == 0U) { + printk("Stream %p: received %u total ISO packets: Valid %u | Error %u | Loss %u\n", + &sink_stream->stream, sink_stream->recv_cnt, sink_stream->valid_cnt, + sink_stream->error_cnt, sink_stream->loss_cnt); } } static struct bt_bap_stream_ops stream_ops = { .started = stream_started_cb, .stopped = stream_stopped_cb, - .recv = stream_recv_cb + .recv = stream_recv_cb, }; -static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base) +#if defined(CONFIG_LIBLC3) +static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + struct bt_audio_codec_cfg *codec_cfg = user_data; + struct bt_bap_base_codec_id codec_id; + int ret; + + ret = bt_bap_base_get_subgroup_codec_id(subgroup, &codec_id); + if (ret < 0) { + printk("Could not get codec id for subgroup %p: %d", subgroup, ret); + return true; + } + + if (codec_id.id != BT_HCI_CODING_FORMAT_LC3) { + printk("Unsupported codec for subgroup %p: 0x%02x", subgroup, codec_id.id); + return true; /* parse next subgroup */ + } + + ret = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, codec_cfg); + if (ret < 0) { + printk("Could convert subgroup %p to codec_cfg: %d", subgroup, ret); + return true; + } + + return false; /* We only care about the first subgroup with LC3 */ +} +#endif /* CONFIG_LIBLC3 */ + +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 %u subgroups from broadcast sink %p\n", - base->subgroup_count, sink); + printk("Received BASE with %d subgroups from broadcast sink %p\n", + bt_bap_base_get_subgroup_count(base), sink); - 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; +#if defined(CONFIG_LIBLC3) + struct bt_audio_codec_cfg codec_cfg = {0}; - base_bis_index_bitfield |= BIT(index); - } + err = bt_bap_base_foreach_subgroup(base, base_subgroup_cb, &codec_cfg); + if (err != 0 && err != -ECANCELED) { + printk("Failed to parse subgroups: %d\n", err); + return; + } else if (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(&codec_cfg); + if (err < 0) { + printk("Error: cannot enable LC3 codec: %d", err); + return; + } +#endif /* CONFIG_LIBLC3 */ + + err = bt_bap_base_get_bis_indexes(base, &base_bis_index_bitfield); + if (err != 0) { + printk("Failed to BIS indexes: %d\n", err); + return; } bis_index_bitfield = base_bis_index_bitfield & bis_index_mask; @@ -420,9 +608,57 @@ static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data) return false; } +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 bool data_cb(struct bt_data *data, void *user_data) +{ + char *name = user_data; + + switch (data->type) { + case BT_DATA_NAME_SHORTENED: + case BT_DATA_NAME_COMPLETE: + case BT_DATA_BROADCAST_NAME: + memcpy(name, data->data, MIN(data->data_len, NAME_LEN - 1)); + return false; + default: + return true; + } +} + static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad) { if (info->interval != 0U) { + /* call to bt_data_parse consumes netbufs so shallow clone for verbose output */ + if (strlen(CONFIG_TARGET_BROADCAST_NAME) > 0U) { + struct net_buf_simple buf_copy; + char name[NAME_LEN] = {0}; + + net_buf_simple_clone(ad, &buf_copy); + bt_data_parse(&buf_copy, data_cb, name); + if (!(is_substring(CONFIG_TARGET_BROADCAST_NAME, name))) { + return; + } + } bt_data_parse(ad, scan_check_and_sync_broadcast, (void *)info); } } @@ -482,7 +718,7 @@ static int init(void) bt_le_scan_cb_register(&bap_scan_cb); for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { - streams[i].ops = &stream_ops; + streams[i].stream.ops = &stream_ops; } return 0; @@ -573,7 +809,6 @@ static int reset(void) k_sem_reset(&sem_broadcast_code_received); k_sem_reset(&sem_bis_sync_requested); k_sem_reset(&sem_bis_synced); - return 0; } @@ -659,10 +894,15 @@ int main(void) } for (size_t i = 0U; i < ARRAY_SIZE(streams_p); i++) { - streams_p[i] = &streams[i]; + streams_p[i] = &streams[i].stream; +#if defined(CONFIG_LIBLC3) + k_mutex_init(&streams[i].lc3_decoder_mutex); +#endif /* defined(CONFIG_LIBLC3) */ } while (true) { + uint32_t sync_bitfield; + err = reset(); if (err != 0) { printk("Resetting failed: %d - Aborting\n", err); @@ -709,7 +949,13 @@ int main(void) } } - printk("Scanning for broadcast sources\n"); + if (strlen(CONFIG_TARGET_BROADCAST_NAME) > 0U) { + printk("Scanning for broadcast sources containing`" + CONFIG_TARGET_BROADCAST_NAME "`\n"); + } else { + printk("Scanning for broadcast sources\n"); + } + err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL); if (err != 0 && err != -EALREADY) { printk("Unable to start scan for broadcast sources: %d\n", @@ -785,10 +1031,10 @@ int main(void) continue; } - printk("Syncing to broadcast\n"); - err = bt_bap_broadcast_sink_sync(broadcast_sink, - bis_index_bitfield & requested_bis_sync, - streams_p, sink_broadcast_code); + sync_bitfield = bis_index_bitfield & requested_bis_sync; + printk("Syncing to broadcast with bitfield: 0x%08x\n", sync_bitfield); + err = bt_bap_broadcast_sink_sync(broadcast_sink, sync_bitfield, streams_p, + sink_broadcast_code); if (err != 0) { printk("Unable to sync to broadcast source: %d\n", err); return 0; diff --git a/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake b/samples/bluetooth/broadcast_audio_sink/sysbuild.cmake new file mode 100644 index 000000000000000..2523aac8ea76f16 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_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/broadcast_audio_source/Kconfig b/samples/bluetooth/broadcast_audio_source/Kconfig new file mode 100644 index 000000000000000..683eeaf9dbffdb2 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_source/Kconfig @@ -0,0 +1,41 @@ +# Copyright (c) 2023 Demant A/S +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "Bluetooth: Broadcast Audio Source" + +choice BAP_LC3_PRESET + prompt "The BAP LC3 Preset to be used" + default BAP_BROADCAST_16_2_1 + +config BAP_BROADCAST_16_2_1 + bool "BAP_LC3_BROADCAST_PRESET_16_2_1 preset" + help + Using the BAP_LC3_BROADCAST_PRESET_16_2_1 preset. + +config BAP_BROADCAST_24_2_1 + bool "BAP_LC3_BROADCAST_PRESET_24_2_1 preset" + help + Using the BAP_LC3_BROADCAST_PRESET_24_2_1 preset. + +endchoice + +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 CPU_HAS_FPU && \ + (ARCH_POSIX || SOC_COMPATIBLE_NRF52X || SOC_COMPATIBLE_NRF5340_CPUAPP) + select LIBLC3 + select FPU + +config USE_USB_AUDIO_INPUT + bool "Use USB Audio as input" + # By default, use the USB Audio path is disabled. + default n + depends on ENABLE_LC3 + select USB_DEVICE_STACK + select USB_DEVICE_AUDIO + select RING_BUFFER + +source "Kconfig.zephyr" diff --git a/samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild b/samples/bluetooth/broadcast_audio_source/Kconfig.sysbuild new file mode 100644 index 000000000000000..f434010f81d27ce --- /dev/null +++ b/samples/bluetooth/broadcast_audio_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/broadcast_audio_source/README.rst b/samples/bluetooth/broadcast_audio_source/README.rst index 12fb6c0ca1a636d..1c36236231b77a7 100644 --- a/samples/bluetooth/broadcast_audio_source/README.rst +++ b/samples/bluetooth/broadcast_audio_source/README.rst @@ -1,7 +1,8 @@ -.. _bluetooth_broadcast_audio_source: +.. zephyr:code-sample:: bluetooth_broadcast_audio_source + :name: Bluetooth: Broadcast Audio Source + :relevant-api: bluetooth -Bluetooth: Broadcast Audio Source -################################# + Bluetooth: Broadcast Audio Source Overview ******** @@ -13,6 +14,11 @@ broadcast audio source endpoint (BASE) and finally the BIGinfo together with The broadcast source will reset every 30 seconds to show the full API. +This sample can be found under +:zephyr_file:`samples/bluetooth/broadcast_audio_source` in the Zephyr tree. + +Check the :ref:`bluetooth samples section ` for general information. + Requirements ************ @@ -21,9 +27,53 @@ Requirements Building and Running ******************** -This sample can be found under -:zephyr_file:`samples/bluetooth/broadcast_audio_source` in the Zephyr tree. -Use `-DEXTRA_CONF_FILE=overlay-bt_ll_sw_split.conf` to enable required ISO -feature support in Zephyr Bluetooth Controller on supported boards. -See :ref:`bluetooth samples section ` for details. +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/broadcast_audio_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/broadcast_audio_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/broadcast_audio_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/broadcast_audio_source/ + :board: nrf52_bsim + :goals: build + :gen-args: -DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf 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 000000000000000..ff68bab6356b3ff --- /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 000000000000000..b8e72f1b61c5bc1 --- /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 000000000000000..ff68bab6356b3ff --- /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 000000000000000..b8e72f1b61c5bc1 --- /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/nrf52_bsim.conf b/samples/bluetooth/broadcast_audio_source/boards/nrf52_bsim.conf new file mode 100644 index 000000000000000..5df721fba267419 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf52_bsim.conf @@ -0,0 +1 @@ +CONFIG_MAIN_STACK_SIZE=4096 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 new file mode 100644 index 000000000000000..ff68bab6356b3ff --- /dev/null +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf5340_audio_dk_nrf5340_cpuapp.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/nrf5340bsim_nrf5340_cpuapp.conf b/samples/bluetooth/broadcast_audio_source/boards/nrf5340bsim_nrf5340_cpuapp.conf new file mode 100644 index 000000000000000..5df721fba267419 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf5340bsim_nrf5340_cpuapp.conf @@ -0,0 +1 @@ +CONFIG_MAIN_STACK_SIZE=4096 diff --git a/samples/bluetooth/broadcast_audio_source/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/bluetooth/broadcast_audio_source/boards/nrf5340dk_nrf5340_cpuapp.conf new file mode 100644 index 000000000000000..5df721fba267419 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -0,0 +1 @@ +CONFIG_MAIN_STACK_SIZE=4096 diff --git a/samples/bluetooth/broadcast_audio_source/prj.conf b/samples/bluetooth/broadcast_audio_source/prj.conf index 89210995535e759..746b7fff42341c9 100644 --- a/samples/bluetooth/broadcast_audio_source/prj.conf +++ b/samples/bluetooth/broadcast_audio_source/prj.conf @@ -7,7 +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 1c3904d8c8229ca..3c55480340933bd 100644 --- a/samples/bluetooth/broadcast_audio_source/sample.yaml +++ b/samples/bluetooth/broadcast_audio_source/sample.yaml @@ -8,18 +8,22 @@ tests: - qemu_cortex_m3 - qemu_x86 - nrf5340dk_nrf5340_cpuapp + - nrf5340bsim_nrf5340_cpuapp integration_platforms: - qemu_x86 - nrf5340dk_nrf5340_cpuapp tags: bluetooth + sysbuild: true sample.bluetooth.broadcast_audio_source.bt_ll_sw_split: harness: bluetooth platform_allow: - 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 e30243791b5f6b8..ee343f5123f4b09 100644 --- a/samples/bluetooth/broadcast_audio_source/src/main.c +++ b/samples/bluetooth/broadcast_audio_source/src/main.c @@ -9,22 +9,119 @@ #include #include +/* Zephyr Controller works best while Extended Advertising interval to be a multiple + * of the ISO Interval minus 10 ms (max. advertising random delay). This is + * required to place the AUX_ADV_IND PDUs in a non-overlapping interval with the + * Broadcast ISO radio events. + * + * I.e. for a 7.5 ms ISO interval use 90 ms minus 10 ms ==> 80 ms advertising + * interval. + * And, for 10 ms ISO interval, can use 90 ms minus 10 ms ==> 80 ms advertising + * interval. + */ +#define BT_LE_EXT_ADV_CUSTOM \ + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_USE_NAME, 0x0080, 0x0080, NULL) + /* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that * the controller is never idle */ -#define BROADCAST_ENQUEUE_COUNT 2U -#define TOTAL_BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT) +#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, "CONFIG_BT_ISO_TX_BUF_COUNT should be at least " "BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT"); -static struct bt_bap_lc3_preset preset_16_2_1 = BT_BAP_LC3_BROADCAST_PRESET_16_2_1( - BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); +#if defined(CONFIG_BAP_BROADCAST_16_2_1) + +static struct bt_bap_lc3_preset preset_active = BT_BAP_LC3_BROADCAST_PRESET_16_2_1( + BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT, + BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + +#define BROADCAST_SAMPLE_RATE 16000 + +#elif defined(CONFIG_BAP_BROADCAST_24_2_1) + +static struct bt_bap_lc3_preset preset_active = BT_BAP_LC3_BROADCAST_PRESET_24_2_1( + BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT, + BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + +#define BROADCAST_SAMPLE_RATE 24000 + +#endif + +#if defined(CONFIG_BAP_BROADCAST_16_2_1) +#define MAX_SAMPLE_RATE 16000 +#elif defined(CONFIG_BAP_BROADCAST_24_2_1) +#define MAX_SAMPLE_RATE 24000 +#endif +#define MAX_FRAME_DURATION_US 10000 +#define MAX_NUM_SAMPLES ((MAX_FRAME_DURATION_US * MAX_SAMPLE_RATE) / USEC_PER_SEC) + +#if defined(CONFIG_LIBLC3) +#include "lc3.h" + +#if defined(CONFIG_USB_DEVICE_AUDIO) +#include +#include +#include + +/* USB Audio Data is downsampled from 48kHz to match broadcast preset when receiving data */ +#define USB_SAMPLE_RATE 48000 +#define USB_DOWNSAMPLE_RATE BROADCAST_SAMPLE_RATE +#define USB_FRAME_DURATION_US 1000 +#define USB_NUM_SAMPLES ((USB_FRAME_DURATION_US * USB_DOWNSAMPLE_RATE) / USEC_PER_SEC) +#define USB_BYTES_PER_SAMPLE 2 +#define USB_CHANNELS 2 + +#define RING_BUF_USB_FRAMES 20 +#define AUDIO_RING_BUF_BYTES USB_NUM_SAMPLES * USB_BYTES_PER_SAMPLE * RING_BUF_USB_FRAMES +#else /* !defined(CONFIG_USB_DEVICE_AUDIO) */ + +#include + +#define AUDIO_VOLUME (INT16_MAX - 3000) /* codec does clipping above INT16_MAX - 3000 */ +#define AUDIO_TONE_FREQUENCY_HZ 400 + +/** + * Use the math lib to generate a sine-wave using 16 bit samples into a buffer. + * + * @param buf Destination buffer + * @param length_us Length of the buffer in microseconds + * @param frequency_hz frequency in Hz + * @param sample_rate_hz sample-rate in Hz. + */ +static void fill_audio_buf_sin(int16_t *buf, int length_us, int frequency_hz, int sample_rate_hz) +{ + const int sine_period_samples = sample_rate_hz / frequency_hz; + const unsigned int num_samples = (length_us * sample_rate_hz) / USEC_PER_SEC; + const float step = 2 * 3.1415f / sine_period_samples; + + for (unsigned int i = 0; i < num_samples; i++) { + const float sample = sinf(i * step); + + buf[i] = (int16_t)(AUDIO_VOLUME * sample); + } +} +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ +#endif /* defined(CONFIG_LIBLC3) */ + static struct broadcast_source_stream { struct bt_bap_stream stream; uint16_t seq_num; size_t sent_cnt; +#if defined(CONFIG_LIBLC3) + lc3_encoder_t lc3_encoder; +#if defined(CONFIG_BAP_BROADCAST_16_2_1) + lc3_encoder_mem_16k_t lc3_encoder_mem; +#elif defined(CONFIG_BAP_BROADCAST_24_2_1) + lc3_encoder_mem_48k_t lc3_encoder_mem; +#endif +#if defined(CONFIG_USB_DEVICE_AUDIO) + struct ring_buf audio_ring_buf; + uint8_t _ring_buffer_memory[AUDIO_RING_BUF_BYTES]; +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ +#endif /* defined(CONFIG_LIBLC3) */ } streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; static struct bt_bap_broadcast_source *broadcast_source; @@ -32,7 +129,8 @@ NET_BUF_POOL_FIXED_DEFINE(tx_pool, TOTAL_BUF_NEEDED, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); -static uint8_t mock_data[CONFIG_BT_ISO_TX_MTU]; + +static int16_t send_pcm_data[MAX_NUM_SAMPLES]; static uint16_t seq_num; static bool stopping; @@ -41,25 +139,18 @@ static K_SEM_DEFINE(sem_stopped, 0U, ARRAY_SIZE(streams)); #define BROADCAST_SOURCE_LIFETIME 120U /* seconds */ -static void stream_started_cb(struct bt_bap_stream *stream) -{ - struct broadcast_source_stream *source_stream = - CONTAINER_OF(stream, struct broadcast_source_stream, stream); +#if defined(CONFIG_LIBLC3) +static int freq_hz; +static int frame_duration_us; +static int frames_per_sdu; +static int octets_per_frame; - source_stream->seq_num = 0U; - source_stream->sent_cnt = 0U; - k_sem_give(&sem_started); -} +static K_SEM_DEFINE(lc3_encoder_sem, 0U, TOTAL_BUF_NEEDED); +#endif -static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +static void send_data(struct broadcast_source_stream *source_stream) { - k_sem_give(&sem_stopped); -} - -static void stream_sent_cb(struct bt_bap_stream *stream) -{ - struct broadcast_source_stream *source_stream = - CONTAINER_OF(stream, struct broadcast_source_stream, stream); + struct bt_bap_stream *stream = &source_stream->stream; struct net_buf *buf; int ret; @@ -75,7 +166,38 @@ static void stream_sent_cb(struct bt_bap_stream *stream) } net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); - net_buf_add_mem(buf, mock_data, preset_16_2_1.qos.sdu); +#if defined(CONFIG_LIBLC3) + uint8_t lc3_encoded_buffer[preset_active.qos.sdu]; + + if (source_stream->lc3_encoder == NULL) { + printk("LC3 encoder not setup, cannot encode data.\n"); + return; + } + +#if defined(CONFIG_USB_DEVICE_AUDIO) + uint32_t size = ring_buf_get(&source_stream->audio_ring_buf, + (uint8_t *)send_pcm_data, sizeof(send_pcm_data)); + + if (size < sizeof(send_pcm_data)) { + const size_t padding_size = sizeof(send_pcm_data) - size; + + printk("Not enough bytes ready, padding %d!\n", padding_size); + memset(&((uint8_t *)send_pcm_data)[size], 0, padding_size); + } +#endif + + ret = lc3_encode(source_stream->lc3_encoder, LC3_PCM_FORMAT_S16, + send_pcm_data, 1, octets_per_frame, lc3_encoded_buffer); + if (ret == -1) { + printk("LC3 encoder failed - wrong parameters?: %d", ret); + return; + } + + net_buf_add_mem(buf, lc3_encoded_buffer, preset_active.qos.sdu); +#else + net_buf_add_mem(buf, send_pcm_data, preset_active.qos.sdu); +#endif /* defined(CONFIG_LIBLC3) */ + ret = bt_bap_stream_send(stream, buf, source_stream->seq_num++, BT_ISO_TIMESTAMP_NONE); if (ret < 0) { /* This will end broadcasting on this stream. */ @@ -90,6 +212,164 @@ static void stream_sent_cb(struct bt_bap_stream *stream) } } +#if defined(CONFIG_LIBLC3) +static void init_lc3_thread(void *arg1, void *arg2, void *arg3) +{ + const struct bt_audio_codec_cfg *codec_cfg = &preset_active.codec_cfg; + int ret; + + ret = bt_audio_codec_cfg_get_freq(codec_cfg); + if (ret > 0) { + freq_hz = bt_audio_codec_cfg_freq_to_freq_hz(ret); + } else { + return; + } + + 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; + } + + octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg); + frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true); + + if (freq_hz < 0) { + printk("Error: Codec frequency not set, cannot start codec."); + return; + } + + if (frame_duration_us < 0) { + printk("Error: Frame duration not set, cannot start codec."); + return; + } + + if (octets_per_frame < 0) { + printk("Error: Octets per frame not set, cannot start codec."); + return; + } + +#if !defined(CONFIG_USB_DEVICE_AUDIO) + /* If USB is not used as a sound source, generate a sine wave */ + fill_audio_buf_sin(send_pcm_data, frame_duration_us, AUDIO_TONE_FREQUENCY_HZ, freq_hz); +#endif + + /* Create the encoder instance. This shall complete before stream_started() is called. */ + for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { + printk("Initializing lc3 encoder for stream %zu\n", i); + streams[i].lc3_encoder = lc3_setup_encoder(frame_duration_us, freq_hz, + 0, &streams[i].lc3_encoder_mem); + + if (streams[i].lc3_encoder == NULL) { + printk("ERROR: Failed to setup LC3 encoder - wrong parameters?\n"); + } + } + + while (true) { + for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { + k_sem_take(&lc3_encoder_sem, K_FOREVER); + } + for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { + send_data(&streams[i]); + } + } +} + +#define LC3_ENCODER_STACK_SIZE 4 * 4096 +#define LC3_ENCODER_PRIORITY 5 + +K_THREAD_DEFINE(encoder, LC3_ENCODER_STACK_SIZE, init_lc3_thread, + NULL, NULL, NULL, LC3_ENCODER_PRIORITY, 0, -1); + +#if defined(CONFIG_USB_DEVICE_AUDIO) +static void data_received(const struct device *dev, + struct net_buf *buffer, + size_t size) +{ + static int count; + int16_t *pcm; + int nsamples, ratio; + int16_t usb_pcm_data[USB_CHANNELS][USB_NUM_SAMPLES]; + + if (!buffer) { + return; + } + + if (!size) { + net_buf_unref(buffer); + return; + } + + pcm = (int16_t *)net_buf_pull_mem(buffer, size); + + /* 'size' is in bytes, containing 1ms, 48kHz, stereo, 2 bytes per sample. + * Take left channel and do a simple downsample to 16kHz/24Khz + * matching the broadcast preset. + */ + + ratio = USB_SAMPLE_RATE / USB_DOWNSAMPLE_RATE; + nsamples = size / (sizeof(int16_t) * USB_CHANNELS * ratio); + for (size_t i = 0, j = 0; i < nsamples; i++, j += USB_CHANNELS * ratio) { + usb_pcm_data[0][i] = pcm[j]; + usb_pcm_data[1][i] = pcm[j + 1]; + } + + for (size_t i = 0U; i < MIN(ARRAY_SIZE(streams), 2); i++) { + const uint32_t size_put = ring_buf_put(&(streams[i].audio_ring_buf), + (uint8_t *)(usb_pcm_data[i]), nsamples * USB_BYTES_PER_SAMPLE); + if (size_put < nsamples * USB_BYTES_PER_SAMPLE) { + printk("Not enough room for samples in %s buffer: %u < %u, total capacity: %u\n", + i == 0 ? "left" : "right", + size_put, + nsamples * USB_BYTES_PER_SAMPLE, + ring_buf_capacity_get(&(streams[i].audio_ring_buf))); + } + } + + count++; + if ((count % 1000) == 0) { + printk("USB Data received (count = %d)\n", count); + } + + net_buf_unref(buffer); +} + +static const struct usb_audio_ops ops = { + .data_received_cb = data_received +}; +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ +#endif /* defined(CONFIG_LIBLC3) */ + +static void stream_started_cb(struct bt_bap_stream *stream) +{ + struct broadcast_source_stream *source_stream = + CONTAINER_OF(stream, struct broadcast_source_stream, stream); + + source_stream->seq_num = 0U; + source_stream->sent_cnt = 0U; + k_sem_give(&sem_started); +} + +static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +{ + k_sem_give(&sem_stopped); +} + +static void stream_sent_cb(struct bt_bap_stream *stream) +{ +#if defined(CONFIG_LIBLC3) + k_sem_give(&lc3_encoder_sem); +#else + /* If no LC3 encoder is used, just send mock data directly */ + struct broadcast_source_stream *source_stream = + CONTAINER_OF(stream, struct broadcast_source_stream, stream); + + send_data(source_stream); +#endif +} + static struct bt_bap_stream_ops stream_ops = { .started = stream_started_cb, .stopped = stream_stopped_cb, @@ -104,26 +384,28 @@ static int setup_broadcast_source(struct bt_bap_broadcast_source **source) subgroup_param[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT]; struct bt_bap_broadcast_source_param create_param; const size_t streams_per_subgroup = ARRAY_SIZE(stream_params) / ARRAY_SIZE(subgroup_param); + uint8_t left[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, + BT_BYTES_LIST_LE32(BT_AUDIO_LOCATION_FRONT_LEFT))}; + uint8_t right[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, + BT_BYTES_LIST_LE32(BT_AUDIO_LOCATION_FRONT_RIGHT))}; int err; - (void)memset(streams, 0, sizeof(streams)); - for (size_t i = 0U; i < ARRAY_SIZE(subgroup_param); i++) { subgroup_param[i].params_count = streams_per_subgroup; subgroup_param[i].params = stream_params + i * streams_per_subgroup; - subgroup_param[i].codec_cfg = &preset_16_2_1.codec_cfg; + subgroup_param[i].codec_cfg = &preset_active.codec_cfg; } for (size_t j = 0U; j < ARRAY_SIZE(stream_params); j++) { stream_params[j].stream = &streams[j].stream; - stream_params[j].data = NULL; - stream_params[j].data_len = 0U; + stream_params[j].data = j == 0 ? left : right; + stream_params[j].data_len = j == 0 ? sizeof(left) : sizeof(right); bt_bap_stream_cb_register(stream_params[j].stream, &stream_ops); } create_param.params_count = ARRAY_SIZE(subgroup_param); create_param.params = subgroup_param; - create_param.qos = &preset_16_2_1.qos; + create_param.qos = &preset_active.qos; create_param.encryption = false; create_param.packing = BT_ISO_PACKING_SEQUENTIAL; @@ -152,11 +434,46 @@ int main(void) } printk("Bluetooth initialized\n"); - for (size_t i = 0U; i < ARRAY_SIZE(mock_data); i++) { + for (size_t i = 0U; i < ARRAY_SIZE(send_pcm_data); i++) { /* Initialize mock data */ - mock_data[i] = i; + send_pcm_data[i] = i; + } + +#if defined(CONFIG_LIBLC3) +#if defined(CONFIG_USB_DEVICE_AUDIO) + const struct device *hs_dev; + + hs_dev = DEVICE_DT_GET(DT_NODELABEL(hs_0)); + + if (!device_is_ready(hs_dev)) { + printk("Device USB Headset is not ready\n"); + return 0; + } + + printk("Found USB Headset Device\n"); + + (void)memset(streams, 0, sizeof(streams)); + + for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { + ring_buf_init(&(streams[i].audio_ring_buf), + sizeof(streams[i]._ring_buffer_memory), + streams[i]._ring_buffer_memory); + printk("Initialized ring buf %zu: capacity: %u\n", i, + ring_buf_capacity_get(&(streams[i].audio_ring_buf))); } + usb_audio_register(hs_dev, &ops); + + err = usb_enable(NULL); + 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) */ + while (true) { /* Broadcast Audio Streaming Endpoint advertising data */ NET_BUF_SIMPLE_DEFINE(ad_buf, @@ -167,7 +484,7 @@ int main(void) uint32_t broadcast_id; /* Create a non-connectable non-scannable advertising set */ - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, &adv); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CUSTOM, NULL, &adv); if (err != 0) { printk("Unable to create extended advertising set: %d\n", err); @@ -262,10 +579,13 @@ int main(void) } } +#if defined(CONFIG_LIBLC3) && defined(CONFIG_USB_DEVICE_AUDIO) + /* Never stop streaming when using USB Audio as input */ + k_sleep(K_FOREVER); +#endif /* defined(CONFIG_LIBLC3) && defined(CONFIG_USB_DEVICE_AUDIO) */ printk("Waiting %u seconds before stopped\n", BROADCAST_SOURCE_LIFETIME); k_sleep(K_SECONDS(BROADCAST_SOURCE_LIFETIME)); - printk("Stopping broadcast source\n"); stopping = true; err = bt_bap_broadcast_source_stop(broadcast_source); diff --git a/samples/bluetooth/broadcast_audio_source/sysbuild.cmake b/samples/bluetooth/broadcast_audio_source/sysbuild.cmake new file mode 100644 index 000000000000000..2523aac8ea76f16 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_source/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/broadcaster_multiple/src/broadcaster_multiple.c b/samples/bluetooth/broadcaster_multiple/src/broadcaster_multiple.c index 30fe35d3dec6e04..d4ce51c4f252f90 100644 --- a/samples/bluetooth/broadcaster_multiple/src/broadcaster_multiple.c +++ b/samples/bluetooth/broadcaster_multiple/src/broadcaster_multiple.c @@ -56,7 +56,7 @@ static uint8_t mfg_data[BT_MFG_DATA_LEN] = { 0xFF, 0xFF, }; static const struct bt_data ad[] = { BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, sizeof(mfg_data)), -#if defined(CONFIG_BT_CTLR_ADV_DATA_CHAIN) +#if CONFIG_BT_CTLR_ADV_DATA_LEN_MAX > 255 BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, sizeof(mfg_data)), #endif }; 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 58c8c58f50f3a1f..7deecd11219b911 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 ecb262c8517f42d..305066bccd6816f 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 f2396115cc2ca73..cc9bdae61c19a42 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_iso/src/main.c b/samples/bluetooth/central_iso/src/main.c index c5da26373b1da89..a0062fcfa73654f 100644 --- a/samples/bluetooth/central_iso/src/main.c +++ b/samples/bluetooth/central_iso/src/main.c @@ -25,6 +25,7 @@ static struct bt_conn *default_conn; static struct k_work_delayable iso_send_work; static struct bt_iso_chan iso_chan; static uint16_t seq_num; +static uint16_t latency_ms = 10U; /* 10ms */ static uint32_t interval_us = 10U * USEC_PER_MSEC; /* 10 ms */ NET_BUF_POOL_FIXED_DEFINE(tx_pool, 1, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); @@ -251,8 +252,10 @@ int main(void) param.sca = BT_GAP_SCA_UNKNOWN; param.packing = 0; param.framing = 0; - param.latency = 10; /* ms */ - param.interval = interval_us; /* us */ + param.c_to_p_latency = latency_ms; /* ms */ + param.p_to_c_latency = latency_ms; /* ms */ + param.c_to_p_interval = interval_us; /* us */ + param.p_to_c_interval = interval_us; /* us */ err = bt_iso_cig_create(¶m, &cig); diff --git a/samples/bluetooth/central_otc/src/main.c b/samples/bluetooth/central_otc/src/main.c index 5dd9412ff65d4a3..7c2c659f5106440 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 d93f77083eb4559..c8ebda0df9b55a8 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/direction_finding_central/README.rst b/samples/bluetooth/direction_finding_central/README.rst index 17cbc599f6bdbfc..07a5d1c52be9768 100644 --- a/samples/bluetooth/direction_finding_central/README.rst +++ b/samples/bluetooth/direction_finding_central/README.rst @@ -37,21 +37,21 @@ changing ``nrf52833dk_nrf52833`` as needed for your board: :compact: To run the application on nRF5340DK, a Bluetooth controller application must -also run on the network core. The :ref:`bluetooth-hci-rpmsg-sample` sample +also run on the network core. The :ref:`bluetooth-hci-ipc-sample` sample application may be used. To build this sample with direction finding support enabled: * Copy :zephyr_file:`samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52833.overlay` to a new file, - :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay`. + :file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.overlay`. * Make sure the same GPIO pins are assigned to Direction Finding Extension in file :zephyr_file:`samples/bluetooth/direction_finding_central/boards/nrf5340dk_nrf5340_cpuapp.overlay`. - as those in the created file :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay`. + as those in the created file :file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.overlay`. * Copy :zephyr_file:`samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52833.conf` to a new file, - :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.conf`. + :file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.conf`. Antenna matrix configuration **************************** @@ -69,8 +69,8 @@ this overlay. See :ref:`set-devicetree-overlays` for information on setting up and using overlays. Note that antenna matrix configuration for the nRF5340 SoC is part of the -network core application. When :ref:`bluetooth-hci-rpmsg-sample` is used as the +network core application. When :ref:`bluetooth-hci-ipc-sample` is used as the network core application, the antenna matrix configuration should be stored in the file -:file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay` +:file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.overlay` instead. diff --git a/samples/bluetooth/direction_finding_connectionless_rx/README.rst b/samples/bluetooth/direction_finding_connectionless_rx/README.rst index b7a970acbc4f051..ad8416dd5376a82 100644 --- a/samples/bluetooth/direction_finding_connectionless_rx/README.rst +++ b/samples/bluetooth/direction_finding_connectionless_rx/README.rst @@ -37,21 +37,21 @@ changing ``nrf52833dk_nrf52833`` as needed for your board: :compact: To run the application on nRF5340DK, a Bluetooth controller application must -also run on the network core. The :ref:`bluetooth-hci-rpmsg-sample` sample +also run on the network core. The :ref:`bluetooth-hci-ipc-sample` sample application may be used. To build this sample with direction finding support enabled: * Copy :zephyr_file:`samples/bluetooth/direction_finding_connectionless_rx/boards/nrf52833dk_nrf52833.overlay` to a new file, - :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay`. + :file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.overlay`. * Make sure the same GPIO pins are assigned to Direction Finding Extension in file :zephyr_file:`samples/bluetooth/direction_finding_connectionless_rx/boards/nrf5340dk_nrf5340_cpuapp.overlay`. - as those in the created file :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay`. + as those in the created file :file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.overlay`. * Copy :zephyr_file:`samples/bluetooth/direction_finding_connectionless_rx/boards/nrf52833dk_nrf52833.conf` to a new file, - :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.conf`. Add + :file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.conf`. Add the line ``CONFIG_BT_EXT_ADV=y`` to enable extended size of :kconfig:option:`CONFIG_BT_BUF_CMD_TX_SIZE` to support the LE Set Extended Advertising Data command. @@ -72,8 +72,8 @@ this overlay. See :ref:`set-devicetree-overlays` for information on setting up and using overlays. Note that antenna matrix configuration for the nRF5340 SoC is part of the -network core application. When :ref:`bluetooth-hci-rpmsg-sample` is used as the +network core application. When :ref:`bluetooth-hci-ipc-sample` is used as the network core application, the antenna matrix configuration should be stored in the file -:file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay` +:file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.overlay` instead. diff --git a/samples/bluetooth/direction_finding_connectionless_tx/README.rst b/samples/bluetooth/direction_finding_connectionless_tx/README.rst index ca27319cbc7e1ca..6fe3dd68722b50d 100644 --- a/samples/bluetooth/direction_finding_connectionless_tx/README.rst +++ b/samples/bluetooth/direction_finding_connectionless_tx/README.rst @@ -37,21 +37,21 @@ To use Angle of Arrival mode only, build this application as follows, changing :compact: To run the application on nRF5340DK, a Bluetooth controller application must -also run on the network core. The :zephyr_file:`samples/bluetooth/hci_rpmsg` +also run on the network core. The :zephyr_file:`samples/bluetooth/hci_ipc` sample application may be used. To build this sample with direction finding support enabled: * Copy :zephyr_file:`samples/bluetooth/direction_finding_connectionless_tx/boards/nrf52833dk_nrf52833.overlay` to a new file, - :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay`. + :file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.overlay`. * Make sure the same GPIO pins are assigned to Direction Finding Extension in file :zephyr_file:`samples/bluetooth/direction_finding_connectionless_tx/boards/nrf5340dk_nrf5340_cpuapp.overlay`. - as those in the created file :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay`. + as those in the created file :file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.overlay`. * Copy :zephyr_file:`samples/bluetooth/direction_finding_connectionless_tx/boards/nrf52833dk_nrf52833.conf` to a new file, - :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.conf`. Add + :file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.conf`. Add the line ``CONFIG_BT_EXT_ADV=y`` to enable extended size of :kconfig:option:`CONFIG_BT_BUF_CMD_TX_SIZE` to support the LE Set Extended Advertising Data command. @@ -73,10 +73,10 @@ this overlay. See :ref:`set-devicetree-overlays` for information on setting up and using overlays. Note that antenna matrix configuration for the nRF5340 SoC is part of the -network core application. When :ref:`bluetooth-hci-rpmsg-sample` is used as +network core application. When :ref:`bluetooth-hci-ipc-sample` is used as network core application, the antenna matrix configuration should be stored in the file -:file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay` +:file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.overlay` instead. In addition to the devicetree configuration, to successfully use the Direction diff --git a/samples/bluetooth/direction_finding_peripheral/README.rst b/samples/bluetooth/direction_finding_peripheral/README.rst index 36846c84d6f22a1..75cc5b9a9176849 100644 --- a/samples/bluetooth/direction_finding_peripheral/README.rst +++ b/samples/bluetooth/direction_finding_peripheral/README.rst @@ -36,21 +36,21 @@ changing ``nrf52833dk_nrf52833`` as needed for your board: :compact: To run the application on nRF5340DK, a Bluetooth controller application must -also run on the network core. The :ref:`bluetooth-hci-rpmsg-sample` sample +also run on the network core. The :ref:`bluetooth-hci-ipc-sample` sample application may be used. To build this sample with direction finding support enabled: * Copy :zephyr_file:`samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52833.overlay` to a new file, - :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay`. + :file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.overlay`. * Make sure the same GPIO pins are assigned to Direction Finding Extension in file :zephyr_file:`samples/bluetooth/direction_finding_peripheral/boards/nrf5340dk_nrf5340_cpuapp.overlay`. - as those in the created file :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay`. + as those in the created file :file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.overlay`. * Copy :zephyr_file:`samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52833.conf` to a new file, - :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.conf`. + :file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.conf`. Antenna matrix configuration **************************** @@ -68,8 +68,8 @@ this overlay. See :ref:`set-devicetree-overlays` for information on setting up and using overlays. Note that antenna matrix configuration for the nRF5340 SoC is part of the -network core application. When :ref:`bluetooth-hci-rpmsg-sample` is used as the +network core application. When :ref:`bluetooth-hci-ipc-sample` is used as the network core application, the antenna matrix configuration should be stored in the file -:file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay` +:file:`samples/bluetooth/hci_ipc/boards/nrf5340dk_nrf5340_cpunet.overlay` instead. diff --git a/samples/bluetooth/eddystone/src/main.c b/samples/bluetooth/eddystone/src/main.c index ff4ab59cd9c4768..86a99aaac4c0527 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/handsfree/prj.conf b/samples/bluetooth/handsfree/prj.conf index ce7e742f10b89a5..924d9c0af0efd17 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/hap_ha/boards/native_sim.conf b/samples/bluetooth/hap_ha/boards/native_sim.conf new file mode 100644 index 000000000000000..abce1c1111e5db2 --- /dev/null +++ b/samples/bluetooth/hap_ha/boards/native_sim.conf @@ -0,0 +1,7 @@ +CONFIG_LOG_MODE_IMMEDIATE=y +CONFIG_BT_TINYCRYPT_ECC=y + +# For LE-audio at 10ms intervals we need the tick counter to occur more frequently +# than every 10 ms as each PDU for some reason takes 2 ticks to process. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/bluetooth/hap_ha/sample.yaml b/samples/bluetooth/hap_ha/sample.yaml index c9fcfda90ca22db..3b0fcd53a51cdb7 100644 --- a/samples/bluetooth/hap_ha/sample.yaml +++ b/samples/bluetooth/hap_ha/sample.yaml @@ -4,25 +4,33 @@ sample: tests: sample.bluetooth.hap_ha.monaural: harness: bluetooth - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim tags: bluetooth build_only: true sample.bluetooth.hap_ha.monaural_no_presets: harness: bluetooth - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim tags: bluetooth build_only: true extra_configs: - CONFIG_BT_HAS_PRESET_COUNT=0 sample.bluetooth.hap_ha.banded: harness: bluetooth - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim tags: bluetooth extra_args: OVERLAY_CONFIG="banded.conf" build_only: true sample.bluetooth.hap_ha.binaural: harness: bluetooth - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim tags: bluetooth extra_args: OVERLAY_CONFIG="binaural.conf" build_only: true diff --git a/samples/bluetooth/hap_ha/src/bap_unicast_sr.c b/samples/bluetooth/hap_ha/src/bap_unicast_sr.c index 5ed64e86202ac97..1eca1fd25c26e14 100644 --- a/samples/bluetooth/hap_ha/src/bap_unicast_sr.c +++ b/samples/bluetooth/hap_ha/src/bap_unicast_sr.c @@ -87,8 +87,12 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg) printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_freq_to_freq_hz(ret)); } - printk(" Frame Duration: %d us\n", - bt_audio_codec_cfg_get_frame_duration_us(codec_cfg)); + ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg); + if (ret > 0) { + printk(" Frame Duration: %d us\n", + bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret)); + } + if (bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation) == 0) { printk(" Channel allocation: 0x%x\n", chan_allocation); } diff --git a/samples/bluetooth/hci_ipc/CMakeLists.txt b/samples/bluetooth/hci_ipc/CMakeLists.txt new file mode 100644 index 000000000000000..02ff09719d7f9e0 --- /dev/null +++ b/samples/bluetooth/hci_ipc/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(hci_ipc) + +target_sources(app PRIVATE src/main.c) + +# Remove after 3.7.0 is released +dt_chosen(chosen_hci_rpmsg PROPERTY "zephyr,bt-hci-rpmsg-ipc") +if(DEFINED chosen_hci_rpmsg) + message(FATAL_ERROR "zephyr,bt-hci-rpmsg-ipc has been renamed to zephyr,bt-hci-ipc") +endif() diff --git a/samples/bluetooth/hci_ipc/README.rst b/samples/bluetooth/hci_ipc/README.rst new file mode 100644 index 000000000000000..605898d7220e19d --- /dev/null +++ b/samples/bluetooth/hci_ipc/README.rst @@ -0,0 +1,39 @@ +.. _bluetooth-hci-ipc-sample: + +Bluetooth: HCI IPC +################## + +Overview +******** + +This sample exposes :ref:`bluetooth_controller` support +to another device or CPU using IPC subsystem. + +Requirements +************ + +* A board with IPC subsystem and Bluetooth LE support + +Building and Running +******************** + +This sample can be found under :zephyr_file:`samples/bluetooth/hci_ipc` +in the Zephyr tree. + +To use this application, you need a board with a Bluetooth controller +and IPC support. +You can then build this application and flash it onto your board in +the usual way. See :ref:`boards` for board-specific building and +programming information. + +To test this sample, you need a separate device/CPU that acts as Bluetooth +HCI IPC peer. +This sample is compatible with the HCI IPC driver provided by +Zephyr's Bluetooth :ref:`bt_hci_drivers` core. See the +:kconfig:option:`CONFIG_BT_HCI_IPC` configuration option for more information. + +You might need to adjust the Kconfig configuration of this sample to make it +compatible with the peer application. For example, :kconfig:option:`CONFIG_BT_MAX_CONN` +must be equal to the maximum number of connections supported by the peer application. + +Refer to :ref:`bluetooth-samples` for general information about Bluetooth samples. diff --git a/samples/bluetooth/hci_rpmsg/debug_overlay.conf b/samples/bluetooth/hci_ipc/debug_overlay.conf similarity index 100% rename from samples/bluetooth/hci_rpmsg/debug_overlay.conf rename to samples/bluetooth/hci_ipc/debug_overlay.conf diff --git a/samples/bluetooth/hci_rpmsg/dts/arm/nordic/override.dtsi b/samples/bluetooth/hci_ipc/dts/arm/nordic/override.dtsi similarity index 100% rename from samples/bluetooth/hci_rpmsg/dts/arm/nordic/override.dtsi rename to samples/bluetooth/hci_ipc/dts/arm/nordic/override.dtsi diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_bis-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_bis-bt_ll_sw_split.conf similarity index 100% rename from samples/bluetooth/hci_rpmsg/nrf5340_cpunet_bis-bt_ll_sw_split.conf rename to samples/bluetooth/hci_ipc/nrf5340_cpunet_bis-bt_ll_sw_split.conf diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf similarity index 100% rename from samples/bluetooth/hci_rpmsg/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf rename to samples/bluetooth/hci_ipc/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_cis-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_cis-bt_ll_sw_split.conf similarity index 100% rename from samples/bluetooth/hci_rpmsg/nrf5340_cpunet_cis-bt_ll_sw_split.conf rename to samples/bluetooth/hci_ipc/nrf5340_cpunet_cis-bt_ll_sw_split.conf diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_df-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_df-bt_ll_sw_split.conf similarity index 100% rename from samples/bluetooth/hci_rpmsg/nrf5340_cpunet_df-bt_ll_sw_split.conf rename to samples/bluetooth/hci_ipc/nrf5340_cpunet_df-bt_ll_sw_split.conf diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_df-bt_ll_sw_split.overlay b/samples/bluetooth/hci_ipc/nrf5340_cpunet_df-bt_ll_sw_split.overlay similarity index 100% rename from samples/bluetooth/hci_rpmsg/nrf5340_cpunet_df-bt_ll_sw_split.overlay rename to samples/bluetooth/hci_ipc/nrf5340_cpunet_df-bt_ll_sw_split.overlay diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf similarity index 98% rename from samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso-bt_ll_sw_split.conf rename to samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf index e9e5ac634835f3e..f80f324be53e465 100644 --- a/samples/bluetooth/hci_rpmsg/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_rpmsg/nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf similarity index 100% rename from samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf rename to samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf similarity index 100% rename from samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf rename to samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf similarity index 100% rename from samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf rename to samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf similarity index 100% rename from samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf rename to samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf diff --git a/samples/bluetooth/hci_rpmsg/prj.conf b/samples/bluetooth/hci_ipc/prj.conf similarity index 100% rename from samples/bluetooth/hci_rpmsg/prj.conf rename to samples/bluetooth/hci_ipc/prj.conf diff --git a/samples/bluetooth/hci_ipc/sample.yaml b/samples/bluetooth/hci_ipc/sample.yaml new file mode 100644 index 000000000000000..e05a5d384d214d9 --- /dev/null +++ b/samples/bluetooth/hci_ipc/sample.yaml @@ -0,0 +1,110 @@ +sample: + description: Allows Zephyr to provide Bluetooth connectivity via IPC + name: Bluetooth HCI IPC +tests: + sample.bluetooth.hci_ipc: + harness: bluetooth + tags: bluetooth + platform_allow: + - nrf5340dk_nrf5340_cpunet + - nrf5340_audio_dk_nrf5340_cpunet + - nrf5340bsim_nrf5340_cpunet + integration_platforms: + - nrf5340dk_nrf5340_cpunet + - nrf5340_audio_dk_nrf5340_cpunet + sample.bluetooth.hci_ipc.iso_broadcast.bt_ll_sw_split: + harness: bluetooth + tags: bluetooth + extra_args: CONF_FILE="nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf" + platform_allow: + - nrf5340dk_nrf5340_cpunet + - nrf5340_audio_dk_nrf5340_cpunet + - nrf5340bsim_nrf5340_cpunet + integration_platforms: + - nrf5340dk_nrf5340_cpunet + - nrf5340_audio_dk_nrf5340_cpunet + sample.bluetooth.hci_ipc.iso_receive.bt_ll_sw_split: + harness: bluetooth + tags: bluetooth + extra_args: CONF_FILE="nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf" + platform_allow: + - nrf5340dk_nrf5340_cpunet + - nrf5340_audio_dk_nrf5340_cpunet + - nrf5340bsim_nrf5340_cpunet + integration_platforms: + - nrf5340dk_nrf5340_cpunet + sample.bluetooth.hci_ipc.bis.bt_ll_sw_split: + harness: bluetooth + tags: bluetooth + extra_args: CONF_FILE="nrf5340_cpunet_bis-bt_ll_sw_split.conf" + platform_allow: + - nrf5340dk_nrf5340_cpunet + - nrf5340_audio_dk_nrf5340_cpunet + - nrf5340bsim_nrf5340_cpunet + integration_platforms: + - nrf5340dk_nrf5340_cpunet + sample.bluetooth.hci_ipc.iso_central.bt_ll_sw_split: + harness: bluetooth + tags: bluetooth + extra_args: CONF_FILE="nrf5340_cpunet_iso_central-bt_ll_sw_split.conf" + platform_allow: + - nrf5340dk_nrf5340_cpunet + - nrf5340_audio_dk_nrf5340_cpunet + - nrf5340bsim_nrf5340_cpunet + integration_platforms: + - nrf5340dk_nrf5340_cpunet + sample.bluetooth.hci_ipc.iso_peripheral.bt_ll_sw_split: + harness: bluetooth + tags: bluetooth + extra_args: CONF_FILE="nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf" + platform_allow: + - nrf5340dk_nrf5340_cpunet + - nrf5340_audio_dk_nrf5340_cpunet + - nrf5340bsim_nrf5340_cpunet + integration_platforms: + - nrf5340dk_nrf5340_cpunet + sample.bluetooth.hci_ipc.cis.bt_ll_sw_split: + harness: bluetooth + tags: bluetooth + extra_args: CONF_FILE="nrf5340_cpunet_cis-bt_ll_sw_split.conf" + platform_allow: + - nrf5340dk_nrf5340_cpunet + - nrf5340_audio_dk_nrf5340_cpunet + - nrf5340bsim_nrf5340_cpunet + integration_platforms: + - nrf5340dk_nrf5340_cpunet + sample.bluetooth.hci_ipc.iso.bt_ll_sw_split: + harness: bluetooth + tags: bluetooth + extra_args: CONF_FILE="nrf5340_cpunet_iso-bt_ll_sw_split.conf" + platform_allow: + - nrf5340dk_nrf5340_cpunet + - nrf5340bsim_nrf5340_cpunet + integration_platforms: + - nrf5340dk_nrf5340_cpunet + sample.bluetooth.hci_ipc.df.bt_ll_sw_split: + harness: bluetooth + tags: bluetooth + extra_args: + - CONF_FILE="nrf5340_cpunet_df-bt_ll_sw_split.conf" + - DTC_OVERLAY_FILE="nrf5340_cpunet_df-bt_ll_sw_split.overlay" + platform_allow: nrf5340dk_nrf5340_cpunet + integration_platforms: + - nrf5340dk_nrf5340_cpunet + sample.bluetooth.hci_ipc.df.no_phy_coded.bt_ll_sw_split: + harness: bluetooth + tags: bluetooth + extra_args: + - CONF_FILE="nrf5340_cpunet_df-bt_ll_sw_split.conf" + - DTC_OVERLAY_FILE="nrf5340_cpunet_df-bt_ll_sw_split.overlay" + - CONFIG_BT_CTLR_PHY_CODED=n + platform_allow: nrf5340dk_nrf5340_cpunet + integration_platforms: + - nrf5340dk_nrf5340_cpunet + sample.bluetooth.hci_ipc.mesh.bt_ll_sw_split: + harness: bluetooth + tags: bluetooth + extra_args: CONF_FILE="nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf" + platform_allow: nrf5340dk_nrf5340_cpunet + integration_platforms: + - nrf5340dk_nrf5340_cpunet diff --git a/samples/bluetooth/hci_ipc/src/main.c b/samples/bluetooth/hci_ipc/src/main.c new file mode 100644 index 000000000000000..5f0614139be7ad7 --- /dev/null +++ b/samples/bluetooth/hci_ipc/src/main.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2019-2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +LOG_MODULE_REGISTER(hci_ipc, CONFIG_BT_LOG_LEVEL); + +static struct ipc_ept hci_ept; + +static K_THREAD_STACK_DEFINE(tx_thread_stack, CONFIG_BT_HCI_TX_STACK_SIZE); +static struct k_thread tx_thread_data; +static K_FIFO_DEFINE(tx_queue); +static K_SEM_DEFINE(ipc_bound_sem, 0, 1); +#if defined(CONFIG_BT_CTLR_ASSERT_HANDLER) || defined(CONFIG_BT_HCI_VS_FATAL_ERROR) +/* A flag used to store information if the IPC endpoint has already been bound. The end point can't + * be used before that happens. + */ +static bool ipc_ept_ready; +#endif /* CONFIG_BT_CTLR_ASSERT_HANDLER || CONFIG_BT_HCI_VS_FATAL_ERROR */ + +#define HCI_IPC_CMD 0x01 +#define HCI_IPC_ACL 0x02 +#define HCI_IPC_SCO 0x03 +#define HCI_IPC_EVT 0x04 +#define HCI_IPC_ISO 0x05 + +#define HCI_FATAL_ERR_MSG true +#define HCI_REGULAR_MSG false + +static struct net_buf *hci_ipc_cmd_recv(uint8_t *data, size_t remaining) +{ + struct bt_hci_cmd_hdr *hdr = (void *)data; + struct net_buf *buf; + + if (remaining < sizeof(*hdr)) { + LOG_ERR("Not enough data for command header"); + return NULL; + } + + buf = bt_buf_get_tx(BT_BUF_CMD, K_NO_WAIT, hdr, sizeof(*hdr)); + if (buf) { + data += sizeof(*hdr); + remaining -= sizeof(*hdr); + } else { + LOG_ERR("No available command buffers!"); + return NULL; + } + + if (remaining != hdr->param_len) { + LOG_ERR("Command payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + if (remaining > net_buf_tailroom(buf)) { + LOG_ERR("Not enough space in buffer"); + net_buf_unref(buf); + return NULL; + } + + LOG_DBG("len %u", hdr->param_len); + net_buf_add_mem(buf, data, remaining); + + return buf; +} + +static struct net_buf *hci_ipc_acl_recv(uint8_t *data, size_t remaining) +{ + struct bt_hci_acl_hdr *hdr = (void *)data; + struct net_buf *buf; + + if (remaining < sizeof(*hdr)) { + LOG_ERR("Not enough data for ACL header"); + return NULL; + } + + buf = bt_buf_get_tx(BT_BUF_ACL_OUT, K_NO_WAIT, hdr, sizeof(*hdr)); + if (buf) { + data += sizeof(*hdr); + remaining -= sizeof(*hdr); + } else { + LOG_ERR("No available ACL buffers!"); + return NULL; + } + + if (remaining != sys_le16_to_cpu(hdr->len)) { + LOG_ERR("ACL payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + if (remaining > net_buf_tailroom(buf)) { + LOG_ERR("Not enough space in buffer"); + net_buf_unref(buf); + return NULL; + } + + LOG_DBG("len %u", remaining); + net_buf_add_mem(buf, data, remaining); + + return buf; +} + +static struct net_buf *hci_ipc_iso_recv(uint8_t *data, size_t remaining) +{ + struct bt_hci_iso_hdr *hdr = (void *)data; + struct net_buf *buf; + + if (remaining < sizeof(*hdr)) { + LOG_ERR("Not enough data for ISO header"); + return NULL; + } + + buf = bt_buf_get_tx(BT_BUF_ISO_OUT, K_NO_WAIT, hdr, sizeof(*hdr)); + if (buf) { + data += sizeof(*hdr); + remaining -= sizeof(*hdr); + } else { + LOG_ERR("No available ISO buffers!"); + return NULL; + } + + if (remaining != bt_iso_hdr_len(sys_le16_to_cpu(hdr->len))) { + LOG_ERR("ISO payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + if (remaining > net_buf_tailroom(buf)) { + LOG_ERR("Not enough space in buffer"); + net_buf_unref(buf); + return NULL; + } + + LOG_DBG("len %zu", remaining); + net_buf_add_mem(buf, data, remaining); + + return buf; +} + +static void hci_ipc_rx(uint8_t *data, size_t len) +{ + uint8_t pkt_indicator; + struct net_buf *buf = NULL; + size_t remaining = len; + + LOG_HEXDUMP_DBG(data, len, "IPC data:"); + + pkt_indicator = *data++; + remaining -= sizeof(pkt_indicator); + + switch (pkt_indicator) { + case HCI_IPC_CMD: + buf = hci_ipc_cmd_recv(data, remaining); + break; + + case HCI_IPC_ACL: + buf = hci_ipc_acl_recv(data, remaining); + break; + + case HCI_IPC_ISO: + buf = hci_ipc_iso_recv(data, remaining); + break; + + default: + LOG_ERR("Unknown HCI type %u", pkt_indicator); + return; + } + + if (buf) { + net_buf_put(&tx_queue, buf); + + LOG_HEXDUMP_DBG(buf->data, buf->len, "Final net buffer:"); + } +} + +static void tx_thread(void *p1, void *p2, void *p3) +{ + while (1) { + struct net_buf *buf; + int err; + + /* Wait until a buffer is available */ + buf = net_buf_get(&tx_queue, K_FOREVER); + /* Pass buffer to the stack */ + err = bt_send(buf); + if (err) { + LOG_ERR("Unable to send (err %d)", err); + net_buf_unref(buf); + } + + /* Give other threads a chance to run if tx_queue keeps getting + * new data all the time. + */ + k_yield(); + } +} + +static void hci_ipc_send(struct net_buf *buf, bool is_fatal_err) +{ + uint8_t pkt_indicator; + uint8_t retries = 0; + int ret; + + LOG_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len); + + LOG_HEXDUMP_DBG(buf->data, buf->len, "Controller buffer:"); + + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_IN: + pkt_indicator = HCI_IPC_ACL; + break; + case BT_BUF_EVT: + pkt_indicator = HCI_IPC_EVT; + break; + case BT_BUF_ISO_IN: + pkt_indicator = HCI_IPC_ISO; + break; + default: + LOG_ERR("Unknown type %u", bt_buf_get_type(buf)); + net_buf_unref(buf); + return; + } + net_buf_push_u8(buf, pkt_indicator); + + LOG_HEXDUMP_DBG(buf->data, buf->len, "Final HCI buffer:"); + + do { + ret = ipc_service_send(&hci_ept, buf->data, buf->len); + if (ret < 0) { + retries++; + if (retries > 10) { + /* Default backend (rpmsg_virtio) has a timeout of 150ms. */ + LOG_WRN("IPC send has been blocked for 1.5 seconds."); + retries = 0; + } + + /* The function can be called by the application main thread, + * bt_ctlr_assert_handle and k_sys_fatal_error_handler. In case of a call by + * Bluetooth Controller assert handler or system fatal error handler the + * call can be from ISR context, hence there is no thread to yield. Besides + * that both handlers implement a policy to provide error information and + * stop the system in an infinite loop. The goal is to prevent any other + * damage to the system if one of such exeptional situations occur, hence + * call to k_yield is against it. + */ + if (is_fatal_err) { + LOG_ERR("IPC service send error: %d", ret); + } else { + k_yield(); + } + } + } while (ret < 0); + + LOG_INF("Sent message of %d bytes.", ret); + + net_buf_unref(buf); +} + +#if defined(CONFIG_BT_CTLR_ASSERT_HANDLER) +void bt_ctlr_assert_handle(char *file, uint32_t line) +{ + /* Disable interrupts, this is unrecoverable */ + (void)irq_lock(); + +#if defined(CONFIG_BT_HCI_VS_FATAL_ERROR) + /* Generate an error event only when IPC service endpoint is already bound. */ + if (ipc_ept_ready) { + /* Prepare vendor specific HCI debug event */ + struct net_buf *buf; + + buf = hci_vs_err_assert(file, line); + if (buf == NULL) { + /* Send the event over ipc */ + hci_ipc_send(buf, HCI_FATAL_ERR_MSG); + } else { + LOG_ERR("Can't create Fatal Error HCI event: %s at %d", __FILE__, __LINE__); + } + } else { + LOG_ERR("IPC endpoint is not ready yet: %s at %d", __FILE__, __LINE__); + } + + LOG_ERR("Halting system"); + +#else /* !CONFIG_BT_HCI_VS_FATAL_ERROR */ + LOG_ERR("Controller assert in: %s at %d", file, line); + +#endif /* !CONFIG_BT_HCI_VS_FATAL_ERROR */ + + /* Flush the logs before locking the CPU */ + LOG_PANIC(); + + while (true) { + }; +} +#endif /* CONFIG_BT_CTLR_ASSERT_HANDLER */ + +#if defined(CONFIG_BT_HCI_VS_FATAL_ERROR) +void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *esf) +{ + /* Disable interrupts, this is unrecoverable */ + (void)irq_lock(); + + /* Generate an error event only when there is a stack frame and IPC service endpoint is + * already bound. + */ + if (esf != NULL && ipc_ept_ready) { + /* Prepare vendor specific HCI debug event */ + struct net_buf *buf; + + buf = hci_vs_err_stack_frame(reason, esf); + if (buf != NULL) { + hci_ipc_send(buf, HCI_FATAL_ERR_MSG); + } else { + LOG_ERR("Can't create Fatal Error HCI event.\n"); + } + } + + LOG_ERR("Halting system"); + + /* Flush the logs before locking the CPU */ + LOG_PANIC(); + + while (true) { + }; + + CODE_UNREACHABLE; +} +#endif /* CONFIG_BT_HCI_VS_FATAL_ERROR */ + +static void hci_ept_bound(void *priv) +{ + k_sem_give(&ipc_bound_sem); +#if defined(CONFIG_BT_CTLR_ASSERT_HANDLER) || defined(CONFIG_BT_HCI_VS_FATAL_ERROR) + ipc_ept_ready = true; +#endif /* CONFIG_BT_CTLR_ASSERT_HANDLER || CONFIG_BT_HCI_VS_FATAL_ERROR */ +} + +static void hci_ept_recv(const void *data, size_t len, void *priv) +{ + LOG_INF("Received message of %u bytes.", len); + hci_ipc_rx((uint8_t *) data, len); +} + +static struct ipc_ept_cfg hci_ept_cfg = { + .name = "nrf_bt_hci", + .cb = { + .bound = hci_ept_bound, + .received = hci_ept_recv, + }, +}; + +int main(void) +{ + int err; + const struct device *hci_ipc_instance = + DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_hci_ipc)); + + /* incoming events and data from the controller */ + static K_FIFO_DEFINE(rx_queue); + + LOG_DBG("Start"); + + /* Enable the raw interface, this will in turn open the HCI driver */ + bt_enable_raw(&rx_queue); + + /* Spawn the TX thread and start feeding commands and data to the + * controller + */ + k_thread_create(&tx_thread_data, tx_thread_stack, + K_THREAD_STACK_SIZEOF(tx_thread_stack), tx_thread, + NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); + k_thread_name_set(&tx_thread_data, "HCI ipc TX"); + + /* Initialize IPC service instance and register endpoint. */ + err = ipc_service_open_instance(hci_ipc_instance); + if (err < 0 && err != -EALREADY) { + LOG_ERR("IPC service instance initialization failed: %d\n", err); + } + + err = ipc_service_register_endpoint(hci_ipc_instance, &hci_ept, &hci_ept_cfg); + if (err) { + LOG_ERR("Registering endpoint failed with %d", err); + } + + k_sem_take(&ipc_bound_sem, K_FOREVER); + + while (1) { + struct net_buf *buf; + + buf = net_buf_get(&rx_queue, K_FOREVER); + hci_ipc_send(buf, HCI_REGULAR_MSG); + } + return 0; +} diff --git a/samples/bluetooth/hci_rpmsg/CMakeLists.txt b/samples/bluetooth/hci_rpmsg/CMakeLists.txt deleted file mode 100644 index 11dd731c28516f8..000000000000000 --- a/samples/bluetooth/hci_rpmsg/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(hci_rpmsg) - -target_sources(app PRIVATE src/main.c) diff --git a/samples/bluetooth/hci_rpmsg/README.rst b/samples/bluetooth/hci_rpmsg/README.rst deleted file mode 100644 index 8d0cc704bfad8d7..000000000000000 --- a/samples/bluetooth/hci_rpmsg/README.rst +++ /dev/null @@ -1,40 +0,0 @@ -.. _bluetooth-hci-rpmsg-sample: - -Bluetooth: HCI RPMsg -#################### - -Overview -******** - -This sample exposes :ref:`bluetooth_controller` support -to another device or CPU using RPMsg transport which is -a part of `OpenAMP `__. - -Requirements -************ - -* A board with :ref:`ipm_api` driver and Bluetooth LE support - -Building and Running -******************** - -This sample can be found under :zephyr_file:`samples/bluetooth/hci_rpmsg` -in the Zephyr tree. - -To use this application, you need a board with a Bluetooth controller -and IPM drivers. -You can then build this application and flash it onto your board in -the usual way. See :ref:`boards` for board-specific building and -programming information. - -To test this sample, you need a separate device/CPU that acts as Bluetooth -HCI RPMsg peer. -This sample is compatible with the HCI RPMsg driver provided by -Zephyr's Bluetooth :ref:`bt_hci_drivers` core. See the -:kconfig:option:`CONFIG_BT_RPMSG` configuration option for more information. - -You might need to adjust the Kconfig configuration of this sample to make it -compatible with the peer application. For example, :kconfig:option:`CONFIG_BT_MAX_CONN` -must be equal to the maximum number of connections supported by the peer application. - -Refer to :ref:`bluetooth-samples` for general information about Bluetooth samples. diff --git a/samples/bluetooth/hci_rpmsg/sample.yaml b/samples/bluetooth/hci_rpmsg/sample.yaml deleted file mode 100644 index 7cecb12be6749fd..000000000000000 --- a/samples/bluetooth/hci_rpmsg/sample.yaml +++ /dev/null @@ -1,101 +0,0 @@ -sample: - description: Allows Zephyr to provide Bluetooth connectivity via RPMsg. - name: Bluetooth HCI RPMsg -tests: - sample.bluetooth.hci_rpmsg: - harness: bluetooth - tags: bluetooth - platform_allow: - - nrf5340dk_nrf5340_cpunet - - nrf5340_audio_dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet - - nrf5340_audio_dk_nrf5340_cpunet - sample.bluetooth.hci_rpmsg.iso_broadcast.bt_ll_sw_split: - harness: bluetooth - tags: bluetooth - extra_args: CONF_FILE="nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf" - platform_allow: - - nrf5340dk_nrf5340_cpunet - - nrf5340_audio_dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet - - nrf5340_audio_dk_nrf5340_cpunet - sample.bluetooth.hci_rpmsg.iso_receive.bt_ll_sw_split: - harness: bluetooth - tags: bluetooth - extra_args: CONF_FILE="nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf" - platform_allow: - - nrf5340dk_nrf5340_cpunet - - nrf5340_audio_dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet - sample.bluetooth.hci_rpmsg.bis.bt_ll_sw_split: - harness: bluetooth - tags: bluetooth - extra_args: CONF_FILE="nrf5340_cpunet_bis-bt_ll_sw_split.conf" - platform_allow: - - nrf5340dk_nrf5340_cpunet - - nrf5340_audio_dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet - sample.bluetooth.hci_rpmsg.iso_central.bt_ll_sw_split: - harness: bluetooth - tags: bluetooth - extra_args: CONF_FILE="nrf5340_cpunet_iso_central-bt_ll_sw_split.conf" - platform_allow: - - nrf5340dk_nrf5340_cpunet - - nrf5340_audio_dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet - sample.bluetooth.hci_rpmsg.iso_peripheral.bt_ll_sw_split: - harness: bluetooth - tags: bluetooth - extra_args: CONF_FILE="nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf" - platform_allow: - - nrf5340dk_nrf5340_cpunet - - nrf5340_audio_dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet - sample.bluetooth.hci_rpmsg.cis.bt_ll_sw_split: - harness: bluetooth - tags: bluetooth - extra_args: CONF_FILE="nrf5340_cpunet_cis-bt_ll_sw_split.conf" - platform_allow: - - nrf5340dk_nrf5340_cpunet - - nrf5340_audio_dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet - sample.bluetooth.hci_rpmsg.iso.bt_ll_sw_split: - harness: bluetooth - tags: bluetooth - extra_args: CONF_FILE="nrf5340_cpunet_iso-bt_ll_sw_split.conf" - platform_allow: nrf5340dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet - sample.bluetooth.hci_rpmsg.df.bt_ll_sw_split: - harness: bluetooth - tags: bluetooth - extra_args: - - CONF_FILE="nrf5340_cpunet_df-bt_ll_sw_split.conf" - - DTC_OVERLAY_FILE="nrf5340_cpunet_df-bt_ll_sw_split.overlay" - platform_allow: nrf5340dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet - sample.bluetooth.hci_rpmsg.df.no_phy_coded.bt_ll_sw_split: - harness: bluetooth - tags: bluetooth - extra_args: - - CONF_FILE="nrf5340_cpunet_df-bt_ll_sw_split.conf" - - DTC_OVERLAY_FILE="nrf5340_cpunet_df-bt_ll_sw_split.overlay" - - CONFIG_BT_CTLR_PHY_CODED=n - platform_allow: nrf5340dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet - sample.bluetooth.hci_rpmsg.mesh.bt_ll_sw_split: - harness: bluetooth - tags: bluetooth - extra_args: CONF_FILE="nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf" - platform_allow: nrf5340dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet diff --git a/samples/bluetooth/hci_rpmsg/src/main.c b/samples/bluetooth/hci_rpmsg/src/main.c deleted file mode 100644 index 32c4616cc790a4c..000000000000000 --- a/samples/bluetooth/hci_rpmsg/src/main.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright (c) 2019-2021 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -LOG_MODULE_REGISTER(hci_rpmsg, CONFIG_BT_LOG_LEVEL); - -static struct ipc_ept hci_ept; - -static K_THREAD_STACK_DEFINE(tx_thread_stack, CONFIG_BT_HCI_TX_STACK_SIZE); -static struct k_thread tx_thread_data; -static K_FIFO_DEFINE(tx_queue); -static K_SEM_DEFINE(ipc_bound_sem, 0, 1); -#if defined(CONFIG_BT_CTLR_ASSERT_HANDLER) || defined(CONFIG_BT_HCI_VS_FATAL_ERROR) -/* A flag used to store information if the IPC endpoint has already been bound. The end point can't - * be used before that happens. - */ -static bool ipc_ept_ready; -#endif /* CONFIG_BT_CTLR_ASSERT_HANDLER || CONFIG_BT_HCI_VS_FATAL_ERROR */ - -#define HCI_RPMSG_CMD 0x01 -#define HCI_RPMSG_ACL 0x02 -#define HCI_RPMSG_SCO 0x03 -#define HCI_RPMSG_EVT 0x04 -#define HCI_RPMSG_ISO 0x05 - -#define HCI_FATAL_ERR_MSG true -#define HCI_REGULAR_MSG false - -static struct net_buf *hci_rpmsg_cmd_recv(uint8_t *data, size_t remaining) -{ - struct bt_hci_cmd_hdr *hdr = (void *)data; - struct net_buf *buf; - - if (remaining < sizeof(*hdr)) { - LOG_ERR("Not enough data for command header"); - return NULL; - } - - buf = bt_buf_get_tx(BT_BUF_CMD, K_NO_WAIT, hdr, sizeof(*hdr)); - if (buf) { - data += sizeof(*hdr); - remaining -= sizeof(*hdr); - } else { - LOG_ERR("No available command buffers!"); - return NULL; - } - - if (remaining != hdr->param_len) { - LOG_ERR("Command payload length is not correct"); - net_buf_unref(buf); - return NULL; - } - - if (remaining > net_buf_tailroom(buf)) { - LOG_ERR("Not enough space in buffer"); - net_buf_unref(buf); - return NULL; - } - - LOG_DBG("len %u", hdr->param_len); - net_buf_add_mem(buf, data, remaining); - - return buf; -} - -static struct net_buf *hci_rpmsg_acl_recv(uint8_t *data, size_t remaining) -{ - struct bt_hci_acl_hdr *hdr = (void *)data; - struct net_buf *buf; - - if (remaining < sizeof(*hdr)) { - LOG_ERR("Not enough data for ACL header"); - return NULL; - } - - buf = bt_buf_get_tx(BT_BUF_ACL_OUT, K_NO_WAIT, hdr, sizeof(*hdr)); - if (buf) { - data += sizeof(*hdr); - remaining -= sizeof(*hdr); - } else { - LOG_ERR("No available ACL buffers!"); - return NULL; - } - - if (remaining != sys_le16_to_cpu(hdr->len)) { - LOG_ERR("ACL payload length is not correct"); - net_buf_unref(buf); - return NULL; - } - - if (remaining > net_buf_tailroom(buf)) { - LOG_ERR("Not enough space in buffer"); - net_buf_unref(buf); - return NULL; - } - - LOG_DBG("len %u", remaining); - net_buf_add_mem(buf, data, remaining); - - return buf; -} - -static struct net_buf *hci_rpmsg_iso_recv(uint8_t *data, size_t remaining) -{ - struct bt_hci_iso_hdr *hdr = (void *)data; - struct net_buf *buf; - - if (remaining < sizeof(*hdr)) { - LOG_ERR("Not enough data for ISO header"); - return NULL; - } - - buf = bt_buf_get_tx(BT_BUF_ISO_OUT, K_NO_WAIT, hdr, sizeof(*hdr)); - if (buf) { - data += sizeof(*hdr); - remaining -= sizeof(*hdr); - } else { - LOG_ERR("No available ISO buffers!"); - return NULL; - } - - if (remaining != bt_iso_hdr_len(sys_le16_to_cpu(hdr->len))) { - LOG_ERR("ISO payload length is not correct"); - net_buf_unref(buf); - return NULL; - } - - if (remaining > net_buf_tailroom(buf)) { - LOG_ERR("Not enough space in buffer"); - net_buf_unref(buf); - return NULL; - } - - LOG_DBG("len %zu", remaining); - net_buf_add_mem(buf, data, remaining); - - return buf; -} - -static void hci_rpmsg_rx(uint8_t *data, size_t len) -{ - uint8_t pkt_indicator; - struct net_buf *buf = NULL; - size_t remaining = len; - - LOG_HEXDUMP_DBG(data, len, "RPMSG data:"); - - pkt_indicator = *data++; - remaining -= sizeof(pkt_indicator); - - switch (pkt_indicator) { - case HCI_RPMSG_CMD: - buf = hci_rpmsg_cmd_recv(data, remaining); - break; - - case HCI_RPMSG_ACL: - buf = hci_rpmsg_acl_recv(data, remaining); - break; - - case HCI_RPMSG_ISO: - buf = hci_rpmsg_iso_recv(data, remaining); - break; - - default: - LOG_ERR("Unknown HCI type %u", pkt_indicator); - return; - } - - if (buf) { - net_buf_put(&tx_queue, buf); - - LOG_HEXDUMP_DBG(buf->data, buf->len, "Final net buffer:"); - } -} - -static void tx_thread(void *p1, void *p2, void *p3) -{ - while (1) { - struct net_buf *buf; - int err; - - /* Wait until a buffer is available */ - buf = net_buf_get(&tx_queue, K_FOREVER); - /* Pass buffer to the stack */ - err = bt_send(buf); - if (err) { - LOG_ERR("Unable to send (err %d)", err); - net_buf_unref(buf); - } - - /* Give other threads a chance to run if tx_queue keeps getting - * new data all the time. - */ - k_yield(); - } -} - -static void hci_rpmsg_send(struct net_buf *buf, bool is_fatal_err) -{ - uint8_t pkt_indicator; - uint8_t retries = 0; - int ret; - - LOG_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len); - - LOG_HEXDUMP_DBG(buf->data, buf->len, "Controller buffer:"); - - switch (bt_buf_get_type(buf)) { - case BT_BUF_ACL_IN: - pkt_indicator = HCI_RPMSG_ACL; - break; - case BT_BUF_EVT: - pkt_indicator = HCI_RPMSG_EVT; - break; - case BT_BUF_ISO_IN: - pkt_indicator = HCI_RPMSG_ISO; - break; - default: - LOG_ERR("Unknown type %u", bt_buf_get_type(buf)); - net_buf_unref(buf); - return; - } - net_buf_push_u8(buf, pkt_indicator); - - LOG_HEXDUMP_DBG(buf->data, buf->len, "Final HCI buffer:"); - - do { - ret = ipc_service_send(&hci_ept, buf->data, buf->len); - if (ret < 0) { - retries++; - if (retries > 10) { - /* Default backend (rpmsg_virtio) has a timeout of 150ms. */ - LOG_WRN("IPC send has been blocked for 1.5 seconds."); - retries = 0; - } - - /* The function can be called by the application main thread, - * bt_ctlr_assert_handle and k_sys_fatal_error_handler. In case of a call by - * Bluetooth Controller assert handler or system fatal error handler the - * call can be from ISR context, hence there is no thread to yield. Besides - * that both handlers implement a policy to provide error information and - * stop the system in an infinite loop. The goal is to prevent any other - * damage to the system if one of such exeptional situations occur, hence - * call to k_yield is against it. - */ - if (is_fatal_err) { - LOG_ERR("IPC service send error: %d", ret); - } else { - k_yield(); - } - } - } while (ret < 0); - - LOG_INF("Sent message of %d bytes.", ret); - - net_buf_unref(buf); -} - -#if defined(CONFIG_BT_CTLR_ASSERT_HANDLER) -void bt_ctlr_assert_handle(char *file, uint32_t line) -{ - /* Disable interrupts, this is unrecoverable */ - (void)irq_lock(); - -#if defined(CONFIG_BT_HCI_VS_FATAL_ERROR) - /* Generate an error event only when IPC service endpoint is already bound. */ - if (ipc_ept_ready) { - /* Prepare vendor specific HCI debug event */ - struct net_buf *buf; - - buf = hci_vs_err_assert(file, line); - if (buf == NULL) { - /* Send the event over rpmsg */ - hci_rpmsg_send(buf, HCI_FATAL_ERR_MSG); - } else { - LOG_ERR("Can't create Fatal Error HCI event: %s at %d", __FILE__, __LINE__); - } - } else { - LOG_ERR("IPC endpoint is not ready yet: %s at %d", __FILE__, __LINE__); - } - - LOG_ERR("Halting system"); - -#else /* !CONFIG_BT_HCI_VS_FATAL_ERROR */ - LOG_ERR("Controller assert in: %s at %d", file, line); - -#endif /* !CONFIG_BT_HCI_VS_FATAL_ERROR */ - - /* Flush the logs before locking the CPU */ - LOG_PANIC(); - - while (true) { - }; -} -#endif /* CONFIG_BT_CTLR_ASSERT_HANDLER */ - -#if defined(CONFIG_BT_HCI_VS_FATAL_ERROR) -void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *esf) -{ - /* Disable interrupts, this is unrecoverable */ - (void)irq_lock(); - - /* Generate an error event only when there is a stack frame and IPC service endpoint is - * already bound. - */ - if (esf != NULL && ipc_ept_ready) { - /* Prepare vendor specific HCI debug event */ - struct net_buf *buf; - - buf = hci_vs_err_stack_frame(reason, esf); - if (buf != NULL) { - hci_rpmsg_send(buf, HCI_FATAL_ERR_MSG); - } else { - LOG_ERR("Can't create Fatal Error HCI event.\n"); - } - } - - LOG_ERR("Halting system"); - - /* Flush the logs before locking the CPU */ - LOG_PANIC(); - - while (true) { - }; - - CODE_UNREACHABLE; -} -#endif /* CONFIG_BT_HCI_VS_FATAL_ERROR */ - -static void hci_ept_bound(void *priv) -{ - k_sem_give(&ipc_bound_sem); -#if defined(CONFIG_BT_CTLR_ASSERT_HANDLER) || defined(CONFIG_BT_HCI_VS_FATAL_ERROR) - ipc_ept_ready = true; -#endif /* CONFIG_BT_CTLR_ASSERT_HANDLER || CONFIG_BT_HCI_VS_FATAL_ERROR */ -} - -static void hci_ept_recv(const void *data, size_t len, void *priv) -{ - LOG_INF("Received message of %u bytes.", len); - hci_rpmsg_rx((uint8_t *) data, len); -} - -static struct ipc_ept_cfg hci_ept_cfg = { - .name = "nrf_bt_hci", - .cb = { - .bound = hci_ept_bound, - .received = hci_ept_recv, - }, -}; - -int main(void) -{ - int err; - const struct device *hci_ipc_instance = - DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_hci_rpmsg_ipc)); - - /* incoming events and data from the controller */ - static K_FIFO_DEFINE(rx_queue); - - LOG_DBG("Start"); - - /* Enable the raw interface, this will in turn open the HCI driver */ - bt_enable_raw(&rx_queue); - - /* Spawn the TX thread and start feeding commands and data to the - * controller - */ - k_thread_create(&tx_thread_data, tx_thread_stack, - K_THREAD_STACK_SIZEOF(tx_thread_stack), tx_thread, - NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); - k_thread_name_set(&tx_thread_data, "HCI rpmsg TX"); - - /* Initialize IPC service instance and register endpoint. */ - err = ipc_service_open_instance(hci_ipc_instance); - if (err < 0 && err != -EALREADY) { - LOG_ERR("IPC service instance initialization failed: %d\n", err); - } - - err = ipc_service_register_endpoint(hci_ipc_instance, &hci_ept, &hci_ept_cfg); - if (err) { - LOG_ERR("Registering endpoint failed with %d", err); - } - - k_sem_take(&ipc_bound_sem, K_FOREVER); - - while (1) { - struct net_buf *buf; - - buf = net_buf_get(&rx_queue, K_FOREVER); - hci_rpmsg_send(buf, HCI_REGULAR_MSG); - } - return 0; -} diff --git a/samples/bluetooth/hci_uart/README.rst b/samples/bluetooth/hci_uart/README.rst index 83004cd544f982d..0beb105035d82ae 100644 --- a/samples/bluetooth/hci_uart/README.rst +++ b/samples/bluetooth/hci_uart/README.rst @@ -55,10 +55,10 @@ For example, to build for the nRF52832 Development Kit: .. _bluetooth-hci-uart-qemu-posix: -Using the controller with QEMU and Native POSIX -=============================================== +Using the controller with QEMU or native_sim +============================================ -In order to use the HCI UART controller with QEMU or Native POSIX you will need +In order to use the HCI UART controller with QEMU or :ref:`native_sim ` you will need to attach it to the Linux Host first. To do so simply build the sample and connect the UART to the Linux machine, and then attach it with this command: @@ -84,7 +84,7 @@ If you are running :file:`btmon` you should see a brief log showing how the Linux kernel identifies the attached controller. Once the controller is attached follow the instructions in the -:ref:`bluetooth_qemu_posix` section to use QEMU with it. +:ref:`bluetooth_qemu_native` section to use QEMU with it. .. _bluetooth-hci-uart-bluez: diff --git a/samples/bluetooth/hci_uart_async/README.rst b/samples/bluetooth/hci_uart_async/README.rst index 75bf586868dc3c5..f5caf0f965d1e57 100644 --- a/samples/bluetooth/hci_uart_async/README.rst +++ b/samples/bluetooth/hci_uart_async/README.rst @@ -52,10 +52,10 @@ For example, to build for the nRF52832 Development Kit: .. _bluetooth-hci-uart-async-qemu-posix: -Using the controller with QEMU and Native POSIX -=============================================== +Using the controller with QEMU or native_sim +============================================ -In order to use the HCI UART controller with QEMU or Native POSIX you will need +In order to use the HCI UART controller with QEMU or :ref:`native_sim ` you will need to attach it to the Linux Host first. To do so simply build the sample and connect the UART to the Linux machine, and then attach it with this command: @@ -77,7 +77,7 @@ If you are running :file:`btmon` you should see a brief log showing how the Linux kernel identifies the attached controller. Once the controller is attached follow the instructions in the -:ref:`bluetooth_qemu_posix` section to use QEMU with it. +:ref:`bluetooth_qemu_native` section to use QEMU with it. .. _bluetooth-hci-uart-async-bluez: 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 000000000000000..adef7109b3c9f96 --- /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/hci_usb/sample.yaml b/samples/bluetooth/hci_usb/sample.yaml index 4b998f95bb661b3..9848aed2430c11d 100644 --- a/samples/bluetooth/hci_usb/sample.yaml +++ b/samples/bluetooth/hci_usb/sample.yaml @@ -10,7 +10,7 @@ tests: - usb - bluetooth # FIXME: exclude due to build error - platform_exclude: 96b_carbon + platform_exclude: 96b_carbon stm32l562e_dk sample.bluetooth.hci_usb.device_next: harness: bluetooth depends_on: diff --git a/samples/bluetooth/hci_usb_h4/sample.yaml b/samples/bluetooth/hci_usb_h4/sample.yaml index b09b30185a3e921..afc6e2429cbc854 100644 --- a/samples/bluetooth/hci_usb_h4/sample.yaml +++ b/samples/bluetooth/hci_usb_h4/sample.yaml @@ -10,4 +10,4 @@ tests: - usb - bluetooth # FIXME: exclude due to build error - platform_exclude: 96b_carbon + platform_exclude: 96b_carbon stm32l562e_dk diff --git a/samples/bluetooth/ipsp/src/main.c b/samples/bluetooth/ipsp/src/main.c index c4f1f87c169a07a..a8c017140c36cea 100644 --- a/samples/bluetooth/ipsp/src/main.c +++ b/samples/bluetooth/ipsp/src/main.c @@ -285,8 +285,12 @@ static void setup_tcp_accept(struct net_context *tcp_recv6) } } -static void listen(void) +static void listen(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + struct net_context *udp_recv6 = { 0 }; struct net_context *tcp_recv6 = { 0 }; @@ -313,7 +317,7 @@ int main(void) init_app(); k_thread_create(&thread_data, thread_stack, STACKSIZE, - (k_thread_entry_t)listen, + listen, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); return 0; } diff --git a/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c b/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c index 735ac7a3318bc4f..6c52e2aef82635b 100644 --- a/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c +++ b/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c @@ -22,14 +22,14 @@ LOG_MODULE_REGISTER(iso_broadcast_broadcaster, LOG_LEVEL_DBG); #define DEFAULT_BIS_PACKING 0 #define DEFAULT_BIS_FRAMING 0 #define DEFAULT_BIS_COUNT CONFIG_BT_ISO_MAX_CHAN -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) #define DEFAULT_BIS_NSE BT_ISO_NSE_MIN #define DEFAULT_BIS_BN BT_ISO_BN_MIN #define DEFAULT_BIS_PDU_SIZE CONFIG_BT_ISO_TX_MTU #define DEFAULT_BIS_IRC BT_ISO_IRC_MIN #define DEFAULT_BIS_PTO BT_ISO_PTO_MIN #define DEFAULT_BIS_ISO_INTERVAL DEFAULT_BIS_INTERVAL_US / 1250U /* N * 10 ms */ -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ NET_BUF_POOL_FIXED_DEFINE(bis_tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), @@ -53,11 +53,11 @@ static struct bt_iso_big_create_param big_create_param = { .framing = DEFAULT_BIS_FRAMING, /* 0 - unframed, 1 - framed */ .interval = DEFAULT_BIS_INTERVAL_US, /* in microseconds */ .latency = DEFAULT_BIS_LATENCY_MS, /* milliseconds */ -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) .irc = DEFAULT_BIS_IRC, .pto = DEFAULT_BIS_PTO, .iso_interval = DEFAULT_BIS_ISO_INTERVAL, -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; static void iso_connected(struct bt_iso_chan *chan) @@ -91,17 +91,17 @@ static struct bt_iso_chan_io_qos iso_tx_qos = { .sdu = DEFAULT_BIS_SDU, /* bytes */ .rtn = DEFAULT_BIS_RTN, .phy = DEFAULT_BIS_PHY, -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) .max_pdu = DEFAULT_BIS_PDU_SIZE, .burst_number = DEFAULT_BIS_BN, -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; static struct bt_iso_chan_qos bis_iso_qos = { .tx = &iso_tx_qos, -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) .num_subevents = DEFAULT_BIS_NSE, -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; static size_t get_chars(char *buffer, size_t max_size) @@ -241,7 +241,7 @@ static int parse_sdu_arg(void) return (int)sdu; } -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) static int parse_irc_arg(void) { size_t char_count; @@ -385,7 +385,7 @@ static int parse_bn_arg(void) return (int)burst_number; } -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ static int parse_packing_arg(void) { @@ -468,14 +468,14 @@ static int parse_args(void) int packing; int framing; int bis_count; -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) int num_subevents; int iso_interval; int burst_number; int max_pdu; int irc; int pto; -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ printk("Follow the prompts. Press enter to use default values.\n"); @@ -519,7 +519,7 @@ static int parse_args(void) return -EINVAL; } -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) irc = parse_irc_arg(); if (irc < 0) { return -EINVAL; @@ -549,7 +549,7 @@ static int parse_args(void) if (burst_number < 0) { return -EINVAL; } -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ iso_tx_qos.rtn = rtn; iso_tx_qos.phy = phy; @@ -559,14 +559,14 @@ static int parse_args(void) big_create_param.packing = packing; big_create_param.framing = framing; big_create_param.num_bis = bis_count; -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) bis_iso_qos.num_subevents = num_subevents; iso_tx_qos.max_pdu = max_pdu; iso_tx_qos.burst_number = burst_number; big_create_param.irc = irc; big_create_param.pto = pto; big_create_param.iso_interval = iso_interval; -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ return 0; } diff --git a/samples/bluetooth/iso_connected_benchmark/src/main.c b/samples/bluetooth/iso_connected_benchmark/src/main.c index 99b308ccbb2a388..9d387ed88065446 100644 --- a/samples/bluetooth/iso_connected_benchmark/src/main.c +++ b/samples/bluetooth/iso_connected_benchmark/src/main.c @@ -28,6 +28,11 @@ enum benchmark_role { ROLE_QUIT }; +enum sdu_dir { + DIR_C_TO_P, + DIR_P_TO_C +}; + #define DEFAULT_CIS_RTN 2 #define DEFAULT_CIS_INTERVAL_US 7500 #define DEFAULT_CIS_LATENCY_MS 40 @@ -38,13 +43,13 @@ enum benchmark_role { #define DEFAULT_CIS_COUNT 1U #define DEFAULT_CIS_SEC_LEVEL BT_SECURITY_L1 -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) #define DEFAULT_CIS_NSE BT_ISO_NSE_MIN #define DEFAULT_CIS_BN BT_ISO_BN_MIN #define DEFAULT_CIS_PDU_SIZE CONFIG_BT_ISO_TX_MTU #define DEFAULT_CIS_FT BT_ISO_FT_MIN #define DEFAULT_CIS_ISO_INTERVAL DEFAULT_CIS_INTERVAL_US / 1250U /* N * 1.25 ms */ -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ #define BUFFERS_ENQUEUED 2 /* Number of buffers enqueue for each channel */ @@ -91,43 +96,45 @@ static struct bt_iso_chan_io_qos iso_tx_qos = { .sdu = DEFAULT_CIS_SDU_SIZE, /* bytes */ .rtn = DEFAULT_CIS_RTN, .phy = DEFAULT_CIS_PHY, -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) .max_pdu = DEFAULT_CIS_PDU_SIZE, .burst_number = DEFAULT_CIS_BN, -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; static struct bt_iso_chan_io_qos iso_rx_qos = { .sdu = DEFAULT_CIS_SDU_SIZE, /* bytes */ .rtn = DEFAULT_CIS_RTN, .phy = DEFAULT_CIS_PHY, -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) .max_pdu = DEFAULT_CIS_PDU_SIZE, .burst_number = DEFAULT_CIS_BN, -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; static struct bt_iso_chan_qos iso_qos = { .tx = &iso_tx_qos, .rx = &iso_rx_qos, -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) .num_subevents = DEFAULT_CIS_NSE, -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; static struct bt_iso_cig_param cig_create_param = { - .interval = DEFAULT_CIS_INTERVAL_US, /* in microseconds */ - .latency = DEFAULT_CIS_LATENCY_MS, /* milliseconds */ + .c_to_p_interval = DEFAULT_CIS_INTERVAL_US, /* in microseconds */ + .p_to_c_interval = DEFAULT_CIS_INTERVAL_US, /* in microseconds */ + .c_to_p_latency = DEFAULT_CIS_LATENCY_MS, /* milliseconds */ + .p_to_c_latency = DEFAULT_CIS_LATENCY_MS, /* milliseconds */ .sca = BT_GAP_SCA_UNKNOWN, .packing = DEFAULT_CIS_PACKING, .framing = DEFAULT_CIS_FRAMING, .cis_channels = cis, .num_cis = DEFAULT_CIS_COUNT, -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) .c_to_p_ft = DEFAULT_CIS_FT, .p_to_c_ft = DEFAULT_CIS_FT, .iso_interval = DEFAULT_CIS_ISO_INTERVAL, -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; static enum benchmark_role device_role_select(void) @@ -179,6 +186,7 @@ static void iso_send(struct bt_iso_chan *chan) int ret; struct net_buf *buf; struct iso_chan_work *chan_work; + uint32_t interval; chan_work = CONTAINER_OF(chan, struct iso_chan_work, chan); @@ -186,10 +194,13 @@ static void iso_send(struct bt_iso_chan *chan) return; } + interval = (role == ROLE_CENTRAL) ? + cig_create_param.c_to_p_interval : cig_create_param.p_to_c_interval; + buf = net_buf_alloc(&tx_pool, K_FOREVER); if (buf == NULL) { LOG_ERR("Could not allocate buffer"); - k_work_reschedule(&chan_work->send_work, K_USEC(cig_create_param.interval)); + k_work_reschedule(&chan_work->send_work, K_USEC(interval)); return; } @@ -201,7 +212,7 @@ static void iso_send(struct bt_iso_chan *chan) if (ret < 0) { LOG_ERR("Unable to send data: %d", ret); net_buf_unref(buf); - k_work_reschedule(&chan_work->send_work, K_USEC(cig_create_param.interval)); + k_work_reschedule(&chan_work->send_work, K_USEC(interval)); return; } @@ -535,14 +546,18 @@ static int parse_rtn_arg(struct bt_iso_chan_io_qos *qos) return (int)rtn; } -static int parse_interval_arg(void) +static int parse_interval_arg(enum sdu_dir direction) { char buffer[9]; size_t char_count; uint64_t interval; - printk("Set interval (us) (current %u, default %u)\n", - cig_create_param.interval, DEFAULT_CIS_INTERVAL_US); + interval = (direction == DIR_C_TO_P) ? + cig_create_param.c_to_p_interval : cig_create_param.p_to_c_interval; + + printk("Set %s interval (us) (current %llu, default %u)\n", + (direction == DIR_C_TO_P) ? "C to P" : "P to C", + interval, DEFAULT_CIS_INTERVAL_US); char_count = get_chars(buffer, sizeof(buffer) - 1); if (char_count == 0) { @@ -550,7 +565,6 @@ static int parse_interval_arg(void) } interval = strtoul(buffer, NULL, 0); - /* TODO: Replace literal ints with a #define once it has been created */ if (interval < BT_ISO_SDU_INTERVAL_MIN || interval > BT_ISO_SDU_INTERVAL_MAX) { printk("Invalid interval %llu", interval); return -EINVAL; @@ -559,14 +573,18 @@ static int parse_interval_arg(void) return (int)interval; } -static int parse_latency_arg(void) +static int parse_latency_arg(enum sdu_dir direction) { char buffer[6]; size_t char_count; uint64_t latency; - printk("Set latency (ms) (current %u, default %u)\n", - cig_create_param.latency, DEFAULT_CIS_LATENCY_MS); + latency = (direction == DIR_C_TO_P) ? + cig_create_param.c_to_p_latency : cig_create_param.p_to_c_latency; + + printk("Set %s latency (ms) (current %llu, default %u)\n", + (direction == DIR_C_TO_P) ? "C to P" : "P to C", + latency, DEFAULT_CIS_LATENCY_MS); char_count = get_chars(buffer, sizeof(buffer) - 1); if (char_count == 0) { @@ -632,7 +650,7 @@ static int parse_sdu_arg(struct bt_iso_chan_io_qos *qos) return (int)sdu; } -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) static int parse_c_to_p_ft_arg(void) { char buffer[4]; @@ -778,7 +796,7 @@ static int parse_bn_arg(const struct bt_iso_chan_io_qos *qos) return (int)bn; } -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ static int parse_cis_count_arg(void) { @@ -805,15 +823,17 @@ static int parse_cis_count_arg(void) static int parse_cig_args(void) { - int interval; - int latency; + int c_to_p_interval; + int p_to_c_interval; + int c_to_p_latency; + int p_to_c_latency; int cis_count; -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) int c_to_p_ft; int p_to_c_ft; int iso_interval; int num_subevents; -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ printk("Follow the prompts. Press enter to use default values.\n"); @@ -822,17 +842,27 @@ static int parse_cig_args(void) return -EINVAL; } - interval = parse_interval_arg(); - if (interval < 0) { + c_to_p_interval = parse_interval_arg(DIR_C_TO_P); + if (c_to_p_interval < 0) { + return -EINVAL; + } + + p_to_c_interval = parse_interval_arg(DIR_P_TO_C); + if (p_to_c_interval < 0) { + return -EINVAL; + } + + c_to_p_latency = parse_latency_arg(DIR_C_TO_P); + if (c_to_p_latency < 0) { return -EINVAL; } - latency = parse_latency_arg(); - if (latency < 0) { + p_to_c_latency = parse_latency_arg(DIR_P_TO_C); + if (p_to_c_latency < 0) { return -EINVAL; } -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) c_to_p_ft = parse_c_to_p_ft_arg(); if (c_to_p_ft < 0) { return -EINVAL; @@ -852,17 +882,19 @@ static int parse_cig_args(void) if (num_subevents < 0) { return -EINVAL; } -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ - cig_create_param.interval = interval; - cig_create_param.latency = latency; + cig_create_param.c_to_p_interval = c_to_p_interval; + cig_create_param.p_to_c_interval = p_to_c_interval; + cig_create_param.c_to_p_latency = c_to_p_latency; + cig_create_param.p_to_c_latency = p_to_c_latency; cig_create_param.num_cis = cis_count; -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) cig_create_param.c_to_p_ft = c_to_p_ft; cig_create_param.p_to_c_ft = p_to_c_ft; cig_create_param.iso_interval = iso_interval; iso_qos.num_subevents = num_subevents; -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ return 0; } @@ -872,10 +904,10 @@ static int parse_cis_args(struct bt_iso_chan_io_qos *qos) int rtn; int phy; int sdu; -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) int max_pdu; int burst_number; -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ printk("Follow the prompts. Press enter to use default values.\n"); @@ -894,7 +926,7 @@ static int parse_cis_args(struct bt_iso_chan_io_qos *qos) return -EINVAL; } -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) max_pdu = parse_pdu_arg(qos); if (max_pdu < 0) { return -EINVAL; @@ -904,15 +936,15 @@ static int parse_cis_args(struct bt_iso_chan_io_qos *qos) if (burst_number < 0) { return -EINVAL; } -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ qos->rtn = rtn; qos->phy = phy; qos->sdu = sdu; -#if defined(CONFIG_BT_ISO_ADVANCED) +#if defined(CONFIG_BT_ISO_TEST_PARAMS) qos->max_pdu = max_pdu; qos->burst_number = burst_number; -#endif /* CONFIG_BT_ISO_ADVANCED */ +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ return 0; } @@ -923,9 +955,11 @@ static int change_central_settings(void) int err; printk("Change CIG settings (y/N)? (Current settings: cis_count=%u, " - "interval=%u, latency=%u)\n", - cig_create_param.num_cis, cig_create_param.interval, - cig_create_param.latency); + "C to P interval=%u, P to C interval=%u " + "C to P latency=%u, P to C latency=%u)\n", + cig_create_param.num_cis, cig_create_param.c_to_p_interval, + cig_create_param.p_to_c_interval, cig_create_param.c_to_p_latency, + cig_create_param.p_to_c_latency); c = tolower(console_getchar()); if (c == 'y') { @@ -934,9 +968,12 @@ static int change_central_settings(void) return err; } - printk("New settings: cis_count=%u, inteval=%u, latency=%u\n", - cig_create_param.num_cis, cig_create_param.interval, - cig_create_param.latency); + printk("New settings: cis_count=%u, C to P interval=%u, " + "P TO C interval=%u, C to P latency=%u " + "P TO C latency=%u\n", + cig_create_param.num_cis, cig_create_param.c_to_p_interval, + cig_create_param.p_to_c_interval, cig_create_param.c_to_p_latency, + cig_create_param.p_to_c_latency); } printk("Change TX settings (y/N)? (Current settings: rtn=%u, " diff --git a/samples/bluetooth/iso_receive/src/main.c b/samples/bluetooth/iso_receive/src/main.c index 90fdf767dc53cce..844a7161443c0e2 100644 --- a/samples/bluetooth/iso_receive/src/main.c +++ b/samples/bluetooth/iso_receive/src/main.c @@ -277,10 +277,20 @@ 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 */ }; +static void reset_semaphores(void) +{ + k_sem_reset(&sem_per_adv); + k_sem_reset(&sem_per_sync); + k_sem_reset(&sem_per_sync_lost); + k_sem_reset(&sem_per_big_info); + k_sem_reset(&sem_big_sync); + k_sem_reset(&sem_big_sync_lost); +} + int main(void) { struct bt_le_per_adv_sync_param sync_create_param; @@ -328,6 +338,7 @@ int main(void) printk("Success.\n"); do { + reset_semaphores(); per_adv_lost = false; printk("Start scanning..."); diff --git a/samples/bluetooth/mesh/CMakeLists.txt b/samples/bluetooth/mesh/CMakeLists.txt index 6ee28b12d488461..74734eb84b4504c 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/README.rst b/samples/bluetooth/mesh/README.rst index c30bb48adae3e36..58532a0600bbaa3 100644 --- a/samples/bluetooth/mesh/README.rst +++ b/samples/bluetooth/mesh/README.rst @@ -6,7 +6,7 @@ Bluetooth: Mesh Overview ******** -This sample demonstrates Bluetooth mesh functionality. It has several +This sample demonstrates Bluetooth Mesh functionality. It has several standard mesh models, and supports provisioning over both the Advertising and the GATT Provisioning Bearers (i.e. PB-ADV and PB-GATT). The application also needs a functioning serial console, since that's @@ -45,9 +45,9 @@ Refer to your :ref:`board's documentation ` for alternative flash instructions if your board doesn't support the ``flash`` target. To run the application on an :ref:`nrf5340dk_nrf5340`, a Bluetooth controller application -must also run on the network core. The :ref:`bluetooth-hci-rpmsg-sample` sample +must also run on the network core. The :ref:`bluetooth-hci-ipc-sample` sample application may be used. Build this sample with configuration -:zephyr_file:`samples/bluetooth/hci_rpmg/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf` +:zephyr_file:`samples/bluetooth/hci_ipc/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf` to enable mesh support. Interacting with the sample diff --git a/samples/bluetooth/mesh/boards/bbc_microbit.conf b/samples/bluetooth/mesh/boards/bbc_microbit.conf index 26fb05301c1c594..1655768864b1c86 100644 --- a/samples/bluetooth/mesh/boards/bbc_microbit.conf +++ b/samples/bluetooth/mesh/boards/bbc_microbit.conf @@ -32,3 +32,4 @@ CONFIG_BT_MESH_SUBNET_COUNT=1 CONFIG_BT_MESH_APP_KEY_COUNT=1 CONFIG_BT_MESH_MODEL_GROUP_COUNT=1 CONFIG_BT_MESH_LABEL_COUNT=0 +CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG=n diff --git a/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf index c638a292c910dc8..f56dfa703f14651 100644 --- a/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf +++ b/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -1,3 +1,4 @@ -# Known issue: non secure platforms do not work with settings subsystem. -CONFIG_SETTINGS=n -CONFIG_BT_SETTINGS=n +# The option adds TinyCrypt based bt_rand. +CONFIG_BT_HOST_CRYPTO=n +# The option adds GATT caching feature that is based on TinyCrypt. +CONFIG_BT_GATT_CACHING=n diff --git a/samples/bluetooth/mesh/src/main.c b/samples/bluetooth/mesh/src/main.c index 6914c4fc40975d5..b220b354fd5c17b 100644 --- a/samples/bluetooth/mesh/src/main.c +++ b/samples/bluetooth/mesh/src/main.c @@ -25,12 +25,12 @@ #define OP_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03) #define OP_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04) -static void attention_on(struct bt_mesh_model *mod) +static void attention_on(const struct bt_mesh_model *mod) { board_led_set(true); } -static void attention_off(struct bt_mesh_model *mod) +static void attention_off(const struct bt_mesh_model *mod) { board_led_set(false); } @@ -102,7 +102,7 @@ static inline uint8_t model_time_encode(int32_t ms) return 0x3f; } -static int onoff_status_send(struct bt_mesh_model *model, +static int onoff_status_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { uint32_t remaining; @@ -151,7 +151,7 @@ static void onoff_timeout(struct k_work *work) /* Generic OnOff Server message handlers */ -static int gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -159,7 +159,7 @@ static int gen_onoff_get(struct bt_mesh_model *model, return 0; } -static int gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -202,7 +202,7 @@ static int gen_onoff_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -221,7 +221,7 @@ static const struct bt_mesh_model_op gen_onoff_srv_op[] = { /* Generic OnOff Client */ -static int gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -248,7 +248,7 @@ static const struct bt_mesh_model_op gen_onoff_cli_op[] = { }; /* This application only needs one element to contain its models */ -static struct bt_mesh_model models[] = { +static const struct bt_mesh_model models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op, NULL, @@ -257,7 +257,7 @@ static struct bt_mesh_model models[] = { NULL), }; -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, models, BT_MESH_MODEL_NONE), }; diff --git a/samples/bluetooth/mesh_demo/CMakeLists.txt b/samples/bluetooth/mesh_demo/CMakeLists.txt index 07736d6c12e1aad..f5d347ab373b491 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/README.rst b/samples/bluetooth/mesh_demo/README.rst index 52a786c164d6c7f..2edb690ab196ac5 100644 --- a/samples/bluetooth/mesh_demo/README.rst +++ b/samples/bluetooth/mesh_demo/README.rst @@ -6,7 +6,7 @@ Bluetooth: Mesh Demo Overview ******** -This sample is a Bluetooth mesh application intended for demonstration +This sample is a Bluetooth Mesh application intended for demonstration purposes only. The application provisions and configures itself (i.e. no external provisioner needed) with hard-coded network and application key values. The local unicast address can be set using a NODE_ADDR build @@ -56,7 +56,7 @@ Refer to your :ref:`board's documentation ` for alternative flash instructions if your board doesn't support the ``flash`` target. To run the application on an :ref:`nrf5340dk_nrf5340`, a Bluetooth controller application -must also run on the network core. The :ref:`bluetooth-hci-rpmsg-sample` sample +must also run on the network core. The :ref:`bluetooth-hci-ipc-sample` sample application may be used. Build this sample with configuration -:zephyr_file:`samples/bluetooth/hci_rpmg/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf` +:zephyr_file:`samples/bluetooth/hci_ipc/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf` to enable mesh support. diff --git a/samples/bluetooth/mesh_demo/boards/bbc_microbit.conf b/samples/bluetooth/mesh_demo/boards/bbc_microbit.conf index 5eb087c4cedd5de..64adc46579455c3 100644 --- a/samples/bluetooth/mesh_demo/boards/bbc_microbit.conf +++ b/samples/bluetooth/mesh_demo/boards/bbc_microbit.conf @@ -22,3 +22,4 @@ CONFIG_BT_MESH_BEACON_ENABLED=n CONFIG_BT_MESH_LABEL_COUNT=1 CONFIG_BT_MESH_SETTINGS_WORKQ=n +CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG=n 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 c638a292c910dc8..f56dfa703f14651 100644 --- a/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf +++ b/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -1,3 +1,4 @@ -# Known issue: non secure platforms do not work with settings subsystem. -CONFIG_SETTINGS=n -CONFIG_BT_SETTINGS=n +# The option adds TinyCrypt based bt_rand. +CONFIG_BT_HOST_CRYPTO=n +# The option adds GATT caching feature that is based on TinyCrypt. +CONFIG_BT_GATT_CACHING=n diff --git a/samples/bluetooth/mesh_demo/src/main.c b/samples/bluetooth/mesh_demo/src/main.c index 642cce1d18ec6e0..b405fd062164f8b 100644 --- a/samples/bluetooth/mesh_demo/src/main.c +++ b/samples/bluetooth/mesh_demo/src/main.c @@ -50,14 +50,14 @@ static void heartbeat(const struct bt_mesh_hb_sub *sub, uint8_t hops, static struct bt_mesh_cfg_cli cfg_cli = { }; -static void attention_on(struct bt_mesh_model *model) +static void attention_on(const struct bt_mesh_model *model) { printk("attention_on()\n"); board_attention(true); board_play("100H100C100H100C100H100C"); } -static void attention_off(struct bt_mesh_model *model) +static void attention_off(const struct bt_mesh_model *model) { printk("attention_off()\n"); board_attention(false); @@ -74,19 +74,19 @@ static struct bt_mesh_health_srv health_srv = { BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0); -static struct bt_mesh_model root_models[] = { +static const struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), }; -static int vnd_button_pressed(struct bt_mesh_model *model, +static int vnd_button_pressed(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { printk("src 0x%04x\n", ctx->addr); - if (ctx->addr == bt_mesh_model_elem(model)->addr) { + if (ctx->addr == bt_mesh_model_elem(model)->rt->addr) { return 0; } @@ -101,11 +101,11 @@ static const struct bt_mesh_model_op vnd_ops[] = { BT_MESH_MODEL_OP_END, }; -static struct bt_mesh_model vnd_models[] = { +static const struct bt_mesh_model vnd_models[] = { BT_MESH_MODEL_VND(BT_COMP_ID_LF, MOD_LF, vnd_ops, NULL, NULL), }; -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, vnd_models), }; diff --git a/samples/bluetooth/mesh_provisioner/CMakeLists.txt b/samples/bluetooth/mesh_provisioner/CMakeLists.txt index 7b22bd0fe14cf9d..aefe3628ba876a7 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/README.rst b/samples/bluetooth/mesh_provisioner/README.rst index 4769ae09f17da08..1b37a04a4a83dec 100644 --- a/samples/bluetooth/mesh_provisioner/README.rst +++ b/samples/bluetooth/mesh_provisioner/README.rst @@ -6,7 +6,7 @@ Bluetooth: Mesh Provisioner Overview ******** -This sample demonstrates how to use the Bluetooth mesh APIs related to +This sample demonstrates how to use the Bluetooth Mesh APIs related to provisioning and using the Configuration Database (CDB). It is intended to be tested together with a device capable of being provisioned. For example, one could use the sample in @@ -54,7 +54,7 @@ Refer to your :ref:`board's documentation ` for alternative flash instructions if your board doesn't support the ``flash`` target. To run the application on an :ref:`nrf5340dk_nrf5340`, a Bluetooth controller application -must also run on the network core. The :ref:`bluetooth-hci-rpmsg-sample` sample +must also run on the network core. The :ref:`bluetooth-hci-ipc-sample` sample application may be used. Build this sample with configuration -:zephyr_file:`samples/bluetooth/hci_rpmg/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf` +:zephyr_file:`samples/bluetooth/hci_ipc/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf` to enable mesh support. 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 c638a292c910dc8..c4aa66d1201dbe8 100644 --- a/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf +++ b/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -1,3 +1,2 @@ -# Known issue: non secure platforms do not work with settings subsystem. -CONFIG_SETTINGS=n -CONFIG_BT_SETTINGS=n +# The option adds TinyCrypt based bt_rand. +CONFIG_BT_HOST_CRYPTO=n diff --git a/samples/bluetooth/mesh_provisioner/prj.conf b/samples/bluetooth/mesh_provisioner/prj.conf index 3b40d2c2c7b9a10..341dd49ed2e5125 100644 --- a/samples/bluetooth/mesh_provisioner/prj.conf +++ b/samples/bluetooth/mesh_provisioner/prj.conf @@ -1,5 +1,5 @@ #CONFIG_INIT_STACKS=y -CONFIG_MAIN_STACK_SIZE=1408 +CONFIG_MAIN_STACK_SIZE=2048 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 # The Bluetooth API should not be used from a preemptive thread: CONFIG_MAIN_THREAD_PRIORITY=-2 @@ -33,7 +33,7 @@ CONFIG_BT_MESH_RELAY=y CONFIG_BT_MESH_RELAY_RETRANSMIT_COUNT=3 CONFIG_BT_MESH_PROVISIONER=y -CONFIG_BT_MESH_PROV_DEVICE=n +CONFIG_BT_MESH_PROVISIONEE=n CONFIG_BT_MESH_CDB=y CONFIG_BT_MESH_CDB_NODE_COUNT=16 CONFIG_BT_MESH_CDB_SUBNET_COUNT=3 diff --git a/samples/bluetooth/mesh_provisioner/src/main.c b/samples/bluetooth/mesh_provisioner/src/main.c index 42eaa31207b2095..472dc020d438ee6 100644 --- a/samples/bluetooth/mesh_provisioner/src/main.c +++ b/samples/bluetooth/mesh_provisioner/src/main.c @@ -53,13 +53,13 @@ static struct bt_mesh_health_cli health_cli = { .current_status = health_current_status, }; -static struct bt_mesh_model root_models[] = { +static const struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_HEALTH_CLI(&health_cli), }; -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE), }; 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 f30e50a85ab71a8..66af1bf86b54bed 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 d39a7814943f3de..24be636d8c9af58 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 53847832e16f479..7cd656360375185 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 e9b4b670578b646..f185bfdd6c8b45c 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 addee9bf92ed6c4..135f41667e21441 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 d25259ec66025c1..b8a3da4f5b53fb5 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 000000000000000..74bed078bddb843 --- /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 000000000000000..f434010f81d27ce --- /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 000000000000000..5f47bcd05abafdf --- /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 000000000000000..e336dae38e1f15b --- /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 000000000000000..0feae717a7777a3 --- /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 000000000000000..8b81f4cc36456df --- /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 000000000000000..1331ffbededcb92 --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/src/main.c @@ -0,0 +1,436 @@ +/* + * 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 uint8_t meta[CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE]; + +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) +{ + uint32_t *broadcast_id = user_data; + struct bt_uuid_16 adv_uuid; + enum bt_pbp_announcement_feature source_features = 0U; + + memset(meta, 0, ARRAY_SIZE(meta)); + + 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; + } + + if (!bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_PBA)) { + bt_pbp_parse_announcement(data, &source_features, meta); + 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 true; + } + printk("Found Suitable Public Broadcast Announcement\n"); + pbs_found = true; + + /** + * Continue parsing if Broadcast Audio Announcement Service + * was not found. + */ + if (*broadcast_id == INVALID_BROADCAST_ID) { + return true; + } + + return false; + } + + 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 000000000000000..2523aac8ea76f16 --- /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 000000000000000..6331703e2d89a5b --- /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 000000000000000..f434010f81d27ce --- /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 000000000000000..9111cd3f614c13c --- /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 000000000000000..c73ff9c3ea9b88f --- /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 000000000000000..ca7d3f38261b781 --- /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 000000000000000..eb2bd5dc79b909e --- /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 000000000000000..c719810e243586d --- /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 000000000000000..d3bf7be5b6c36ff --- /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 3a65cc0d777d04c..95060f9167a6294 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/boards/native_sim.conf b/samples/bluetooth/tmap_bmr/boards/native_sim.conf new file mode 100644 index 000000000000000..e06b29993819415 --- /dev/null +++ b/samples/bluetooth/tmap_bmr/boards/native_sim.conf @@ -0,0 +1,10 @@ +CONFIG_LOG_MODE_IMMEDIATE=y +CONFIG_BT_TINYCRYPT_ECC=y + +CONFIG_LIBLC3=y +CONFIG_FPU=y + +# For LE-audio at 10ms intervals we need the tick counter to occur more frequently +# than every 10 ms as each PDU for some reason takes 2 ticks to process. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/bluetooth/tmap_bmr/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/samples/bluetooth/tmap_bmr/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf index f7c6bbfd3db02b3..af60fb49fbdad93 100644 --- a/samples/bluetooth/tmap_bmr/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/tmap_bmr/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -4,5 +4,5 @@ CONFIG_LIBLC3=y # 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 -# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. -CONFIG_NEWLIB_LIBC=y +# LC3 lib requires floating point support in the c-lib +CONFIG_REQUIRES_FULL_LIBC=y diff --git a/samples/bluetooth/tmap_bmr/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/bluetooth/tmap_bmr/boards/nrf5340dk_nrf5340_cpuapp.conf index f7c6bbfd3db02b3..8d48d5e1c207211 100644 --- a/samples/bluetooth/tmap_bmr/boards/nrf5340dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/tmap_bmr/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -4,5 +4,3 @@ CONFIG_LIBLC3=y # 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 -# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. -CONFIG_NEWLIB_LIBC=y diff --git a/samples/bluetooth/tmap_bmr/prj.conf b/samples/bluetooth/tmap_bmr/prj.conf index 3a0fd96f598e60b..7c3ea5b037299e5 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/sample.yaml b/samples/bluetooth/tmap_bmr/sample.yaml index 2427ef9ca823274..aaaa52961492cf7 100644 --- a/samples/bluetooth/tmap_bmr/sample.yaml +++ b/samples/bluetooth/tmap_bmr/sample.yaml @@ -4,7 +4,10 @@ sample: tests: sample.bluetooth.tmap_bmr: harness: bluetooth - platform_allow: qemu_cortex_m3 qemu_x86 + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - native_sim tags: bluetooth integration_platforms: - qemu_cortex_m3 diff --git a/samples/bluetooth/tmap_bmr/src/bap_broadcast_sink.c b/samples/bluetooth/tmap_bmr/src/bap_broadcast_sink.c index 7a306cfb30476dd..cc6c95a3fe6860f 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/boards/native_sim.conf b/samples/bluetooth/tmap_bms/boards/native_sim.conf new file mode 100644 index 000000000000000..e06b29993819415 --- /dev/null +++ b/samples/bluetooth/tmap_bms/boards/native_sim.conf @@ -0,0 +1,10 @@ +CONFIG_LOG_MODE_IMMEDIATE=y +CONFIG_BT_TINYCRYPT_ECC=y + +CONFIG_LIBLC3=y +CONFIG_FPU=y + +# For LE-audio at 10ms intervals we need the tick counter to occur more frequently +# than every 10 ms as each PDU for some reason takes 2 ticks to process. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/bluetooth/tmap_bms/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/samples/bluetooth/tmap_bms/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf index f7c6bbfd3db02b3..8d48d5e1c207211 100644 --- a/samples/bluetooth/tmap_bms/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/tmap_bms/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -4,5 +4,3 @@ CONFIG_LIBLC3=y # 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 -# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. -CONFIG_NEWLIB_LIBC=y diff --git a/samples/bluetooth/tmap_bms/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/bluetooth/tmap_bms/boards/nrf5340dk_nrf5340_cpuapp.conf index f7c6bbfd3db02b3..8d48d5e1c207211 100644 --- a/samples/bluetooth/tmap_bms/boards/nrf5340dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/tmap_bms/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -4,5 +4,3 @@ CONFIG_LIBLC3=y # 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 -# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. -CONFIG_NEWLIB_LIBC=y diff --git a/samples/bluetooth/tmap_bms/prj.conf b/samples/bluetooth/tmap_bms/prj.conf index ab3641a7a0fc0d6..be8acce18802d4d 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/sample.yaml b/samples/bluetooth/tmap_bms/sample.yaml index 83bdc86a9a2dd01..fc4410eac0eca98 100644 --- a/samples/bluetooth/tmap_bms/sample.yaml +++ b/samples/bluetooth/tmap_bms/sample.yaml @@ -4,7 +4,10 @@ sample: tests: sample.bluetooth.tmap_bms: harness: bluetooth - platform_allow: qemu_cortex_m3 qemu_x86 + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - native_sim tags: bluetooth integration_platforms: - qemu_cortex_m3 diff --git a/samples/bluetooth/tmap_bms/src/cap_initiator.c b/samples/bluetooth/tmap_bms/src/cap_initiator.c index af946f8ba945e4e..1e50977eab52126 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/boards/native_sim.conf b/samples/bluetooth/tmap_central/boards/native_sim.conf new file mode 100644 index 000000000000000..e06b29993819415 --- /dev/null +++ b/samples/bluetooth/tmap_central/boards/native_sim.conf @@ -0,0 +1,10 @@ +CONFIG_LOG_MODE_IMMEDIATE=y +CONFIG_BT_TINYCRYPT_ECC=y + +CONFIG_LIBLC3=y +CONFIG_FPU=y + +# For LE-audio at 10ms intervals we need the tick counter to occur more frequently +# than every 10 ms as each PDU for some reason takes 2 ticks to process. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/bluetooth/tmap_central/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/samples/bluetooth/tmap_central/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf index f7c6bbfd3db02b3..8d48d5e1c207211 100644 --- a/samples/bluetooth/tmap_central/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/tmap_central/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -4,5 +4,3 @@ CONFIG_LIBLC3=y # 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 -# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. -CONFIG_NEWLIB_LIBC=y diff --git a/samples/bluetooth/tmap_central/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/bluetooth/tmap_central/boards/nrf5340dk_nrf5340_cpuapp.conf index f7c6bbfd3db02b3..8d48d5e1c207211 100644 --- a/samples/bluetooth/tmap_central/boards/nrf5340dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/tmap_central/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -4,5 +4,3 @@ CONFIG_LIBLC3=y # 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 -# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. -CONFIG_NEWLIB_LIBC=y diff --git a/samples/bluetooth/tmap_central/sample.yaml b/samples/bluetooth/tmap_central/sample.yaml index 3d0e1e8a08b16aa..cf4dd36293843a6 100644 --- a/samples/bluetooth/tmap_central/sample.yaml +++ b/samples/bluetooth/tmap_central/sample.yaml @@ -4,7 +4,10 @@ sample: tests: sample.bluetooth.tmap_central: harness: bluetooth - platform_allow: qemu_cortex_m3 qemu_x86 + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - native_sim tags: bluetooth integration_platforms: - qemu_cortex_m3 diff --git a/samples/bluetooth/tmap_central/src/main.c b/samples/bluetooth/tmap_central/src/main.c index d890eb771076942..fa75817c8f91375 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/boards/native_sim.conf b/samples/bluetooth/tmap_peripheral/boards/native_sim.conf new file mode 100644 index 000000000000000..e06b29993819415 --- /dev/null +++ b/samples/bluetooth/tmap_peripheral/boards/native_sim.conf @@ -0,0 +1,10 @@ +CONFIG_LOG_MODE_IMMEDIATE=y +CONFIG_BT_TINYCRYPT_ECC=y + +CONFIG_LIBLC3=y +CONFIG_FPU=y + +# For LE-audio at 10ms intervals we need the tick counter to occur more frequently +# than every 10 ms as each PDU for some reason takes 2 ticks to process. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/bluetooth/tmap_peripheral/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/samples/bluetooth/tmap_peripheral/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf index f7c6bbfd3db02b3..8d48d5e1c207211 100644 --- a/samples/bluetooth/tmap_peripheral/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/tmap_peripheral/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -4,5 +4,3 @@ CONFIG_LIBLC3=y # 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 -# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. -CONFIG_NEWLIB_LIBC=y diff --git a/samples/bluetooth/tmap_peripheral/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/bluetooth/tmap_peripheral/boards/nrf5340dk_nrf5340_cpuapp.conf index f7c6bbfd3db02b3..8d48d5e1c207211 100644 --- a/samples/bluetooth/tmap_peripheral/boards/nrf5340dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/tmap_peripheral/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -4,5 +4,3 @@ CONFIG_LIBLC3=y # 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 -# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. -CONFIG_NEWLIB_LIBC=y diff --git a/samples/bluetooth/tmap_peripheral/prj.conf b/samples/bluetooth/tmap_peripheral/prj.conf index 6b7d7d390a8bee8..79725aaba2b6108 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/tmap_peripheral/sample.yaml b/samples/bluetooth/tmap_peripheral/sample.yaml index 69f399c5b23866a..a27626359685c7f 100644 --- a/samples/bluetooth/tmap_peripheral/sample.yaml +++ b/samples/bluetooth/tmap_peripheral/sample.yaml @@ -4,13 +4,19 @@ sample: tests: sample.bluetooth.tmap_peripheral: harness: bluetooth - platform_allow: qemu_cortex_m3 qemu_x86 + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - native_sim tags: bluetooth integration_platforms: - qemu_cortex_m3 sample.bluetooth.tmap_peripheral.duo: harness: bluetooth - platform_allow: qemu_cortex_m3 qemu_x86 + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - native_sim tags: bluetooth extra_args: OVERLAY_CONFIG="duo.conf" extra_configs: diff --git a/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c b/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c index ef78551efd1f3e5..bb431ef478ad74f 100644 --- a/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c +++ b/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c @@ -76,8 +76,12 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg) printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_freq_to_freq_hz(ret)); } - printk(" Frame Duration: %d us\n", - bt_audio_codec_cfg_get_frame_duration_us(codec_cfg)); + ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg); + if (ret > 0) { + printk(" Frame Duration: %d us\n", + bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret)); + } + if (bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation) == 0) { printk(" Channel allocation: 0x%x\n", chan_allocation); } diff --git a/samples/bluetooth/unicast_audio_client/Kconfig.sysbuild b/samples/bluetooth/unicast_audio_client/Kconfig.sysbuild new file mode 100644 index 000000000000000..f434010f81d27ce --- /dev/null +++ b/samples/bluetooth/unicast_audio_client/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/unicast_audio_client/README.rst b/samples/bluetooth/unicast_audio_client/README.rst index dc3b336d9a3f698..3735aff4ebdb29d 100644 --- a/samples/bluetooth/unicast_audio_client/README.rst +++ b/samples/bluetooth/unicast_audio_client/README.rst @@ -9,6 +9,10 @@ Overview Application demonstrating the LE Audio unicast client functionality. Scans for and connects to a LE Audio unicast server and establishes an audio stream. +This sample can be found under +:zephyr_file:`samples/bluetooth/unicast_audio_client` in the Zephyr tree. + +Check the :ref:`bluetooth samples section ` for general information. Requirements ************ @@ -18,9 +22,62 @@ Requirements Building and Running ******************** -This sample can be found under -:zephyr_file:`samples/bluetooth/unicast_audio_client` in the Zephyr tree. -Use `-DEXTRA_CONF_FILE=overlay-bt_ll_sw_split.conf` to enable required ISO -feature support in Zephyr Bluetooth Controller on supported boards. -See :ref:`bluetooth samples section ` for details. +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 nrf52840dk +-------------------------- + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/unicast_audio_client/ + :board: nrf52840dk_nrf52840 + :goals: build + :gen-args: -DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf + +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/unicast_audio_client/ + :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/unicast_audio_server/ + :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 nrf52_bsim +----------------------------------- + +Similarly to how you would for real HW, you can do: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/unicast_audio_client/ + :board: nrf52_bsim + :goals: build + :gen-args: -DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf + +Note this will produce a Linux executable in `./build/zephyr/zephyr.exe`. +For more information, check :ref:`this board documentation `. + +Building for a simulated nrf5340bsim +------------------------------------ + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/unicast_audio_client/ + :board: nrf5340bsim_nrf5340_cpuapp + :goals: build + :west-args: --sysbuild diff --git a/samples/bluetooth/unicast_audio_client/boards/native_posix.conf b/samples/bluetooth/unicast_audio_client/boards/native_sim.conf similarity index 100% rename from samples/bluetooth/unicast_audio_client/boards/native_posix.conf rename to samples/bluetooth/unicast_audio_client/boards/native_sim.conf diff --git a/samples/bluetooth/unicast_audio_client/boards/nrf52_bsim.conf b/samples/bluetooth/unicast_audio_client/boards/nrf52_bsim.conf new file mode 100644 index 000000000000000..8bfd5bc41f9bcee --- /dev/null +++ b/samples/bluetooth/unicast_audio_client/boards/nrf52_bsim.conf @@ -0,0 +1,3 @@ +# For LC3 the following configs are needed +CONFIG_FPU=y +CONFIG_LIBLC3=y diff --git a/samples/bluetooth/unicast_audio_client/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/samples/bluetooth/unicast_audio_client/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf index f7c6bbfd3db02b3..8d48d5e1c207211 100644 --- a/samples/bluetooth/unicast_audio_client/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/unicast_audio_client/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -4,5 +4,3 @@ CONFIG_LIBLC3=y # 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 -# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. -CONFIG_NEWLIB_LIBC=y diff --git a/samples/bluetooth/unicast_audio_client/boards/nrf5340bsim_nrf5340_cpuapp.conf b/samples/bluetooth/unicast_audio_client/boards/nrf5340bsim_nrf5340_cpuapp.conf new file mode 100644 index 000000000000000..7c6a3aecc26875d --- /dev/null +++ b/samples/bluetooth/unicast_audio_client/boards/nrf5340bsim_nrf5340_cpuapp.conf @@ -0,0 +1,10 @@ +# For LC3 the following configs are needed +CONFIG_FPU=y +CONFIG_LIBLC3=y + +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_CMD_TX_SIZE=255 + +CONFIG_BT_TINYCRYPT_ECC=y diff --git a/samples/bluetooth/unicast_audio_client/boards/nrf5340bsim_nrf5340_cpunet.conf b/samples/bluetooth/unicast_audio_client/boards/nrf5340bsim_nrf5340_cpunet.conf new file mode 100644 index 000000000000000..1572abe65862e5e --- /dev/null +++ b/samples/bluetooth/unicast_audio_client/boards/nrf5340bsim_nrf5340_cpunet.conf @@ -0,0 +1,6 @@ +# This configuration overlay is used when the controller, host and application are built +# all together in the network core + +# For LC3 the following configs are needed +CONFIG_FPU=y +CONFIG_LIBLC3=y diff --git a/samples/bluetooth/unicast_audio_client/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/bluetooth/unicast_audio_client/boards/nrf5340dk_nrf5340_cpuapp.conf index f7c6bbfd3db02b3..76df8dba27a4f45 100644 --- a/samples/bluetooth/unicast_audio_client/boards/nrf5340dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/unicast_audio_client/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -4,5 +4,10 @@ CONFIG_LIBLC3=y # 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 -# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. -CONFIG_NEWLIB_LIBC=y + +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_CMD_TX_SIZE=255 + +CONFIG_BT_TINYCRYPT_ECC=y diff --git a/samples/bluetooth/unicast_audio_client/sample.yaml b/samples/bluetooth/unicast_audio_client/sample.yaml index 9ca15182f523360..76ff71f350bf974 100644 --- a/samples/bluetooth/unicast_audio_client/sample.yaml +++ b/samples/bluetooth/unicast_audio_client/sample.yaml @@ -7,16 +7,19 @@ tests: platform_allow: - qemu_cortex_m3 - qemu_x86 + - nrf5340bsim_nrf5340_cpuapp + - nrf5340dk_nrf5340_cpuapp + - native_sim tags: bluetooth integration_platforms: - - qemu_cortex_m3 + - nrf5340dk_nrf5340_cpuapp + sysbuild: true sample.bluetooth.audio_unicast_client.bt_ll_sw_split: harness: bluetooth platform_allow: - - qemu_cortex_m3 - - qemu_x86 - nrf52_bsim - nrf52dk_nrf52832 + - nrf52840dk_nrf52840 integration_platforms: - nrf52dk_nrf52832 extra_args: OVERLAY_CONFIG=overlay-bt_ll_sw_split.conf diff --git a/samples/bluetooth/unicast_audio_client/src/main.c b/samples/bluetooth/unicast_audio_client/src/main.c index a3aca0424fa217d..8fe82543ab78740 100644 --- a/samples/bluetooth/unicast_audio_client/src/main.c +++ b/samples/bluetooth/unicast_audio_client/src/main.c @@ -19,6 +19,8 @@ static void start_scan(void); +uint64_t unicast_audio_recv_ctr; /* This value is exposed to test code */ + static struct bt_bap_unicast_client_cb unicast_client_cbs; static struct bt_conn *default_conn; static struct k_work_delayable audio_send_work; @@ -104,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. * @@ -120,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); } @@ -234,24 +235,28 @@ static int init_lc3(void) return ret; } - frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(codec_cfg); + 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); + } + octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg); frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true); octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg); if (freq_hz < 0) { printk("Error: Codec frequency not set, cannot start codec."); - return; + return -1; } if (frame_duration_us < 0) { printk("Error: Frame duration not set, cannot start codec."); - return; + return -1; } if (octets_per_frame < 0) { printk("Error: Octets per frame not set, cannot start codec."); - return; + return -1; } frame_duration_100us = frame_duration_us / 100; @@ -273,7 +278,9 @@ static int init_lc3(void) if (lc3_encoder == NULL) { printk("ERROR: Failed to setup LC3 encoder - wrong parameters?\n"); + return -1; } + return 0; } #else @@ -394,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; @@ -558,7 +565,9 @@ static void stream_recv(struct bt_bap_stream *stream, struct net_buf *buf) { if (info->flags & BT_ISO_FLAGS_VALID) { - printk("Incoming audio on stream %p len %u\n", stream, buf->len); + unicast_audio_recv_ctr++; + printk("Incoming audio on stream %p len %u (%"PRIu64")\n", stream, buf->len, + unicast_audio_recv_ctr); } } diff --git a/samples/bluetooth/unicast_audio_client/sysbuild.cmake b/samples/bluetooth/unicast_audio_client/sysbuild.cmake new file mode 100644 index 000000000000000..2523aac8ea76f16 --- /dev/null +++ b/samples/bluetooth/unicast_audio_client/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/unicast_audio_server/Kconfig.sysbuild b/samples/bluetooth/unicast_audio_server/Kconfig.sysbuild new file mode 100644 index 000000000000000..f434010f81d27ce --- /dev/null +++ b/samples/bluetooth/unicast_audio_server/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/unicast_audio_server/README.rst b/samples/bluetooth/unicast_audio_server/README.rst index ce7151e5fb783d0..79a062448396409 100644 --- a/samples/bluetooth/unicast_audio_server/README.rst +++ b/samples/bluetooth/unicast_audio_server/README.rst @@ -9,6 +9,11 @@ Overview Application demonstrating the LE Audio unicast server functionality. Starts advertising and awaits connection from a LE Audio unicast client. +This sample can be found under +:zephyr_file:`samples/bluetooth/unicast_audio_server` in the Zephyr tree. + +Check the :ref:`bluetooth samples section ` for general information. + Requirements ************ @@ -17,9 +22,62 @@ Requirements Building and Running ******************** -This sample can be found under -:zephyr_file:`samples/bluetooth/unicast_audio_server` in the Zephyr tree. -Use `-DEXTRA_CONF_FILE=overlay-bt_ll_sw_split.conf` to enable required ISO -feature support in Zephyr Bluetooth Controller on supported boards. -See :ref:`bluetooth samples section ` for details. +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 nrf52840dk +-------------------------- + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/unicast_audio_server/ + :board: nrf52840dk_nrf52840 + :goals: build + :gen-args: -DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf + +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/unicast_audio_server/ + :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/unicast_audio_server/ + :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 nrf52_bsim +----------------------------------- + +Similarly to how you would for real HW, you can do: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/unicast_audio_server/ + :board: nrf52_bsim + :goals: build + :gen-args: -DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf + +Note this will produce a Linux executable in `./build/zephyr/zephyr.exe`. +For more information, check :ref:`this board documentation `. + +Building for a simulated nrf5340bsim +------------------------------------ + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/unicast_audio_server/ + :board: nrf5340bsim_nrf5340_cpuapp + :goals: build + :west-args: --sysbuild diff --git a/samples/bluetooth/unicast_audio_server/boards/native_posix.conf b/samples/bluetooth/unicast_audio_server/boards/native_sim.conf similarity index 100% rename from samples/bluetooth/unicast_audio_server/boards/native_posix.conf rename to samples/bluetooth/unicast_audio_server/boards/native_sim.conf diff --git a/samples/bluetooth/unicast_audio_server/boards/nrf52_bsim.conf b/samples/bluetooth/unicast_audio_server/boards/nrf52_bsim.conf new file mode 100644 index 000000000000000..8bfd5bc41f9bcee --- /dev/null +++ b/samples/bluetooth/unicast_audio_server/boards/nrf52_bsim.conf @@ -0,0 +1,3 @@ +# For LC3 the following configs are needed +CONFIG_FPU=y +CONFIG_LIBLC3=y diff --git a/samples/bluetooth/unicast_audio_server/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/samples/bluetooth/unicast_audio_server/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf index f7c6bbfd3db02b3..8d48d5e1c207211 100644 --- a/samples/bluetooth/unicast_audio_server/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/unicast_audio_server/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -4,5 +4,3 @@ CONFIG_LIBLC3=y # 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 -# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. -CONFIG_NEWLIB_LIBC=y diff --git a/samples/bluetooth/unicast_audio_server/boards/nrf5340bsim_nrf5340_cpuapp.conf b/samples/bluetooth/unicast_audio_server/boards/nrf5340bsim_nrf5340_cpuapp.conf new file mode 100644 index 000000000000000..7c6a3aecc26875d --- /dev/null +++ b/samples/bluetooth/unicast_audio_server/boards/nrf5340bsim_nrf5340_cpuapp.conf @@ -0,0 +1,10 @@ +# For LC3 the following configs are needed +CONFIG_FPU=y +CONFIG_LIBLC3=y + +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_CMD_TX_SIZE=255 + +CONFIG_BT_TINYCRYPT_ECC=y diff --git a/samples/bluetooth/unicast_audio_server/boards/nrf5340bsim_nrf5340_cpunet.conf b/samples/bluetooth/unicast_audio_server/boards/nrf5340bsim_nrf5340_cpunet.conf new file mode 100644 index 000000000000000..8bfd5bc41f9bcee --- /dev/null +++ b/samples/bluetooth/unicast_audio_server/boards/nrf5340bsim_nrf5340_cpunet.conf @@ -0,0 +1,3 @@ +# For LC3 the following configs are needed +CONFIG_FPU=y +CONFIG_LIBLC3=y diff --git a/samples/bluetooth/unicast_audio_server/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/bluetooth/unicast_audio_server/boards/nrf5340dk_nrf5340_cpuapp.conf index f7c6bbfd3db02b3..76df8dba27a4f45 100644 --- a/samples/bluetooth/unicast_audio_server/boards/nrf5340dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/unicast_audio_server/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -4,5 +4,10 @@ CONFIG_LIBLC3=y # 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 -# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. -CONFIG_NEWLIB_LIBC=y + +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_CMD_TX_SIZE=255 + +CONFIG_BT_TINYCRYPT_ECC=y diff --git a/samples/bluetooth/unicast_audio_server/sample.yaml b/samples/bluetooth/unicast_audio_server/sample.yaml index afb93362d1eb178..0c7496e288b9566 100644 --- a/samples/bluetooth/unicast_audio_server/sample.yaml +++ b/samples/bluetooth/unicast_audio_server/sample.yaml @@ -7,16 +7,19 @@ tests: platform_allow: - qemu_cortex_m3 - qemu_x86 + - nrf5340bsim_nrf5340_cpuapp + - nrf5340dk_nrf5340_cpuapp + - native_sim tags: bluetooth integration_platforms: - - qemu_cortex_m3 + - nrf5340dk_nrf5340_cpuapp + sysbuild: true sample.bluetooth.audio_unicast_server.bt_ll_sw_split: harness: bluetooth platform_allow: - - qemu_cortex_m3 - - qemu_x86 - nrf52_bsim - nrf52dk_nrf52832 + - nrf52840dk_nrf52840 integration_platforms: - nrf52dk_nrf52832 extra_args: OVERLAY_CONFIG=overlay-bt_ll_sw_split.conf diff --git a/samples/bluetooth/unicast_audio_server/src/main.c b/samples/bluetooth/unicast_audio_server/src/main.c index 7c20ee34df8d670..700c1a1ef1e70d6 100644 --- a/samples/bluetooth/unicast_audio_server/src/main.c +++ b/samples/bluetooth/unicast_audio_server/src/main.c @@ -147,8 +147,12 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg) printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_freq_to_freq_hz(ret)); } - printk(" Frame Duration: %d us\n", - bt_audio_codec_cfg_get_frame_duration_us(codec_cfg)); + ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg); + if (ret > 0) { + printk(" Frame Duration: %d us\n", + bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret)); + } + if (bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation) == 0) { printk(" Channel allocation: 0x%x\n", chan_allocation); } @@ -354,8 +358,7 @@ static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t #if defined(CONFIG_LIBLC3) { - const int frame_duration_us = - bt_audio_codec_cfg_get_frame_duration_us(stream->codec_cfg); + int frame_duration_us; int freq; int ret; @@ -369,11 +372,14 @@ static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t return ret; } - if (frame_duration_us < 0) { + ret = bt_audio_codec_cfg_get_frame_dur(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."); *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID, BT_BAP_ASCS_REASON_CODEC_DATA); - return -1; + return ret; } frames_per_sdu = diff --git a/samples/bluetooth/unicast_audio_server/sysbuild.cmake b/samples/bluetooth/unicast_audio_server/sysbuild.cmake new file mode 100644 index 000000000000000..2523aac8ea76f16 --- /dev/null +++ b/samples/bluetooth/unicast_audio_server/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/boards/arc_secure_services/nsim_sem_normal_defconfig b/samples/boards/arc_secure_services/nsim_sem_normal_defconfig index 98b3d6edca0be0b..91b9775a7dd6be2 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 08ebe38a2541163..89f34f3585fa211 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 33373f0b54555d5..b02faffb2d6a6f0 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 000000000000000..33e471dc6b52c6d --- /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 2341a68c528cc3a..d62777871294ba3 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 241fce89d8c9cd4..8a819a03a1df328 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/esp32/flash_memory_mapped/CMakeLists.txt b/samples/boards/esp32/flash_memory_mapped/CMakeLists.txt new file mode 100644 index 000000000000000..3cdbfb0e0b10a08 --- /dev/null +++ b/samples/boards/esp32/flash_memory_mapped/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(flash_memory_mapped) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/esp32/flash_memory_mapped/README.rst b/samples/boards/esp32/flash_memory_mapped/README.rst new file mode 100644 index 000000000000000..17940504fc032ef --- /dev/null +++ b/samples/boards/esp32/flash_memory_mapped/README.rst @@ -0,0 +1,66 @@ +.. _flash_memory_mapped: + +Espressif ESP32 Flash Memory-Mapped +################################### + +Overview +******** + +ESP32 features memory hardware which allows regions of flash memory to be mapped into instruction +and data address spaces. This mapping works only for read operations. It is not possible to modify +contents of flash memory by writing to a mapped memory region. + +Mapping happens in 64 KB pages. Memory mapping hardware can map flash into the data address space +and the instruction address space. See the technical reference manual for more details and +limitations about memory mapping hardware. For more information, check `_ESP32 Flash Memory-Mapping`. + +Supported SoCs +************** + +All ESP32 SoCs support flash memory-mapped feature. + +Building and Running +******************** + +Make sure you have your board connected over USB port. + +.. code-block:: console + + west build -b esp32s3_devkitm samples/boards/esp32/flash_memory_mapped + west flash + +Sample Output +============= + +To check the output of this sample, run ``west espressif monitor`` or any other serial +console program (e.g., minicom, putty, screen, etc). +This example uses ``west espressif monitor``, which automatically detects the serial +port at ``/dev/ttyUSB0``: + +.. code-block:: console + + $ west espressif monitor + +The sample code erases the scratch area defined in DTS file and writes a 32-bytes data buffer in it. +Next, it prints that region content using flash API read and also using memory-mapped pointer. +Both readings should return the same value. Important to notice that writing using memory-mapped pointer +is not allowed. + + +.. code-block:: console + + *** Booting Zephyr OS build v3.5.0-rc3-10-g3118724fa268 *** + [00:00:00.255,000] flash_memory_mapped: memory-mapped pointer address: 0x3c040000 + [00:00:01.122,000] flash_memory_mapped: flash read using memory-mapped pointer + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |........ ........ + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |........ ........ + [00:00:01.122,000] flash_memory_mapped: writing 32-bytes data using flash API + [00:00:01.122,000] flash_memory_mapped: flash read using flash API + 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |........ ........ + 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |........ ........ + [00:00:01.122,000] flash_memory_mapped: flash read using memory-mapped pointer + 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |........ ........ + 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |........ ........ + +.. _ESP32 Flash Memory-Mapping: + https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/spi_flash/index.html#memory-mapping-api diff --git a/samples/boards/esp32/flash_memory_mapped/prj.conf b/samples/boards/esp32/flash_memory_mapped/prj.conf new file mode 100644 index 000000000000000..83a00f200cf6f1c --- /dev/null +++ b/samples/boards/esp32/flash_memory_mapped/prj.conf @@ -0,0 +1,3 @@ +CONFIG_LOG=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y diff --git a/samples/boards/esp32/flash_memory_mapped/sample.yaml b/samples/boards/esp32/flash_memory_mapped/sample.yaml new file mode 100644 index 000000000000000..c8601961d94c330 --- /dev/null +++ b/samples/boards/esp32/flash_memory_mapped/sample.yaml @@ -0,0 +1,10 @@ +sample: + description: Sample application to test memory-mapped flash region + name: flash_memory_mapped +tests: + sample.board.esp32.flash_memory_mapped: + platform_allow: + - esp32_devkitc_wroom + - esp32c3_devkitm + - esp32s3_devkitm + tags: esp32 diff --git a/samples/boards/esp32/flash_memory_mapped/src/main.c b/samples/boards/esp32/flash_memory_mapped/src/main.c new file mode 100644 index 000000000000000..a29d6db08ec5e57 --- /dev/null +++ b/samples/boards/esp32/flash_memory_mapped/src/main.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +LOG_MODULE_REGISTER(flash_memory_mapped, CONFIG_LOG_DEFAULT_LEVEL); + +int main(void) +{ + uint8_t buffer[32]; + const struct device *flash_device; + const void *mem_ptr; + spi_flash_mmap_handle_t handle; + off_t address = FIXED_PARTITION_OFFSET(scratch_partition); + size_t size = FIXED_PARTITION_SIZE(scratch_partition); + + flash_device = DEVICE_DT_GET(DT_CHOSEN(zephyr_flash_controller)); + if (!device_is_ready(flash_device)) { + printk("%s: device not ready.\n", flash_device->name); + return 0; + } + + /* map selected region */ + spi_flash_mmap(address, size, SPI_FLASH_MMAP_DATA, &mem_ptr, &handle); + LOG_INF("memory-mapped pointer address: %p", mem_ptr); + + /* erase and read flash */ + flash_erase(flash_device, address, size); + LOG_HEXDUMP_INF(mem_ptr, 32, "flash read using memory-mapped pointer"); + + LOG_INF("writing 32-bytes data using flash API"); + memset(buffer, 0, sizeof(buffer)); + for (int k = 0; k < 32; k++) { + buffer[k] = k; + } + flash_write(flash_device, address, buffer, 32); + + /* read using flash API */ + memset(buffer, 0, sizeof(buffer)); + flash_read(flash_device, address, buffer, 32); + LOG_HEXDUMP_INF(buffer, 32, "flash read using flash API"); + + LOG_HEXDUMP_INF(mem_ptr, 32, "flash read using memory-mapped pointer"); + + /* unmap mapped region */ + spi_flash_munmap(handle); + + return 0; +} diff --git a/samples/boards/mimxrt1170_evk_cm7/magic_addr/CMakeLists.txt b/samples/boards/mimxrt1170_evk_cm7/magic_addr/CMakeLists.txt new file mode 100644 index 000000000000000..b8af716702a085e --- /dev/null +++ b/samples/boards/mimxrt1170_evk_cm7/magic_addr/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(magic_addr) + +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers/memc) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/mimxrt1170_evk_cm7/magic_addr/README.rst b/samples/boards/mimxrt1170_evk_cm7/magic_addr/README.rst new file mode 100644 index 000000000000000..679343d84ff10d3 --- /dev/null +++ b/samples/boards/mimxrt1170_evk_cm7/magic_addr/README.rst @@ -0,0 +1,18 @@ +.. _flexram_magic_addr: + +FLEXRAM Magic Addr +################## + +Overview +******** + +A sample that shows how to use RT11XX FLEXRAM Magic Addr functionality + +Magic Addr is a feature of FlexRAM that allows user to configure an interrupt +on an arbitrary RAM/TCM address access. This sample shows how to use the custom +API for the flexram in zephyr to use this unique feature. + +Building and Running +******************** + +see board documentation diff --git a/samples/boards/mimxrt1170_evk_cm7/magic_addr/prj.conf b/samples/boards/mimxrt1170_evk_cm7/magic_addr/prj.conf new file mode 100644 index 000000000000000..b58887f49985ba0 --- /dev/null +++ b/samples/boards/mimxrt1170_evk_cm7/magic_addr/prj.conf @@ -0,0 +1,3 @@ +CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API=y +CONFIG_CONSOLE_SUBSYS=y +CONFIG_CONSOLE_GETCHAR=y diff --git a/samples/boards/mimxrt1170_evk_cm7/magic_addr/sample.yaml b/samples/boards/mimxrt1170_evk_cm7/magic_addr/sample.yaml new file mode 100644 index 000000000000000..10e876847f7310f --- /dev/null +++ b/samples/boards/mimxrt1170_evk_cm7/magic_addr/sample.yaml @@ -0,0 +1,12 @@ +sample: + description: RT1170 FLEXRAM Magic Addr example + name: magic addr +common: + integration_platforms: + - mimxrt1170_evk_cm7 + - mimxrt1160_evk_cm7 +tests: + sample.boards.mimxrt1170_evk.magic_addr: + platform_allow: + - mimxrt1170_evk_cm7 + - mimxrt1160_evk_cm7 diff --git a/samples/boards/mimxrt1170_evk_cm7/magic_addr/src/main.c b/samples/boards/mimxrt1170_evk_cm7/magic_addr/src/main.c new file mode 100644 index 000000000000000..6856ca8f10f9d97 --- /dev/null +++ b/samples/boards/mimxrt1170_evk_cm7/magic_addr/src/main.c @@ -0,0 +1,58 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "memc_nxp_flexram.h" +#include +#include +#include + +K_SEM_DEFINE(dtcm_magic, 0, 1); + +__dtcm_bss_section uint8_t var; +int cnt; + +void flexram_magic_addr_isr_cb(enum memc_flexram_interrupt_cause cause, + void *data) +{ + ARG_UNUSED(data); + + if (cause == flexram_dtcm_magic_addr) { + printf("Magic DTCM address accessed %d times\n", ++cnt); + k_sem_give(&dtcm_magic); + } +} + + +int main(void) +{ + memc_flexram_register_callback(flexram_magic_addr_isr_cb, NULL); + + console_init(); + + printf("%s is opening spellbook...\n", CONFIG_BOARD); + printf("Cast some characters:\n"); + + uint32_t dtcm_addr = (uint32_t)&var; + + memc_flexram_set_dtcm_magic_addr(dtcm_addr); + + uint8_t tmp; + + while (1) { + printf("\n"); + tmp = console_getchar(); + printf("Writing %c to magic addr...\n", tmp); + var = tmp; + k_sem_take(&dtcm_magic, K_FOREVER); + printf("Reading from magic addr...\n"); + printf("Magic variable got: %c\n", var); + k_sem_take(&dtcm_magic, K_FOREVER); + } + + return 0; +} diff --git a/samples/boards/nrf/clock_skew/prj.conf b/samples/boards/nrf/clock_skew/prj.conf index 8ef0d31e37abc55..957f0d60648ad69 100644 --- a/samples/boards/nrf/clock_skew/prj.conf +++ b/samples/boards/nrf/clock_skew/prj.conf @@ -1,3 +1,3 @@ CONFIG_COUNTER=y -CONFIG_NEWLIB_LIBC=y -CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y +CONFIG_REQUIRES_FULL_LIBC=y +CONFIG_REQUIRES_FLOAT_PRINTF=y diff --git a/samples/boards/nrf/ieee802154/802154_rpmsg/sample.yaml b/samples/boards/nrf/ieee802154/802154_rpmsg/sample.yaml index fe31e48ff84458c..d99dcceaa32fa01 100644 --- a/samples/boards/nrf/ieee802154/802154_rpmsg/sample.yaml +++ b/samples/boards/nrf/ieee802154/802154_rpmsg/sample.yaml @@ -5,4 +5,6 @@ sample: tests: sample.boards.nrf.802154_rpmsg: build_only: true - platform_allow: nrf5340dk_nrf5340_cpunet + platform_allow: + - nrf5340dk_nrf5340_cpunet + - nrf5340bsim_nrf5340_cpunet diff --git a/samples/boards/nrf/mesh/onoff-app/README.rst b/samples/boards/nrf/mesh/onoff-app/README.rst index e8cadccd53cbf30..35e37d6a599b578 100644 --- a/samples/boards/nrf/mesh/onoff-app/README.rst +++ b/samples/boards/nrf/mesh/onoff-app/README.rst @@ -6,7 +6,7 @@ Bluetooth: Mesh OnOff Model Overview ******** -This is a simple application demonstrating a Bluetooth mesh multi-element node. +This is a simple application demonstrating a Bluetooth Mesh multi-element node. Each element has a mesh onoff client and server model which controls one of the 4 sets of buttons and LEDs . diff --git a/samples/boards/nrf/mesh/onoff-app/src/main.c b/samples/boards/nrf/mesh/onoff-app/src/main.c index 9e8788d464260da..f0755cb70ab626f 100644 --- a/samples/boards/nrf/mesh/onoff-app/src/main.c +++ b/samples/boards/nrf/mesh/onoff-app/src/main.c @@ -54,19 +54,19 @@ #define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03) #define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04) -static int gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); -static int gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); -static int gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); -static int gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); @@ -167,7 +167,7 @@ static struct led_onoff_state led_onoff_states[] = { * Element 0 Root Models */ -static struct bt_mesh_model root_models[] = { +static const struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), @@ -181,7 +181,7 @@ static struct bt_mesh_model root_models[] = { * Element 1 Models */ -static struct bt_mesh_model secondary_0_models[] = { +static const struct bt_mesh_model secondary_0_models[] = { BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op, &gen_onoff_pub_srv_s_0, &led_onoff_states[1]), BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op, @@ -192,7 +192,7 @@ static struct bt_mesh_model secondary_0_models[] = { * Element 2 Models */ -static struct bt_mesh_model secondary_1_models[] = { +static const struct bt_mesh_model secondary_1_models[] = { BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op, &gen_onoff_pub_srv_s_1, &led_onoff_states[2]), BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op, @@ -203,7 +203,7 @@ static struct bt_mesh_model secondary_1_models[] = { * Element 3 Models */ -static struct bt_mesh_model secondary_2_models[] = { +static const struct bt_mesh_model secondary_2_models[] = { BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op, &gen_onoff_pub_srv_s_2, &led_onoff_states[3]), BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op, @@ -214,7 +214,7 @@ static struct bt_mesh_model secondary_2_models[] = { * Button to Client Model Assignments */ -struct bt_mesh_model *mod_cli_sw[] = { +const struct bt_mesh_model *mod_cli_sw[] = { &root_models[4], &secondary_0_models[1], &secondary_1_models[1], @@ -225,7 +225,7 @@ struct bt_mesh_model *mod_cli_sw[] = { * LED to Server Model Assignments */ -struct bt_mesh_model *mod_srv_sw[] = { +const struct bt_mesh_model *mod_srv_sw[] = { &root_models[3], &secondary_0_models[0], &secondary_1_models[0], @@ -236,7 +236,7 @@ struct bt_mesh_model *mod_srv_sw[] = { * Root and Secondary Element Declarations */ -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE), BT_MESH_ELEM(0, secondary_0_models, BT_MESH_MODEL_NONE), BT_MESH_ELEM(0, secondary_1_models, BT_MESH_MODEL_NONE), @@ -281,15 +281,15 @@ static uint16_t primary_net_idx; * */ -static int gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); - struct led_onoff_state *onoff_state = model->user_data; + struct led_onoff_state *onoff_state = model->rt->user_data; printk("addr 0x%04x onoff 0x%02x\n", - bt_mesh_model_elem(model)->addr, onoff_state->current); + bt_mesh_model_elem(model)->rt->addr, onoff_state->current); bt_mesh_model_msg_init(&msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); net_buf_simple_add_u8(&msg, onoff_state->current); @@ -300,17 +300,17 @@ static int gen_onoff_get(struct bt_mesh_model *model, return 0; } -static int gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct net_buf_simple *msg = model->pub->msg; - struct led_onoff_state *onoff_state = model->user_data; + struct led_onoff_state *onoff_state = model->rt->user_data; int err; onoff_state->current = net_buf_simple_pull_u8(buf); printk("addr 0x%02x state 0x%02x\n", - bt_mesh_model_elem(model)->addr, onoff_state->current); + bt_mesh_model_elem(model)->rt->addr, onoff_state->current); gpio_pin_set_dt(&onoff_state->led_device, onoff_state->current); @@ -340,7 +340,7 @@ static int gen_onoff_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -352,7 +352,7 @@ static int gen_onoff_set(struct bt_mesh_model *model, return 0; } -static int gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -361,7 +361,7 @@ static int gen_onoff_status(struct bt_mesh_model *model, state = net_buf_simple_pull_u8(buf); printk("Node 0x%04x OnOff status from 0x%04x with state 0x%02x\n", - bt_mesh_model_elem(model)->addr, ctx->addr, state); + bt_mesh_model_elem(model)->rt->addr, ctx->addr, state); return 0; } @@ -465,7 +465,7 @@ static void button_cnt_timer(struct k_timer *work) static void button_pressed_worker(struct k_work *work) { - struct bt_mesh_model *mod_cli, *mod_srv; + const struct bt_mesh_model *mod_cli, *mod_srv; struct bt_mesh_model_pub *pub_cli, *pub_srv; struct switch_data *button_sw = CONTAINER_OF(work, struct switch_data, button_work); int err; diff --git a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/README.rst b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/README.rst index 05b8d896e771400..f33bf1e77611107 100644 --- a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/README.rst +++ b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/README.rst @@ -4,7 +4,7 @@ Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models ###################################################################### Overview ******** -This is a application demonstrating a Bluetooth mesh node in +This is a application demonstrating a Bluetooth Mesh node in which Root element has following models - Generic OnOff Server diff --git a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c index 2cf7abc30485694..1c59ef8fbd75247 100644 --- a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c +++ b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.c @@ -63,12 +63,12 @@ struct vendor_state vnd_user_data; /* Definitions of models user data (End) */ -static struct bt_mesh_elem elements[]; +static const struct bt_mesh_elem elements[]; /* message handlers (Start) */ /* Generic OnOff Server message handlers */ -static int gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -95,7 +95,7 @@ static int gen_onoff_get(struct bt_mesh_model *model, return 0; } -void gen_onoff_publish(struct bt_mesh_model *model) +void gen_onoff_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -119,7 +119,7 @@ void gen_onoff_publish(struct bt_mesh_model *model) } } -static int gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -188,7 +188,7 @@ static int gen_onoff_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -261,7 +261,7 @@ static int gen_onoff_set(struct bt_mesh_model *model, } /* Generic OnOff Client message handlers */ -static int gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -277,7 +277,7 @@ static int gen_onoff_status(struct bt_mesh_model *model, } /* Generic Level (LIGHTNESS) Server message handlers */ -static int gen_level_get(struct bt_mesh_model *model, +static int gen_level_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -304,7 +304,7 @@ static int gen_level_get(struct bt_mesh_model *model, return 0; } -void gen_level_publish(struct bt_mesh_model *model) +void gen_level_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -328,7 +328,7 @@ void gen_level_publish(struct bt_mesh_model *model) } } -static int gen_level_set_unack(struct bt_mesh_model *model, +static int gen_level_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -394,7 +394,7 @@ static int gen_level_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_level_set(struct bt_mesh_model *model, +static int gen_level_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -463,7 +463,7 @@ static int gen_level_set(struct bt_mesh_model *model, return 0; } -static int gen_delta_set_unack(struct bt_mesh_model *model, +static int gen_delta_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -545,7 +545,7 @@ static int gen_delta_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_delta_set(struct bt_mesh_model *model, +static int gen_delta_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -630,7 +630,7 @@ static int gen_delta_set(struct bt_mesh_model *model, return 0; } -static int gen_move_set_unack(struct bt_mesh_model *model, +static int gen_move_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -705,7 +705,7 @@ static int gen_move_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_move_set(struct bt_mesh_model *model, +static int gen_move_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint8_t tid, tt, delay; @@ -783,7 +783,7 @@ static int gen_move_set(struct bt_mesh_model *model, } /* Generic Level Client message handlers */ -static int gen_level_status(struct bt_mesh_model *model, +static int gen_level_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -799,7 +799,7 @@ static int gen_level_status(struct bt_mesh_model *model, } /* Generic Default Transition Time Server message handlers */ -static int gen_def_trans_time_get(struct bt_mesh_model *model, +static int gen_def_trans_time_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -815,7 +815,7 @@ static int gen_def_trans_time_get(struct bt_mesh_model *model, return 0; } -static void gen_def_trans_time_publish(struct bt_mesh_model *model) +static void gen_def_trans_time_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -833,7 +833,7 @@ static void gen_def_trans_time_publish(struct bt_mesh_model *model) } } -static int gen_def_trans_time_set_unack(struct bt_mesh_model *model, +static int gen_def_trans_time_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -855,7 +855,7 @@ static int gen_def_trans_time_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_def_trans_time_set(struct bt_mesh_model *model, +static int gen_def_trans_time_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -881,7 +881,7 @@ static int gen_def_trans_time_set(struct bt_mesh_model *model, } /* Generic Default Transition Time Client message handlers */ -static int gen_def_trans_time_status(struct bt_mesh_model *model, +static int gen_def_trans_time_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -892,7 +892,7 @@ static int gen_def_trans_time_status(struct bt_mesh_model *model, } /* Generic Power OnOff Server message handlers */ -static int gen_onpowerup_get(struct bt_mesh_model *model, +static int gen_onpowerup_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -909,7 +909,7 @@ static int gen_onpowerup_get(struct bt_mesh_model *model, } /* Generic Power OnOff Client message handlers */ -static int gen_onpowerup_status(struct bt_mesh_model *model, +static int gen_onpowerup_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -921,7 +921,7 @@ static int gen_onpowerup_status(struct bt_mesh_model *model, /* Generic Power OnOff Setup Server message handlers */ -static void gen_onpowerup_publish(struct bt_mesh_model *model) +static void gen_onpowerup_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -939,7 +939,7 @@ static void gen_onpowerup_publish(struct bt_mesh_model *model) } } -static int gen_onpowerup_set_unack(struct bt_mesh_model *model, +static int gen_onpowerup_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -961,7 +961,7 @@ static int gen_onpowerup_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_onpowerup_set(struct bt_mesh_model *model, +static int gen_onpowerup_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -987,11 +987,11 @@ static int gen_onpowerup_set(struct bt_mesh_model *model, } /* Vendor Model message handlers*/ -static int vnd_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int vnd_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct net_buf_simple *msg = NET_BUF_SIMPLE(3 + 6 + 4); - struct vendor_state *state = model->user_data; + struct vendor_state *state = model->rt->user_data; /* This is dummy response for demo purpose */ state->response = 0xA578FEB3; @@ -1007,14 +1007,14 @@ static int vnd_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return 0; } -static int vnd_set_unack(struct bt_mesh_model *model, +static int vnd_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint8_t tid; int current; int64_t now; - struct vendor_state *state = model->user_data; + struct vendor_state *state = model->rt->user_data; current = net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); @@ -1040,7 +1040,7 @@ static int vnd_set_unack(struct bt_mesh_model *model, return 0; } -static int vnd_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int vnd_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { (void)vnd_set_unack(model, ctx, buf); @@ -1049,7 +1049,7 @@ static int vnd_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return 0; } -static int vnd_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int vnd_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { printk("Acknowledgement from Vendor\n"); @@ -1060,7 +1060,7 @@ static int vnd_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, } /* Light Lightness Server message handlers */ -static int light_lightness_get(struct bt_mesh_model *model, +static int light_lightness_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1087,7 +1087,7 @@ static int light_lightness_get(struct bt_mesh_model *model, return 0; } -void light_lightness_publish(struct bt_mesh_model *model) +void light_lightness_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -1111,7 +1111,7 @@ void light_lightness_publish(struct bt_mesh_model *model) } } -static int light_lightness_set_unack(struct bt_mesh_model *model, +static int light_lightness_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1177,7 +1177,7 @@ static int light_lightness_set_unack(struct bt_mesh_model *model, return 0; } -static int light_lightness_set(struct bt_mesh_model *model, +static int light_lightness_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1246,7 +1246,7 @@ static int light_lightness_set(struct bt_mesh_model *model, return 0; } -static int light_lightness_linear_get(struct bt_mesh_model *model, +static int light_lightness_linear_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1274,7 +1274,7 @@ static int light_lightness_linear_get(struct bt_mesh_model *model, return 0; } -void light_lightness_linear_publish(struct bt_mesh_model *model) +void light_lightness_linear_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -1299,7 +1299,7 @@ void light_lightness_linear_publish(struct bt_mesh_model *model) } } -static int light_lightness_linear_set_unack(struct bt_mesh_model *model, +static int light_lightness_linear_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1365,7 +1365,7 @@ static int light_lightness_linear_set_unack(struct bt_mesh_model *model, return 0; } -static int light_lightness_linear_set(struct bt_mesh_model *model, +static int light_lightness_linear_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1434,7 +1434,7 @@ static int light_lightness_linear_set(struct bt_mesh_model *model, return 0; } -static int light_lightness_last_get(struct bt_mesh_model *model, +static int light_lightness_last_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1450,7 +1450,7 @@ static int light_lightness_last_get(struct bt_mesh_model *model, return 0; } -static int light_lightness_default_get(struct bt_mesh_model *model, +static int light_lightness_default_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1467,7 +1467,7 @@ static int light_lightness_default_get(struct bt_mesh_model *model, return 0; } -static int light_lightness_range_get(struct bt_mesh_model *model, +static int light_lightness_range_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1489,7 +1489,7 @@ static int light_lightness_range_get(struct bt_mesh_model *model, /* Light Lightness Setup Server message handlers */ -static void light_lightness_default_publish(struct bt_mesh_model *model) +static void light_lightness_default_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -1508,7 +1508,7 @@ static void light_lightness_default_publish(struct bt_mesh_model *model) } } -static int light_lightness_default_set_unack(struct bt_mesh_model *model, +static int light_lightness_default_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1527,7 +1527,7 @@ static int light_lightness_default_set_unack(struct bt_mesh_model *model, return 0; } -static int light_lightness_default_set(struct bt_mesh_model *model, +static int light_lightness_default_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1549,7 +1549,7 @@ static int light_lightness_default_set(struct bt_mesh_model *model, return 0; } -static void light_lightness_range_publish(struct bt_mesh_model *model) +static void light_lightness_range_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -1569,7 +1569,7 @@ static void light_lightness_range_publish(struct bt_mesh_model *model) } } -static int light_lightness_range_set_unack(struct bt_mesh_model *model, +static int light_lightness_range_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1603,7 +1603,7 @@ static int light_lightness_range_set_unack(struct bt_mesh_model *model, return 0; } -static int light_lightness_range_set(struct bt_mesh_model *model, +static int light_lightness_range_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1641,7 +1641,7 @@ static int light_lightness_range_set(struct bt_mesh_model *model, } /* Light Lightness Client message handlers */ -static int light_lightness_status(struct bt_mesh_model *model, +static int light_lightness_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1657,7 +1657,7 @@ static int light_lightness_status(struct bt_mesh_model *model, return 0; } -static int light_lightness_linear_status(struct bt_mesh_model *model, +static int light_lightness_linear_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1673,7 +1673,7 @@ static int light_lightness_linear_status(struct bt_mesh_model *model, return 0; } -static int light_lightness_last_status(struct bt_mesh_model *model, +static int light_lightness_last_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1683,7 +1683,7 @@ static int light_lightness_last_status(struct bt_mesh_model *model, return 0; } -static int light_lightness_default_status(struct bt_mesh_model *model, +static int light_lightness_default_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1693,7 +1693,7 @@ static int light_lightness_default_status(struct bt_mesh_model *model, return 0; } -static int light_lightness_range_status(struct bt_mesh_model *model, +static int light_lightness_range_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1706,7 +1706,7 @@ static int light_lightness_range_status(struct bt_mesh_model *model, } /* Light CTL Server message handlers */ -static int light_ctl_get(struct bt_mesh_model *model, +static int light_ctl_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1736,7 +1736,7 @@ static int light_ctl_get(struct bt_mesh_model *model, return 0; } -void light_ctl_publish(struct bt_mesh_model *model) +void light_ctl_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -1766,7 +1766,7 @@ void light_ctl_publish(struct bt_mesh_model *model) } } -static int light_ctl_set_unack(struct bt_mesh_model *model, +static int light_ctl_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1845,7 +1845,7 @@ static int light_ctl_set_unack(struct bt_mesh_model *model, return 0; } -static int light_ctl_set(struct bt_mesh_model *model, +static int light_ctl_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1927,7 +1927,7 @@ static int light_ctl_set(struct bt_mesh_model *model, return 0; } -static int light_ctl_temp_range_get(struct bt_mesh_model *model, +static int light_ctl_temp_range_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1947,7 +1947,7 @@ static int light_ctl_temp_range_get(struct bt_mesh_model *model, return 0; } -static int light_ctl_default_get(struct bt_mesh_model *model, +static int light_ctl_default_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -1967,7 +1967,7 @@ static int light_ctl_default_get(struct bt_mesh_model *model, /* Light CTL Setup Server message handlers */ -static void light_ctl_default_publish(struct bt_mesh_model *model) +static void light_ctl_default_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -1987,7 +1987,7 @@ static void light_ctl_default_publish(struct bt_mesh_model *model) } } -static int light_ctl_default_set_unack(struct bt_mesh_model *model, +static int light_ctl_default_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2018,7 +2018,7 @@ static int light_ctl_default_set_unack(struct bt_mesh_model *model, return 0; } -static int light_ctl_default_set(struct bt_mesh_model *model, +static int light_ctl_default_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2052,7 +2052,7 @@ static int light_ctl_default_set(struct bt_mesh_model *model, return 0; } -static void light_ctl_temp_range_publish(struct bt_mesh_model *model) +static void light_ctl_temp_range_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -2072,7 +2072,7 @@ static void light_ctl_temp_range_publish(struct bt_mesh_model *model) } } -static int light_ctl_temp_range_set_unack(struct bt_mesh_model *model, +static int light_ctl_temp_range_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2108,7 +2108,7 @@ static int light_ctl_temp_range_set_unack(struct bt_mesh_model *model, return 0; } -static int light_ctl_temp_range_set(struct bt_mesh_model *model, +static int light_ctl_temp_range_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2148,7 +2148,7 @@ static int light_ctl_temp_range_set(struct bt_mesh_model *model, } /* Light CTL Client message handlers */ -static int light_ctl_status(struct bt_mesh_model *model, +static int light_ctl_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2168,7 +2168,7 @@ static int light_ctl_status(struct bt_mesh_model *model, return 0; } -static int light_ctl_temp_range_status(struct bt_mesh_model *model, +static int light_ctl_temp_range_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2180,7 +2180,7 @@ static int light_ctl_temp_range_status(struct bt_mesh_model *model, return 0; } -static int light_ctl_temp_status(struct bt_mesh_model *model, +static int light_ctl_temp_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2201,7 +2201,7 @@ static int light_ctl_temp_status(struct bt_mesh_model *model, return 0; } -static int light_ctl_default_status(struct bt_mesh_model *model, +static int light_ctl_default_status(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2214,7 +2214,7 @@ static int light_ctl_default_status(struct bt_mesh_model *model, } /* Light CTL Temp. Server message handlers */ -static int light_ctl_temp_get(struct bt_mesh_model *model, +static int light_ctl_temp_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2244,7 +2244,7 @@ static int light_ctl_temp_get(struct bt_mesh_model *model, return 0; } -void light_ctl_temp_publish(struct bt_mesh_model *model) +void light_ctl_temp_publish(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -2270,7 +2270,7 @@ void light_ctl_temp_publish(struct bt_mesh_model *model) } } -static int light_ctl_temp_set_unack(struct bt_mesh_model *model, +static int light_ctl_temp_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2345,7 +2345,7 @@ static int light_ctl_temp_set_unack(struct bt_mesh_model *model, return 0; } -static int light_ctl_temp_set(struct bt_mesh_model *model, +static int light_ctl_temp_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2424,7 +2424,7 @@ static int light_ctl_temp_set(struct bt_mesh_model *model, } /* Generic Level (TEMPERATURE) Server message handlers */ -static int gen_level_get_temp(struct bt_mesh_model *model, +static int gen_level_get_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2451,7 +2451,7 @@ static int gen_level_get_temp(struct bt_mesh_model *model, return 0; } -void gen_level_publish_temp(struct bt_mesh_model *model) +void gen_level_publish_temp(const struct bt_mesh_model *model) { int err; struct net_buf_simple *msg = model->pub->msg; @@ -2475,7 +2475,7 @@ void gen_level_publish_temp(struct bt_mesh_model *model) } } -static int gen_level_set_unack_temp(struct bt_mesh_model *model, +static int gen_level_set_unack_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2541,7 +2541,7 @@ static int gen_level_set_unack_temp(struct bt_mesh_model *model, return 0; } -static int gen_level_set_temp(struct bt_mesh_model *model, +static int gen_level_set_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2610,7 +2610,7 @@ static int gen_level_set_temp(struct bt_mesh_model *model, return 0; } -static int gen_delta_set_unack_temp(struct bt_mesh_model *model, +static int gen_delta_set_unack_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2692,7 +2692,7 @@ static int gen_delta_set_unack_temp(struct bt_mesh_model *model, return 0; } -static int gen_delta_set_temp(struct bt_mesh_model *model, +static int gen_delta_set_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2777,7 +2777,7 @@ static int gen_delta_set_temp(struct bt_mesh_model *model, return 0; } -static int gen_move_set_unack_temp(struct bt_mesh_model *model, +static int gen_move_set_unack_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2852,7 +2852,7 @@ static int gen_move_set_unack_temp(struct bt_mesh_model *model, return 0; } -static int gen_move_set_temp(struct bt_mesh_model *model, +static int gen_move_set_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -2931,7 +2931,7 @@ static int gen_move_set_temp(struct bt_mesh_model *model, } /* Generic Level (TEMPERATURE) Client message handlers */ -static int gen_level_status_temp(struct bt_mesh_model *model, +static int gen_level_status_temp(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -3112,7 +3112,7 @@ static const struct bt_mesh_model_op gen_level_cli_op_temp[] = { BT_MESH_MODEL_OP_END, }; -struct bt_mesh_model root_models[] = { +const struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), @@ -3172,12 +3172,12 @@ struct bt_mesh_model root_models[] = { NULL), }; -struct bt_mesh_model vnd_models[] = { +const struct bt_mesh_model vnd_models[] = { BT_MESH_MODEL_VND(CID_ZEPHYR, 0x4321, vnd_ops, &vnd_pub, &vnd_user_data), }; -struct bt_mesh_model s0_models[] = { +const struct bt_mesh_model s0_models[] = { BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_LEVEL_SRV, gen_level_srv_op_temp, &gen_level_srv_pub_s0, NULL), @@ -3190,7 +3190,7 @@ struct bt_mesh_model s0_models[] = { NULL), }; -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, vnd_models), BT_MESH_ELEM(0, s0_models, BT_MESH_MODEL_NONE), }; diff --git a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.h b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.h index 2bc4c836926607f..108075379b00dbd 100644 --- a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.h +++ b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/src/mesh/device_composition.h @@ -93,18 +93,18 @@ struct light_ctl_state { extern struct vendor_state vnd_user_data; extern struct light_ctl_state *const ctl; -extern struct bt_mesh_model root_models[]; -extern struct bt_mesh_model vnd_models[]; -extern struct bt_mesh_model s0_models[]; +extern const struct bt_mesh_model root_models[]; +extern const struct bt_mesh_model vnd_models[]; +extern const struct bt_mesh_model s0_models[]; extern const struct bt_mesh_comp comp; -void gen_onoff_publish(struct bt_mesh_model *model); -void gen_level_publish(struct bt_mesh_model *model); -void light_lightness_publish(struct bt_mesh_model *model); -void light_lightness_linear_publish(struct bt_mesh_model *model); -void light_ctl_publish(struct bt_mesh_model *model); -void light_ctl_temp_publish(struct bt_mesh_model *model); -void gen_level_publish_temp(struct bt_mesh_model *model); +void gen_onoff_publish(const struct bt_mesh_model *model); +void gen_level_publish(const struct bt_mesh_model *model); +void light_lightness_publish(const struct bt_mesh_model *model); +void light_lightness_linear_publish(const struct bt_mesh_model *model); +void light_ctl_publish(const struct bt_mesh_model *model); +void light_ctl_temp_publish(const struct bt_mesh_model *model); +void gen_level_publish_temp(const struct bt_mesh_model *model); #endif diff --git a/samples/boards/nrf/nrf53_sync_rtc/CMakeLists.txt b/samples/boards/nrf/nrf53_sync_rtc/CMakeLists.txt index da1ce866e878454..432f5497009e1e6 100644 --- a/samples/boards/nrf/nrf53_sync_rtc/CMakeLists.txt +++ b/samples/boards/nrf/nrf53_sync_rtc/CMakeLists.txt @@ -5,33 +5,17 @@ cmake_minimum_required(VERSION 3.20.0) -set(NET_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/sync_rtc_net-prefix/src/sync_rtc_net-build/zephyr) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") - set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet") +if(("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") OR + ("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp")) + message(INFO " ${BOARD} used for Application Core") else() - message(FATAL_ERROR "${BOARD} is not supported for this sample") + message(FATAL_ERROR "${BOARD} is not supported for this sample") endif() -message(INFO " ${BOARD} compile as Master in this sample") - -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(sync_rtc) enable_language(C ASM) target_sources(app PRIVATE src/main.c) - -include(ExternalProject) - -ExternalProject_Add( - sync_rtc_net - SOURCE_DIR ${APPLICATION_SOURCE_DIR}/net - INSTALL_COMMAND "" # This particular build system has no install command - CMAKE_CACHE_ARGS -DBOARD:STRING=${BOARD_REMOTE} - CMAKE_CACHE_ARGS -DDTC_OVERLAY_FILE:STRING=${NET_DTC_OVERLAY_FILE} - CMAKE_CACHE_ARGS -DEXTRA_CONF_FILE:STRING=${NET_OVERLAY_CONF} - BUILD_BYPRODUCTS "${NET_ZEPHYR_DIR}/${KERNEL_BIN_NAME}" - # NB: Do we need to pass on more CMake variables? - BUILD_ALWAYS True -) diff --git a/samples/boards/nrf/nrf53_sync_rtc/Kconfig.sysbuild b/samples/boards/nrf/nrf53_sync_rtc/Kconfig.sysbuild new file mode 100644 index 000000000000000..b6dc3d0a6d0d359 --- /dev/null +++ b/samples/boards/nrf/nrf53_sync_rtc/Kconfig.sysbuild @@ -0,0 +1,10 @@ +# 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 "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" diff --git a/samples/boards/nrf/nrf53_sync_rtc/README.rst b/samples/boards/nrf/nrf53_sync_rtc/README.rst index a1224ab94826af4..0b2fd2a22fa5060 100644 --- a/samples/boards/nrf/nrf53_sync_rtc/README.rst +++ b/samples/boards/nrf/nrf53_sync_rtc/README.rst @@ -28,7 +28,9 @@ Building the application for nrf5340dk_nrf5340_cpuapp .. zephyr-app-commands:: :zephyr-app: samples/boards/nrf/nrf53_sync_rtc :board: nrf5340dk_nrf5340_cpuapp - :goals: flash "flash --hex-file build/sync_rtc_net-prefix/src/sync_rtc_net-build/zephyr/zephyr.hex" + :goals: flash + :flash-args: --hex-file build/nrf53_sync_rtc/zephyr/zephyr.hex + :west-args: --sysbuild Open a serial terminals (for example Minicom or PuTTY) and connect the board with the following settings: @@ -73,3 +75,24 @@ When you reset the development kit, the following messages (one for master and o Observe that initially logging timestamps for the corresponding events on both cores do not match. Same with local and remote timestamps reported on network core. After RTC synchronization is completed they start to match. + +.. _nrf53_sync_rtc_sample_build_bsim: + +Building the application for the simulated nrf5340bsim +****************************************************** + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/nrf/nrf53_sync_rtc + :host-os: unix + :board: nrf5340bsim_nrf5340_cpuapp + :goals: build + :west-args: --sysbuild + +Then you can execute your application using: + +.. code-block:: console + + $ ./build/zephyr/zephyr.exe -nosim + # Press Ctrl+C to exit + +You can expect a similar output as in the real HW in the invoking console. diff --git a/samples/boards/nrf/nrf53_sync_rtc/net/CMakeLists.txt b/samples/boards/nrf/nrf53_sync_rtc/net/CMakeLists.txt index 7612c9a9cec0f54..feced555bc77f1c 100644 --- a/samples/boards/nrf/nrf53_sync_rtc/net/CMakeLists.txt +++ b/samples/boards/nrf/nrf53_sync_rtc/net/CMakeLists.txt @@ -5,13 +5,15 @@ cmake_minimum_required(VERSION 3.20.0) -if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpunet") - message(INFO " ${BOARD} compile as slave in this sample") +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +if(("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpunet") OR + ("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpunet")) + message(INFO " ${BOARD} used for Network Core") else() message(FATAL_ERROR "${BOARD} is not supported for this sample") endif() -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(sync_rtc_net) target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/nrf/nrf53_sync_rtc/net/boards/nrf5340bsim_nrf5340_cpunet.conf b/samples/boards/nrf/nrf53_sync_rtc/net/boards/nrf5340bsim_nrf5340_cpunet.conf new file mode 100644 index 000000000000000..e57e7e2174ffd0e --- /dev/null +++ b/samples/boards/nrf/nrf53_sync_rtc/net/boards/nrf5340bsim_nrf5340_cpunet.conf @@ -0,0 +1 @@ +CONFIG_BUILD_OUTPUT_EXE=n diff --git a/samples/boards/nrf/nrf53_sync_rtc/net/sample.yaml b/samples/boards/nrf/nrf53_sync_rtc/net/sample.yaml deleted file mode 100644 index f6b337dac24601c..000000000000000 --- a/samples/boards/nrf/nrf53_sync_rtc/net/sample.yaml +++ /dev/null @@ -1,11 +0,0 @@ -sample: - description: This app shows how RTCs are synchronized - on nrf53 cores. - name: nRF53 Synchronized RTC sample (net) -common: - harness: remote -tests: - sample.boards.nrf.nrf53_sync_rtc.net: - platform_allow: nrf5340dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet diff --git a/samples/boards/nrf/nrf53_sync_rtc/net/src/main.c b/samples/boards/nrf/nrf53_sync_rtc/net/src/main.c index 55bbcfd2e88bb0e..17cf5cb67ead8f1 100644 --- a/samples/boards/nrf/nrf53_sync_rtc/net/src/main.c +++ b/samples/boards/nrf/nrf53_sync_rtc/net/src/main.c @@ -13,6 +13,13 @@ #include LOG_MODULE_REGISTER(main); +#if (CONFIG_SOC_SERIES_BSIM_NRFXX) +extern uint32_t shared_cell_buffer; +static uint32_t shared_cell = (uintptr_t)&shared_cell_buffer; +#else +static uint32_t shared_cell = 0x20070000; +#endif + static void sync_callback(void) { int32_t offset = z_nrf_rtc_timer_nrf53net_offset_get(); @@ -20,7 +27,6 @@ static void sync_callback(void) __ASSERT(offset >= 0, "Synchronization should be completed"); uint32_t timestamp = sys_clock_tick_get_32() + offset; - uint32_t shared_cell = 0x20070000; uint32_t app_timestamp = *(volatile uint32_t *)shared_cell; LOG_INF("Local timestamp: %u, application core timestamp: %u", diff --git a/samples/boards/nrf/nrf53_sync_rtc/sample.yaml b/samples/boards/nrf/nrf53_sync_rtc/sample.yaml index 54c63eb56e1dfe9..d1905e0cc47848e 100644 --- a/samples/boards/nrf/nrf53_sync_rtc/sample.yaml +++ b/samples/boards/nrf/nrf53_sync_rtc/sample.yaml @@ -3,9 +3,23 @@ sample: on nrf53 cores. name: nRF53 Synchronized RTC sample common: - harness: remote + sysbuild: true tests: - sample.boards.nrf.nrf53_sync_rtc: - platform_allow: nrf5340dk_nrf5340_cpuapp + sample.boards.nrf.nrf53_sync_rtc.real_hw: + platform_allow: + - nrf5340dk_nrf5340_cpuapp integration_platforms: - nrf5340dk_nrf5340_cpuapp + harness: remote + sample.boards.nrf.nrf53_sync_rtc.simu: + platform_allow: + - nrf5340bsim_nrf5340_cpuapp + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "main: Synchronization using mbox driver" + - "sync_rtc: Updated timestamp to synchronized RTC by .* ticks" + - "main: IPC send at .* ticks" + - "main: Local timestamp: .*, application core timestamp:" diff --git a/samples/boards/nrf/nrf53_sync_rtc/src/main.c b/samples/boards/nrf/nrf53_sync_rtc/src/main.c index 0498fe7b5021f3d..9c150fd1d46d46d 100644 --- a/samples/boards/nrf/nrf53_sync_rtc/src/main.c +++ b/samples/boards/nrf/nrf53_sync_rtc/src/main.c @@ -11,11 +11,22 @@ #include LOG_MODULE_REGISTER(main); +#if (CONFIG_SOC_SERIES_BSIM_NRFXX) +#include "nsi_cpu_if.h" + +/* For simulation, we can define shared memory variables linkable from + * other MCUs just by using NATIVE_SIMULATOR_IF + */ +NATIVE_SIMULATOR_IF uint32_t shared_cell_buffer; +static uint32_t shared_cell = (uintptr_t)&shared_cell_buffer; +#else +static uint32_t shared_cell = 0x20070000; +#endif + static void timeout_handler(struct k_timer *timer) { nrf_ipc_task_t task = offsetof(NRF_IPC_Type, TASKS_SEND[2]); uint32_t now = sys_clock_tick_get_32(); - uint32_t shared_cell = 0x20070000; *(volatile uint32_t *)shared_cell = now; nrf_ipc_task_trigger(NRF_IPC, task); diff --git a/samples/boards/nrf/nrf53_sync_rtc/sysbuild.cmake b/samples/boards/nrf/nrf53_sync_rtc/sysbuild.cmake new file mode 100644 index 000000000000000..0c97244fd7b314a --- /dev/null +++ b/samples/boards/nrf/nrf53_sync_rtc/sysbuild.cmake @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if("${SB_CONFIG_NET_CORE_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 net) + +ExternalZephyrProject_Add( + APPLICATION ${REMOTE_APP} + SOURCE_DIR ${APP_DIR}/${REMOTE_APP} + BOARD ${SB_CONFIG_NET_CORE_BOARD} +) + +native_simulator_set_child_images(${DEFAULT_IMAGE} ${REMOTE_APP}) + +native_simulator_set_final_executable(${DEFAULT_IMAGE}) diff --git a/samples/boards/nrf/nrfx/Kconfig b/samples/boards/nrf/nrfx/Kconfig index 0d54067202a2276..a46af347ba932e3 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 32cbfc3279cccd1..d4f0c29699f8806 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 615b800545e4863..8b3819f2d8a15c0 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/nrf/nrfx_prs/src/main.c b/samples/boards/nrf/nrfx_prs/src/main.c index 618c07181434c6e..934bbbe834d4126 100644 --- a/samples/boards/nrf/nrfx_prs/src/main.c +++ b/samples/boards/nrf/nrfx_prs/src/main.c @@ -191,7 +191,7 @@ static bool spim_transfer(const uint8_t *tx_data, size_t tx_data_len, static void uarte_handler(const nrfx_uarte_event_t *p_event, void *p_context) { if (p_event->type == NRFX_UARTE_EVT_RX_DONE) { - received = p_event->data.rx.bytes; + received = p_event->data.rx.length; k_sem_give(&transfer_finished); } else if (p_event->type == NRFX_UARTE_EVT_ERROR) { received = 0; diff --git a/samples/boards/reel_board/mesh_badge/README.rst b/samples/boards/reel_board/mesh_badge/README.rst index d5973ab8e9c4afd..ccfc7e771aeaacb 100644 --- a/samples/boards/reel_board/mesh_badge/README.rst +++ b/samples/boards/reel_board/mesh_badge/README.rst @@ -6,7 +6,7 @@ Mesh Badge Overview ******** -This sample app for the reel board showcases Bluetooth mesh +This sample app for the reel board showcases Bluetooth Mesh The app starts off as a regular Bluetooth GATT peripheral application. Install the "nRF Connect" app on your phone (available both for @@ -34,7 +34,7 @@ Steps to set up you're not happy with it you can try writing something else. #. When you're happy with the text, disconnect from the board (exit the app or go back to the device scan page) -#. Once disconnected the board switches over to Bluetooth mesh mode, and you +#. Once disconnected the board switches over to Bluetooth Mesh mode, and you can't connect to it anymore over GATT. If you configure multiple boards like this they can communicate with diff --git a/samples/boards/reel_board/mesh_badge/src/main.c b/samples/boards/reel_board/mesh_badge/src/main.c index 13dedb3a5c18798..49dd110ec0eec14 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/reel_board/mesh_badge/src/mesh.c b/samples/boards/reel_board/mesh_badge/src/mesh.c index d2916d141e652f0..0b9aff947b0cd8d 100644 --- a/samples/boards/reel_board/mesh_badge/src/mesh.c +++ b/samples/boards/reel_board/mesh_badge/src/mesh.c @@ -159,12 +159,12 @@ static struct bt_mesh_cfg_cli cfg_cli = { .cb = &cfg_cli_cb, }; -static void attention_on(struct bt_mesh_model *model) +static void attention_on(const struct bt_mesh_model *model) { board_show_text("Attention!", false, K_SECONDS(2)); } -static void attention_off(struct bt_mesh_model *model) +static void attention_off(const struct bt_mesh_model *model) { board_refresh_display(); } @@ -179,15 +179,15 @@ static struct bt_mesh_health_srv health_srv = { }; /* Generic OnOff Server message handlers */ -static int gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); - struct led_onoff_state *state = model->user_data; + struct led_onoff_state *state = model->rt->user_data; printk("addr 0x%04x onoff 0x%02x\n", - bt_mesh_model_elem(model)->addr, state->current); + bt_mesh_model_elem(model)->rt->addr, state->current); bt_mesh_model_msg_init(&msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); net_buf_simple_add_u8(&msg, state->current); @@ -198,12 +198,12 @@ static int gen_onoff_get(struct bt_mesh_model *model, return 0; } -static int gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct net_buf_simple *msg = model->pub->msg; - struct led_onoff_state *state = model->user_data; + struct led_onoff_state *state = model->rt->user_data; int err; uint8_t tid, onoff; int64_t now; @@ -229,7 +229,7 @@ static int gen_onoff_set_unack(struct bt_mesh_model *model, state->last_msg_timestamp = now; printk("addr 0x%02x state 0x%02x\n", - bt_mesh_model_elem(model)->addr, state->current); + bt_mesh_model_elem(model)->rt->addr, state->current); if (set_led_state(state->dev_id, onoff)) { printk("Failed to set led state\n"); @@ -263,7 +263,7 @@ static int gen_onoff_set_unack(struct bt_mesh_model *model, return 0; } -static int gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -273,7 +273,7 @@ static int gen_onoff_set(struct bt_mesh_model *model, return 0; } -static int sensor_desc_get(struct bt_mesh_model *model, +static int sensor_desc_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -333,7 +333,7 @@ static void sensor_create_status(uint16_t id, struct net_buf_simple *msg) } } -static int sensor_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int sensor_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(msg, 1 + MAX_SENS_STATUS_LEN + 4); @@ -349,7 +349,7 @@ static int sensor_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return 0; } -static int sensor_col_get(struct bt_mesh_model *model, +static int sensor_col_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -357,7 +357,7 @@ static int sensor_col_get(struct bt_mesh_model *model, return 0; } -static int sensor_series_get(struct bt_mesh_model *model, +static int sensor_series_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { @@ -385,7 +385,7 @@ static const struct bt_mesh_model_op sensor_srv_op[] = { { BT_MESH_MODEL_OP_SENS_SERIES_GET, BT_MESH_LEN_EXACT(2), sensor_series_get }, }; -static struct bt_mesh_model root_models[] = { +static const struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), @@ -396,7 +396,7 @@ static struct bt_mesh_model root_models[] = { sensor_srv_op, NULL, NULL), }; -static int vnd_hello(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int vnd_hello(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { char str[32]; @@ -404,7 +404,7 @@ static int vnd_hello(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, printk("Hello message from 0x%04x\n", ctx->addr); - if (ctx->addr == bt_mesh_model_elem(model)->addr) { + if (ctx->addr == bt_mesh_model_elem(model)->rt->addr) { printk("Ignoring message from self\n"); return 0; } @@ -423,7 +423,7 @@ static int vnd_hello(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return 0; } -static int vnd_baduser(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, +static int vnd_baduser(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { char str[32]; @@ -431,7 +431,7 @@ static int vnd_baduser(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, printk("\"Bad user\" message from 0x%04x\n", ctx->addr); - if (ctx->addr == bt_mesh_model_elem(model)->addr) { + if (ctx->addr == bt_mesh_model_elem(model)->rt->addr) { printk("Ignoring message from self\n"); return 0; } @@ -448,14 +448,14 @@ static int vnd_baduser(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return 0; } -static int vnd_heartbeat(struct bt_mesh_model *model, +static int vnd_heartbeat(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { uint8_t init_ttl, hops; /* Ignore messages from self */ - if (ctx->addr == bt_mesh_model_elem(model)->addr) { + if (ctx->addr == bt_mesh_model_elem(model)->rt->addr) { return 0; } @@ -477,7 +477,7 @@ static const struct bt_mesh_model_op vnd_ops[] = { BT_MESH_MODEL_OP_END, }; -static int pub_update(struct bt_mesh_model *mod) +static int pub_update(const struct bt_mesh_model *mod) { struct net_buf_simple *msg = mod->pub->msg; @@ -491,11 +491,11 @@ static int pub_update(struct bt_mesh_model *mod) BT_MESH_MODEL_PUB_DEFINE(vnd_pub, pub_update, 3 + 1); -static struct bt_mesh_model vnd_models[] = { +static const struct bt_mesh_model vnd_models[] = { BT_MESH_MODEL_VND(BT_COMP_ID_LF, MOD_LF, vnd_ops, &vnd_pub, NULL), }; -static struct bt_mesh_elem elements[] = { +static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, vnd_models), }; @@ -638,12 +638,12 @@ void mesh_start(void) bool mesh_is_initialized(void) { - return elements[0].addr != BT_MESH_ADDR_UNASSIGNED; + return elements[0].rt->addr != BT_MESH_ADDR_UNASSIGNED; } uint16_t mesh_get_addr(void) { - return elements[0].addr; + return elements[0].rt->addr; } int mesh_init(void) diff --git a/samples/boards/sensortile_box_pro/sensors-on-board/CMakeLists.txt b/samples/boards/sensortile_box_pro/sensors-on-board/CMakeLists.txt new file mode 100644 index 000000000000000..4904facbcd13140 --- /dev/null +++ b/samples/boards/sensortile_box_pro/sensors-on-board/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2023 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(sensortile_box_pro) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/sensortile_box_pro/sensors-on-board/README.rst b/samples/boards/sensortile_box_pro/sensors-on-board/README.rst new file mode 100644 index 000000000000000..ce0034e2d86d289 --- /dev/null +++ b/samples/boards/sensortile_box_pro/sensors-on-board/README.rst @@ -0,0 +1,78 @@ +.. _sensortile_box_pro_sample_sensors: + +ST SensorTile.box Pro on-board sensors test +########################################### + +Overview +******** +This sample provides an example of how to read sensors data +from the SensorTile.box Pro board. + +This sample enables all sensors of SensorTile.box Pro board, and then +periodically reads and displays data on the console from the following +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 +************ + +The application requires a SensorTile.box Pro board connected to the PC +through USB. The board shows up as a USB CDC class standard device. + +References +********** + +- :ref:`sensortile_box_pro_board` + +Building and Running +******************** + +Build and flash the sample in the following way: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/sensortile_box_pro/sensors-on-board + :board: sensortile_box_pro + :goals: build flash + +Please note that flashing the board requires a few preliminary steps described +in :ref:`sensortile_box_pro_board`. + +Then, power cycle the board by disconnecting and reconnecting the USB cable. +Run your favorite terminal program to listen for output. + +.. code-block:: console + + $ minicom -D -b 115200 + +Replace :code:`` with the correct device path automatically created on +the host after the SensorTile.box Pro board gets connected to it, +usually :code:`/dev/ttyUSBx` or :code:`/dev/ttyACMx` (with x being 0, 1, 2, ...). +The ``-b`` option sets baud rate ignoring the value from config. + +Sample Output +============= + +The sample code outputs sensors data on the SensorTile.box Pro console. + + .. code-block:: console + + SensorTile.box Pro dashboard + + HTS221: Temperature: 26.4 C + HTS221: Relative Humidity: 60.5% + LPS22DF: Temperature: 28.4 C + 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 new file mode 100644 index 000000000000000..97e6a2d17f220e2 --- /dev/null +++ b/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf @@ -0,0 +1,16 @@ +CONFIG_LOG=y +CONFIG_PRINTK=y +CONFIG_SPI=y +CONFIG_I2C=y +CONFIG_GPIO=y + +# config sensors +CONFIG_SENSOR=y +CONFIG_SENSOR_LOG_LEVEL_DBG=y +CONFIG_HTS221_TRIGGER_NONE=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/sample.yaml b/samples/boards/sensortile_box_pro/sensors-on-board/sample.yaml new file mode 100644 index 000000000000000..d723fcdd7c75add --- /dev/null +++ b/samples/boards/sensortile_box_pro/sensors-on-board/sample.yaml @@ -0,0 +1,12 @@ +sample: + description: SensorTile.box Pro board testing + name: SensorTile.box Pro test +tests: + sample.board.sensortile_box_pro.sensors-on-board: + harness: sensor + platform_allow: sensortile_box_pro + tags: sensors + depends_on: + - i2c + - spi + - gpio 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 new file mode 100644 index 000000000000000..cc27fc2c125a2dd --- /dev/null +++ b/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#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_PRESS); + lps22df_trig_cnt++; +} +#endif + +#ifdef CONFIG_LSM6DSV16X_TRIGGER +static int lsm6dsv16x_acc_trig_cnt; +static int lsm6dsv16x_gyr_trig_cnt; +static int lsm6dsv16x_temp_trig_cnt; + +static void lsm6dsv16x_acc_trig_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); + lsm6dsv16x_acc_trig_cnt++; +} + +static void lsm6dsv16x_gyr_trig_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ); + lsm6dsv16x_gyr_trig_cnt++; +} + +static void lsm6dsv16x_temp_trig_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_DIE_TEMP); + lsm6dsv16x_temp_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_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; + + /* set LPS22DF sampling frequency to 50 Hz */ + odr_attr.val1 = 50; + 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\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 +} + +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 fs 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 fs 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); + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_GYRO_XYZ; + sensor_trigger_set(lsm6dsv16x, &trig, lsm6dsv16x_gyr_trig_handler); + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_DIE_TEMP; + sensor_trigger_set(lsm6dsv16x, &trig, lsm6dsv16x_temp_trig_handler); +#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 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); + const struct gpio_dt_spec led1_gpio = GPIO_DT_SPEC_GET(DT_ALIAS(led1), gpios); + const struct gpio_dt_spec led2_gpio = GPIO_DT_SPEC_GET(DT_ALIAS(led2), gpios); + const struct gpio_dt_spec led3_gpio = GPIO_DT_SPEC_GET(DT_ALIAS(led3), gpios); + int i; + + /* led 0 */ + if (!gpio_is_ready_dt(&led0_gpio)) { + printk("%s: device not ready.\n", led0_gpio.port->name); + return -1; + } + gpio_pin_configure_dt(&led0_gpio, GPIO_OUTPUT_INACTIVE); + + /* led 1 */ + if (!gpio_is_ready_dt(&led1_gpio)) { + printk("%s: device not ready.\n", led1_gpio.port->name); + return -1; + } + gpio_pin_configure_dt(&led1_gpio, GPIO_OUTPUT_INACTIVE); + + /* led 2 */ + if (!gpio_is_ready_dt(&led2_gpio)) { + printk("%s: device not ready.\n", led2_gpio.port->name); + return -1; + } + gpio_pin_configure_dt(&led2_gpio, GPIO_OUTPUT_INACTIVE); + + /* led 3 */ + if (!gpio_is_ready_dt(&led3_gpio)) { + printk("%s: device not ready.\n", led3_gpio.port->name); + return -1; + } + gpio_pin_configure_dt(&led3_gpio, GPIO_OUTPUT_INACTIVE); + + /* output led pattern */ + for (i = 0; i < 12; i++) { + gpio_pin_set_dt(&led0_gpio, ((i % 4) == 0) ? 1 : 0); + gpio_pin_set_dt(&led1_gpio, ((i % 4) == 1) ? 1 : 0); + gpio_pin_set_dt(&led2_gpio, ((i % 4) == 2) ? 1 : 0); + gpio_pin_set_dt(&led3_gpio, ((i % 4) == 3) ? 1 : 0); + k_sleep(K_MSEC(100)); + } + + /* turn all leds off */ + gpio_pin_set_dt(&led0_gpio, 0); + gpio_pin_set_dt(&led1_gpio, 0); + gpio_pin_set_dt(&led2_gpio, 0); + gpio_pin_set_dt(&led3_gpio, 0); + + return 0; +} + +int main(void) +{ + int cnt = 1; + + /* signal that sample is started */ + if (led_pattern_out() < 0) { + return -1; + } + + printk("SensorTile.box Pro sensor test\n"); + + const struct device *const hts221 = DEVICE_DT_GET_ONE(st_hts221); + 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); + return 0; + } + if (!device_is_ready(lps22df)) { + printk("%s: device not ready.\n", lps22df->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(lis2du12)) { + printk("%s: device not ready.\n", lis2du12->name); + return 0; + } + + lis2du12_config(lis2du12); + lis2mdl_config(lis2mdl); + lps22df_config(lps22df); + lsm6dsv16x_config(lsm6dsv16x); + + while (1) { + struct sensor_value hts221_hum, hts221_temp; + struct sensor_value lps22df_press, lps22df_temp; + 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) { + printf("HTS221 Sensor sample update error\n"); + return 0; + } + +#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 Sensor sample update error\n"); + return 0; + } +#endif + +#ifndef CONFIG_LIS2MDL_TRIGGER + if (sensor_sample_fetch(lis2mdl) < 0) { + printf("LIS2MDL Magn Sensor sample update error\n"); + return 0; + } +#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); + sensor_channel_get(lps22df, SENSOR_CHAN_PRESS, &lps22df_press); + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, lsm6dsv16x_accel); + 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 */ + + /* Clear terminal (ANSI ESC-C) */ + printf("\0033\014"); + + printf("SensorTile.box dashboard\n\n"); + + /* HTS221 temperature */ + printf("HTS221: Temperature: %.1f C\n", + sensor_value_to_double(&hts221_temp)); + + /* HTS221 humidity */ + printf("HTS221: Relative Humidity: %.1f%%\n", + sensor_value_to_double(&hts221_hum)); + + /* temperature */ + printf("LPS22DF: Temperature: %.1f C\n", + sensor_value_to_double(&lps22df_temp)); + + /* pressure */ + printf("LPS22DF: Pressure: %.3f kpa\n", + sensor_value_to_double(&lps22df_press)); + + printf("LSM6DSV16X: Accel (m.s-2): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dsv16x_accel[0]), + sensor_value_to_double(&lsm6dsv16x_accel[1]), + sensor_value_to_double(&lsm6dsv16x_accel[2])); + + printf("LSM6DSV16X: GYro (dps): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dsv16x_gyro[0]), + sensor_value_to_double(&lsm6dsv16x_gyro[1]), + sensor_value_to_double(&lsm6dsv16x_gyro[2])); + + /* 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("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 + +#ifdef CONFIG_LSM6DSV16X_TRIGGER + printk("%d:: lsm6dsv16x acc trig %d\n", cnt, lsm6dsv16x_acc_trig_cnt); + printk("%d:: lsm6dsv16x gyr trig %d\n", cnt, lsm6dsv16x_gyr_trig_cnt); +#endif + +#ifdef CONFIG_LIS2MDL_TRIGGER + 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/CMakeLists.txt b/samples/boards/stm32/power_mgmt/adc/CMakeLists.txt new file mode 100644 index 000000000000000..b0eea852bf52b75 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/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_adc) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/stm32/power_mgmt/adc/README.rst b/samples/boards/stm32/power_mgmt/adc/README.rst new file mode 100644 index 000000000000000..2ec694884fadf5c --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/README.rst @@ -0,0 +1,42 @@ +.. _stm32-pm-adc-sample: + +STM32 PM ADC +############ + +Overview +******** + +This sample is a minimum application to demonstrate basic power management +behavior in a basic ADC set up in low power context. + +.. _stm32-pm-adc-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`). + +Building and Running +******************** + +Build and flash as follows, changing ``nucleo_wb55rg`` for your board: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/stm32/power_mgmt/adc + :board: nucleo_wb55rg + :goals: build flash + :compact: + +After flashing, the console shows the ADC measurement in the form: +``ADC reading[0]:`` +``- adc@50040000, channel 3: 1158 = 932 mV`` + +PM configurations +***************** + +By default, :kconfig:option:`CONFIG_PM_DEVICE` and :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME` are +enabled. +On STM32WB, we can observe a power consumption of about 25µA with both kconfig +enabled, 27.5µA without (each time with :kconfig:option:`CONFIG_PM` enabled). diff --git a/samples/boards/stm32/power_mgmt/adc/boards/nucleo_g474re.overlay b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_g474re.overlay new file mode 100644 index 000000000000000..bde07e0f2d621f4 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_g474re.overlay @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +#include + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 1>; + }; +}; + +&adc1 { + #address-cells = <1>; + #size-cells = <0>; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wb55rg.overlay b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wb55rg.overlay new file mode 100644 index 000000000000000..6a39f681c454ea2 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wb55rg.overlay @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 3>; + }; +}; + +&adc1 { + pinctrl-0 = <&adc1_in3_pc2>; + #address-cells = <1>; + #size-cells = <0>; + + channel@3 { + reg = <3>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay new file mode 100644 index 000000000000000..f92c541e298a243 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + 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/adc/prj.conf b/samples/boards/stm32/power_mgmt/adc/prj.conf new file mode 100644 index 000000000000000..c5359fe02387d41 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/prj.conf @@ -0,0 +1,6 @@ +CONFIG_PM=y +CONFIG_PM_DEVICE=y +CONFIG_PM_DEVICE_RUNTIME=y +CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n +CONFIG_ADC=y +#CONFIG_DEBUG=y diff --git a/samples/boards/stm32/power_mgmt/adc/sample.yaml b/samples/boards/stm32/power_mgmt/adc/sample.yaml new file mode 100644 index 000000000000000..e3892df7b5cedda --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/sample.yaml @@ -0,0 +1,17 @@ +sample: + name: STM32 ADC Power Management +tests: + sample.boards.stm32.power_mgmt.adc: + tags: + - adc + - power + harness: console + harness_config: + type: one_line + regex: + - "Device ready" + filter: dt_compat_enabled("zephyr,power-state") and + dt_compat_enabled("st,stm32-adc") and + dt_compat_enabled("st,stm32-lptim") + extra_args: "CONFIG_DEBUG=y" + platform_allow: nucleo_wb55rg diff --git a/samples/boards/stm32/power_mgmt/adc/src/main.c b/samples/boards/stm32/power_mgmt/adc/src/main.c new file mode 100644 index 000000000000000..b75ab4a9af2ce70 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/adc/src/main.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define SLEEP_TIME_MS 2000 + +#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) +}; + +int main(void) +{ + int err; + uint32_t count = 0; + 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("Device ready\n"); + + while (true) { + 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); + } + } + + k_msleep(SLEEP_TIME_MS); + } + return 0; +} diff --git a/samples/boards/stm32/power_mgmt/blinky/README.rst b/samples/boards/stm32/power_mgmt/blinky/README.rst index 4687b07326ef9d6..1f75e2bddbcd000 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 000000000000000..f6f5d399148372f --- /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_f429zi.conf b/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_f429zi.conf new file mode 100644 index 000000000000000..2035eb8c9557df9 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_f429zi.conf @@ -0,0 +1,2 @@ +# Increase IDLE stack for the IDLE timer +CONFIG_IDLE_STACK_SIZE=640 diff --git a/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_f429zi.overlay b/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_f429zi.overlay new file mode 100644 index 000000000000000..859c69df4140e4b --- /dev/null +++ b/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_f429zi.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,cortex-m-idle-timer = &rtc; + }; +}; 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 66bca43ae2f2311..11767aa004b91a0 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 9ac206bd0f3efb6..fa60e82b4f0a479 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/blinky/sample.yaml b/samples/boards/stm32/power_mgmt/blinky/sample.yaml index 103f204a189dce8..04054268228961f 100644 --- a/samples/boards/stm32/power_mgmt/blinky/sample.yaml +++ b/samples/boards/stm32/power_mgmt/blinky/sample.yaml @@ -12,7 +12,9 @@ tests: - "Device ready" filter: dt_compat_enabled("zephyr,power-state") and dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and - dt_compat_enabled("st,stm32-lptim") + (dt_compat_enabled("st,stm32-lptim") or + dt_chosen_enabled("zephyr,cortex-m-idle-timer")) extra_args: "CONFIG_DEBUG=y" integration_platforms: - nucleo_wb55rg + - nucleo_f429zi 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 000000000000000..cce711c785c4454 --- /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 f924e6fdea5f4d1..bcbed7c5824b136 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 83c607ff8a05283..8b6b062cd67f54a 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 3e1a61bf9db99df..ca1e6cf73a9df25 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 42528be505d0245..e0f61361500c587 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 74284abf41b6964..35846c04411686e 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/stm32wb_ble/prj.conf b/samples/boards/stm32/power_mgmt/stm32wb_ble/prj.conf index 583df4e6ee70f44..1dff53f1da7218f 100644 --- a/samples/boards/stm32/power_mgmt/stm32wb_ble/prj.conf +++ b/samples/boards/stm32/power_mgmt/stm32wb_ble/prj.conf @@ -1,5 +1,4 @@ CONFIG_BT=y CONFIG_BT_DEVICE_NAME="Test beacon" CONFIG_POWEROFF=y - -#CONFIG_DEBUG=y +CONFIG_PM=y diff --git a/samples/boards/stm32/power_mgmt/stm32wb_ble/sample.yaml b/samples/boards/stm32/power_mgmt/stm32wb_ble/sample.yaml index 3c00f4ef8567421..0e8e975d19a3371 100644 --- a/samples/boards/stm32/power_mgmt/stm32wb_ble/sample.yaml +++ b/samples/boards/stm32/power_mgmt/stm32wb_ble/sample.yaml @@ -7,3 +7,4 @@ tests: tags: - bluetooth - pm + extra_args: "CONFIG_DEBUG=y" 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 000000000000000..8e813b2d1756024 --- /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 000000000000000..246ac96ea103251 --- /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 000000000000000..3ed3dab7a886deb --- /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 000000000000000..acef64bb9a81300 --- /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 000000000000000..f7eb4383664c07e --- /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 000000000000000..bb1ca9dbb55bd2f --- /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/CMakeLists.txt b/samples/charger/CMakeLists.txt new file mode 100644 index 000000000000000..e0f9e77b374106a --- /dev/null +++ b/samples/charger/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(charger) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/charger/prj.conf b/samples/charger/prj.conf new file mode 100644 index 000000000000000..922c6f65a093d7a --- /dev/null +++ b/samples/charger/prj.conf @@ -0,0 +1 @@ +CONFIG_CHARGER=y diff --git a/samples/charger/sample.yaml b/samples/charger/sample.yaml new file mode 100644 index 000000000000000..18ab714b99cd33e --- /dev/null +++ b/samples/charger/sample.yaml @@ -0,0 +1,6 @@ +sample: + name: Generic charger +tests: + sample.drivers.charger: + tags: charger + depends_on: charger diff --git a/samples/charger/src/main.c b/samples/charger/src/main.c new file mode 100644 index 000000000000000..91961fe15b11b94 --- /dev/null +++ b/samples/charger/src/main.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2023 Cirrus Logic, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "zephyr/sys/printk.h" +#include +#include +#include +#include +#include + +static const struct device *chgdev = DEVICE_DT_GET(DT_NODELABEL(charger)); + +int main(void) +{ + union charger_propval val; + int ret; + + if (chgdev == NULL) { + printk("Error: no charger device found.\n"); + return 0; + } + + if (!device_is_ready(chgdev)) { + printk("Error: Device \"%s\" is not ready; " + "check the driver initialization logs for errors.\n", + chgdev->name); + return 0; + } + + printk("Found device \"%s\", getting charger data\n", chgdev->name); + + while (1) { + /* Poll until external power is presented to the charger */ + do { + ret = charger_get_prop(chgdev, CHARGER_PROP_ONLINE, &val); + if (ret < 0) { + return ret; + } + + k_msleep(100); + } while (val.online == CHARGER_ONLINE_OFFLINE); + + val.status = CHARGER_STATUS_CHARGING; + + ret = charger_charge_enable(chgdev, true); + if (ret == -ENOTSUP) { + printk("Enabling charge not supported, assuming auto charge enable\n"); + continue; + } else if (ret < 0) { + return ret; + } + + k_msleep(500); + + ret = charger_get_prop(chgdev, CHARGER_PROP_STATUS, &val); + if (ret < 0) { + return ret; + } + + switch (val.status) { + case CHARGER_STATUS_CHARGING: + printk("Charging in progress...\n"); + + ret = charger_get_prop(chgdev, CHARGER_PROP_CHARGE_TYPE, &val); + if (ret < 0) { + return ret; + } + + printk("Device \"%s\" charge type is %d\n", chgdev->name, val.charge_type); + break; + case CHARGER_STATUS_NOT_CHARGING: + printk("Charging halted...\n"); + + ret = charger_get_prop(chgdev, CHARGER_PROP_HEALTH, &val); + if (ret < 0) { + return ret; + } + + printk("Device \"%s\" health is %d\n", chgdev->name, val.health); + break; + case CHARGER_STATUS_FULL: + printk("Charging complete!"); + return 0; + case CHARGER_STATUS_DISCHARGING: + printk("External power removed, discharging\n"); + + ret = charger_get_prop(chgdev, CHARGER_PROP_ONLINE, &val); + if (ret < 0) { + return ret; + } + break; + default: + return -EIO; + } + + k_msleep(500); + } +} diff --git a/samples/compression/lz4/prj.conf b/samples/compression/lz4/prj.conf index 34e20dad07d4f5e..d4f2049eb89b8f2 100644 --- a/samples/compression/lz4/prj.conf +++ b/samples/compression/lz4/prj.conf @@ -1,3 +1,4 @@ CONFIG_LZ4=y -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y CONFIG_HEAP_MEM_POOL_SIZE=16384 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=24576 diff --git a/samples/compression/lz4/sample.yaml b/samples/compression/lz4/sample.yaml index 733646979d533cb..f9758f26984affc 100644 --- a/samples/compression/lz4/sample.yaml +++ b/samples/compression/lz4/sample.yaml @@ -6,7 +6,7 @@ common: - compression - lz4 min_ram: 64 - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED harness: console harness_config: type: one_line diff --git a/samples/cpp/hello_world/CMakeLists.txt b/samples/cpp/hello_world/CMakeLists.txt new file mode 100644 index 000000000000000..da4e1f7da41be71 --- /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 000000000000000..cfc2541ff397b00 --- /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 000000000000000..b801dee18552074 --- /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 000000000000000..244c7b4f3453c6c --- /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 000000000000000..369e35735269e05 --- /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/adc/boards/longan_nano.overlay b/samples/drivers/adc/boards/longan_nano.overlay new file mode 100644 index 000000000000000..390534e74ff399b --- /dev/null +++ b/samples/drivers/adc/boards/longan_nano.overlay @@ -0,0 +1,23 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc0 0>; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/drivers/adc/boards/longan_nano_lite.overlay b/samples/drivers/adc/boards/longan_nano_lite.overlay new file mode 100644 index 000000000000000..390534e74ff399b --- /dev/null +++ b/samples/drivers/adc/boards/longan_nano_lite.overlay @@ -0,0 +1,23 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc0 0>; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/drivers/adc/sample.yaml b/samples/drivers/adc/sample.yaml index 46b88fa6040579b..2ed1681a0e0c004 100644 --- a/samples/drivers/adc/sample.yaml +++ b/samples/drivers/adc/sample.yaml @@ -2,7 +2,8 @@ sample: name: ADC driver sample tests: sample.drivers.adc: - tags: ADC + tags: + - adc depends_on: adc platform_allow: - nucleo_l073rz @@ -26,6 +27,8 @@ tests: - gd32l233r_eval - lpcxpresso55s36 - mr_canhubk3 + - longan_nano + - longan_nano_lite integration_platforms: - nucleo_l073rz - nrf52840dk_nrf52840 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 000000000000000..ce71fa65f019a4c --- /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/babbling/Kconfig b/samples/drivers/can/babbling/Kconfig index c98047657a0b86b..0d28308152715a2 100644 --- a/samples/drivers/can/babbling/Kconfig +++ b/samples/drivers/can/babbling/Kconfig @@ -22,10 +22,10 @@ config SAMPLE_CAN_BABBLING_RTR Babbling node sends Remote Transmission Request (RTR) frames. config SAMPLE_CAN_BABBLING_FD_MODE - bool "Send CAN-FD format frames" + bool "Send CAN FD format frames" select CAN_FD_MODE help - Babbling node sends CAN-FD format frames. + Babbling node sends CAN FD format frames. config SAMPLE_CAN_BABBLING_TX_QUEUE_SIZE int "Maximum number of CAN frames to enqueue" diff --git a/samples/drivers/can/babbling/README.rst b/samples/drivers/can/babbling/README.rst index e80e03c84492482..f13c80af8227f2a 100644 --- a/samples/drivers/can/babbling/README.rst +++ b/samples/drivers/can/babbling/README.rst @@ -47,5 +47,5 @@ Sample output .. code-block:: console *** Booting Zephyr OS build zephyr-v3.1.0-4606-g8c1efa8b96bb *** - babbling on can@40024000 with standard (11-bit) CAN ID 0x010, RTR 0, CAN-FD 0 + babbling on can@40024000 with standard (11-bit) CAN ID 0x010, RTR 0, CAN FD 0 abort by pressing User SW3 button diff --git a/samples/drivers/can/babbling/sample.yaml b/samples/drivers/can/babbling/sample.yaml index 8a52e4f59cbe1a2..2e7a8320dae254b 100644 --- a/samples/drivers/can/babbling/sample.yaml +++ b/samples/drivers/can/babbling/sample.yaml @@ -6,7 +6,7 @@ tests: depends_on: can filter: dt_chosen_enabled("zephyr,canbus") integration_platforms: - - native_posix + - native_sim harness: console harness_config: type: one_line diff --git a/samples/drivers/can/babbling/src/main.c b/samples/drivers/can/babbling/src/main.c index d43623bd878b83a..ada6852ae8f7379 100644 --- a/samples/drivers/can/babbling/src/main.c +++ b/samples/drivers/can/babbling/src/main.c @@ -60,7 +60,7 @@ int main(void) if (IS_ENABLED(CONFIG_SAMPLE_CAN_BABBLING_FD_MODE)) { err = can_set_mode(dev, CAN_MODE_FD); if (err != 0) { - printk("Error setting CAN-FD mode (err %d)", err); + printk("Error setting CAN FD mode (err %d)", err); return 0; } } @@ -109,7 +109,7 @@ int main(void) frame.id = CONFIG_SAMPLE_CAN_BABBLING_CAN_ID; - printk("babbling on %s with %s (%d-bit) CAN ID 0x%0*x, RTR %d, CAN-FD %d\n", + printk("babbling on %s with %s (%d-bit) CAN ID 0x%0*x, RTR %d, CAN FD %d\n", dev->name, (frame.flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard", (frame.flags & CAN_FRAME_IDE) != 0 ? 29 : 11, diff --git a/samples/drivers/can/counter/sample.yaml b/samples/drivers/can/counter/sample.yaml index 20f609d0c367c4a..edbb0817c4dc999 100644 --- a/samples/drivers/can/counter/sample.yaml +++ b/samples/drivers/can/counter/sample.yaml @@ -5,8 +5,9 @@ tests: tags: can depends_on: can integration_platforms: - - native_posix + - 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 78048308ca25c0c..2119069e43eff5c 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/clock_control_litex/sample.yaml b/samples/drivers/clock_control_litex/sample.yaml index 5c9ae55424f34e8..cf5618313c53d69 100644 --- a/samples/drivers/clock_control_litex/sample.yaml +++ b/samples/drivers/clock_control_litex/sample.yaml @@ -4,7 +4,5 @@ tests: sample.driver.clock_control_litex: platform_allow: litex_vexriscv tags: - - clock - - litex - - vexriscv + - clock_control - mmcm diff --git a/samples/drivers/counter/alarm/CMakeLists.txt b/samples/drivers/counter/alarm/CMakeLists.txt index eadc9e99e67d20e..747c2b27ebd6e6b 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/counter/maxim_ds3231/prj.conf b/samples/drivers/counter/maxim_ds3231/prj.conf index e858ebb2441b895..26421607393d49d 100644 --- a/samples/drivers/counter/maxim_ds3231/prj.conf +++ b/samples/drivers/counter/maxim_ds3231/prj.conf @@ -6,7 +6,7 @@ CONFIG_COUNTER_MAXIM_DS3231=y CONFIG_COUNTER_INIT_PRIORITY=65 # Minimal libc doesn't have strftime() -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y # Optional step that syncs RTC and local clock. Don't enable this if # your RTC has already been synchronized and you want to keep its diff --git a/samples/drivers/counter/maxim_ds3231/sample.yaml b/samples/drivers/counter/maxim_ds3231/sample.yaml index 6e244d62da09562..4e9c209047c95b9 100644 --- a/samples/drivers/counter/maxim_ds3231/sample.yaml +++ b/samples/drivers/counter/maxim_ds3231/sample.yaml @@ -1,5 +1,5 @@ common: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED sample: name: Maxim DS3231 RTC tests: diff --git a/samples/drivers/counter/maxim_ds3231/src/main.c b/samples/drivers/counter/maxim_ds3231/src/main.c index 32c37c17188bc65..992283ef3439c5e 100644 --- a/samples/drivers/counter/maxim_ds3231/src/main.c +++ b/samples/drivers/counter/maxim_ds3231/src/main.c @@ -105,7 +105,7 @@ static void min_alarm_handler(const struct device *dev, (void)counter_get_value(dev, &time); uint32_t uptime = k_uptime_get_32(); - uint8_t us = uptime % 1000U; + uint16_t ms = uptime % 1000U; uptime /= 1000U; uint8_t se = uptime % 60U; @@ -143,7 +143,7 @@ static void min_alarm_handler(const struct device *dev, printk("%s: adj %d.%09lu, uptime %u:%02u:%02u.%03u, clk err %d ppm\n", format_time(time, -1), (uint32_t)(ts->tv_sec - time), ts->tv_nsec, - hr, mn, se, us, err_ppm); + hr, mn, se, ms, err_ppm); } struct maxim_ds3231_alarm sec_alarm; diff --git a/samples/drivers/crypto/sample.yaml b/samples/drivers/crypto/sample.yaml index d63e7a4a68ab83e..c969bafa67ce3df 100644 --- a/samples/drivers/crypto/sample.yaml +++ b/samples/drivers/crypto/sample.yaml @@ -12,7 +12,7 @@ tests: harness: console extra_args: EXTRA_CONF_FILE=prj_tinycrypt_shim.conf integration_platforms: - - native_posix + - native_sim harness_config: type: multi_line regex: @@ -26,7 +26,7 @@ tests: harness: console extra_args: EXTRA_CONF_FILE=prj_mtls_shim.conf integration_platforms: - - native_posix + - native_sim harness_config: type: multi_line regex: diff --git a/samples/drivers/display/README.rst b/samples/drivers/display/README.rst index 02ec21f3eda1029..872a0b5f5d22243 100644 --- a/samples/drivers/display/README.rst +++ b/samples/drivers/display/README.rst @@ -30,12 +30,12 @@ Below is an example on how to build for a :ref:`nrf52840dk_nrf52840` board with :shield: adafruit_2_8_tft_touch_v2 :compact: -For testing purpose without the need of any hardware, the :ref:`native_posix` +For testing purpose without the need of any hardware, the :ref:`native_sim ` board is also supported and can be built as follows; .. zephyr-app-commands:: :zephyr-app: samples/drivers/display - :board: native_posix + :board: native_sim :goals: build :compact: diff --git a/samples/drivers/display/sample.yaml b/samples/drivers/display/sample.yaml index f2cc9d0a89d489d..579773f3c8c8ede 100644 --- a/samples/drivers/display/sample.yaml +++ b/samples/drivers/display/sample.yaml @@ -103,10 +103,14 @@ tests: fixture: fixture_display sample.display.sdl: build_only: true - platform_allow: native_posix_64 + platform_allow: + - native_posix_64 + - native_sim_64 tags: display sample.display.dummy: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim extra_args: DTC_OVERLAY_FILE="dummy_dc.overlay" extra_configs: - CONFIG_DUMMY_DISPLAY=y @@ -131,3 +135,22 @@ tests: harness: console harness_config: fixture: fixture_display + sample.display.g1120b0mipi: + platform_allow: mimxrt595_evk_cm33 + tags: display + harness: console + extra_args: SHIELD=g1120b0mipi + extra_configs: + - CONFIG_PM=y + - CONFIG_PM_DEVICE=y + - 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 5e74e7a018d3c1a..a9267b51c747c72 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/eeprom/README.rst b/samples/drivers/eeprom/README.rst index 25007274a05a503..079a3ebb469b8c5 100644 --- a/samples/drivers/eeprom/README.rst +++ b/samples/drivers/eeprom/README.rst @@ -15,12 +15,12 @@ Building and Running In case the target board has defined an EEPROM with alias ``eeprom-0`` the sample can be built without further ado. This applies for example to the -:ref:`native_posix` board: +:ref:`native_sim` board: .. zephyr-app-commands:: :zephyr-app: samples/drivers/eeprom :host-os: unix - :board: native_posix + :board: native_sim :goals: run :compact: diff --git a/samples/drivers/eeprom/sample.yaml b/samples/drivers/eeprom/sample.yaml index b971faf9ba53df3..c9dfa7dd071a160 100644 --- a/samples/drivers/eeprom/sample.yaml +++ b/samples/drivers/eeprom/sample.yaml @@ -8,8 +8,10 @@ tests: - gd32f450i_eval - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix_64 + - native_sim_64 harness: console harness_config: type: one_line 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 71f0a86d75a98c4..ce6cb08c32268eb 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/flash_shell/Kconfig b/samples/drivers/flash_shell/Kconfig deleted file mode 100644 index aa7016fa9ae1079..000000000000000 --- a/samples/drivers/flash_shell/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2020, Linaro Ltd. -# SPDX-License-Identifier: Apache-2.0 - -source "Kconfig.zephyr" - -if ARM_MPU -config MPU_ALLOW_FLASH_WRITE - def_bool y -endif diff --git a/samples/drivers/flash_shell/README.rst b/samples/drivers/flash_shell/README.rst index 1c8513bf2c09788..f6e1b78a38ce65b 100644 --- a/samples/drivers/flash_shell/README.rst +++ b/samples/drivers/flash_shell/README.rst @@ -27,19 +27,24 @@ Sample Output .. code-block:: console - uart:~$ flash_sample page_count - Flash device contains 1024 pages. - uart:~$ flash_sample page_erase 1023 - Erasing page 1023 (start offset 0xffc00, size 0x400) - uart:~$ flash_sample page_write 1023 8 17 19 28 39 - Reading back written bytes: - 11 13 1c 27 - uart:~$ flash_sample page_write 1023 4 77 9 1 2 - Reading back written bytes: - 4d 09 01 02 - uart:~$ flash_sample page_read 1023 4 12 - 4d 09 01 02 | 11 13 1c 27 - ff ff ff ff - uart:~$ flash_sample page_read 1023 0 16 - ff ff ff ff | 4d 09 01 02 - 11 13 1c 27 | ff ff ff ff + uart:~$ flash page_info 0 + Page for address 0x0: + start offset: 0x0 + size: 4096 + index: 0 + uart:~$ flash erase 0x1000 + Erase success. + uart:~$ flash write 0x1000 0x12345678 0x9abcdef0 + Write OK. + Verified. + uart:~$ flash write 0x1000 0x11111111 + Write internal ERROR! + uart:~$ flash read 0x1000 0x10 + 00001000: 78 56 34 12 f0 de bc 9a ff ff ff ff ff ff ff ff |xV4..... ........| + + uart:~$ flash write 0x101c 0xabcd1234 + Write OK. + Verified. + uart:~$ flash read 0x1000 0x20 + 00001000: 78 56 34 12 f0 de bc 9a ff ff ff ff ff ff ff ff |xV4..... ........| + 00001010: ff ff ff ff ff ff ff ff ff ff ff ff 34 12 cd ab |........ ....4...| diff --git a/samples/drivers/flash_shell/prj.conf b/samples/drivers/flash_shell/prj.conf index 4e60a63bd0ae24b..657776e96ce1f76 100644 --- a/samples/drivers/flash_shell/prj.conf +++ b/samples/drivers/flash_shell/prj.conf @@ -2,8 +2,5 @@ CONFIG_PRINTK=y CONFIG_SHELL=y CONFIG_LOG=y CONFIG_FLASH=y -# Your flash driver may not enable this, even if it's supported. -# If that's the case and you're interested in the flash layout, enable -# it here. -# CONFIG_FLASH_PAGE_LAYOUT=y -CONFIG_HEAP_MEM_POOL_SIZE=16384 +CONFIG_FLASH_SHELL=y +CONFIG_FLASH_SHELL_TEST_COMMANDS=y diff --git a/samples/drivers/flash_shell/src/main.c b/samples/drivers/flash_shell/src/main.c index e7e1b2d3b4bbfff..2de337414d50a75 100644 --- a/samples/drivers/flash_shell/src/main.c +++ b/samples/drivers/flash_shell/src/main.c @@ -3,767 +3,12 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -LOG_MODULE_REGISTER(app); - -#define PR_SHELL(sh, fmt, ...) \ - shell_fprintf(sh, SHELL_NORMAL, fmt, ##__VA_ARGS__) -#define PR_ERROR(sh, fmt, ...) \ - shell_fprintf(sh, SHELL_ERROR, fmt, ##__VA_ARGS__) -#define PR_INFO(sh, fmt, ...) \ - shell_fprintf(sh, SHELL_INFO, fmt, ##__VA_ARGS__) -#define PR_WARNING(sh, fmt, ...) \ - shell_fprintf(sh, SHELL_WARNING, fmt, ##__VA_ARGS__) - -/* Command usage info. */ -#define WRITE_BLOCK_SIZE_HELP \ - ("Print the device's write block size. This is the smallest amount" \ - " of data which may be written to the device, in bytes.") -#define READ_HELP \ - (" \n" \ - "Read bytes from device offset .") -#define ERASE_HELP \ - (" \n\n" \ - "Erase bytes from device offset , " \ - "subject to hardware page limitations.") -#define WRITE_HELP \ - (" [... byteN]\n\n" \ - "Write given bytes, starting at device offset .\n" \ - "Pages must be erased before they can be written.") -#define WRITE_UNALIGNED_HELP \ - (" [... byteN]\n\n" \ - "Write given bytes, starting at device offset .\n" \ - "Being unaligned, affected memory areas are backed up, erased, protected" \ - " and then overwritten.\n" \ - "This command is designed to test writing to large flash pages.") -#define WRITE_PATTERN_HELP \ - (" \n\n" \ - "Writes a pattern of (0x00 0x01 .. 0xFF 0x00 ..) of length" \ - " at the offset .\n" \ - "Unaligned writing is used, i.e. protection and erasing are automated." \ - "This command is designed to test writing to large flash pages.") -#ifdef CONFIG_FLASH_PAGE_LAYOUT -#define PAGE_COUNT_HELP \ - "\n\nPrint the number of pages on the flash device." -#define PAGE_LAYOUT_HELP \ - ("[start_page] [end_page]\n\n" \ - "Print layout of flash pages in the range [start_page, end_page]," \ - " which is inclusive. By default, all pages are printed.") -#define PAGE_READ_HELP \ - (" OR \n\n" \ - "Read bytes from given page, starting at page offset ," \ - "or offset 0 if not given. No checks are made that bytes read are" \ - " all within the page.") -#define PAGE_ERASE_HELP \ - (" [num]\n\n" \ - "Erase [num] pages (default 1), starting at page .") -#define PAGE_WRITE_HELP \ - (" [... byteN]\n\n" \ - "Write given bytes to given page, starting at page offset ." \ - " No checks are made that the bytes all fall within the page." \ - " Pages must be erased before they can be written.") -#endif -#define SET_DEV_HELP \ - ("\n\n" \ - "Set flash device by name. If a flash device was not found," \ - " this command must be run first to bind a device to this module.") - -#if (CONFIG_SHELL_ARGC_MAX > 4) -#define ARGC_MAX (CONFIG_SHELL_ARGC_MAX - 4) -#else -#error Please increase CONFIG_SHELL_ARGC_MAX parameter. -#endif - -static const struct device *flash_device = - DEVICE_DT_GET_OR_NULL(DT_CHOSEN(zephyr_flash_controller)); - -static int check_flash_device(const struct shell *sh) -{ - if (flash_device == NULL) { - PR_ERROR(sh, "Flash device is unknown." - " Run set_device first.\n"); - return -ENODEV; - } - return 0; -} - -static int dump_buffer(const struct shell *sh, uint8_t *buf, size_t size, - uint8_t *cmp_buf) -{ - int ret = 0; - size_t i; - - for (i = 0; i < size; i++) { - /* Print each byte mismatch as error */ - if (cmp_buf != NULL && buf[i] != cmp_buf[i]) { - PR_ERROR(sh, "%02x ", buf[i]); - ret = -EIO; - } else { - PR_SHELL(sh, "%02x ", buf[i]); - } - - if ((i + 1) % 16 == 0) { - PR_SHELL(sh, "\n"); - } else if ((i + 1) % 4 == 0) { - PR_SHELL(sh, "| "); - } - } - - if (i % 16 != 0) { - PR_SHELL(sh, "\n"); - } - - return ret; -} - -static int parse_ul(const char *str, unsigned long *result) -{ - char *end; - unsigned long val; - - val = strtoul(str, &end, 0); - - if (*str == '\0' || *end != '\0') { - return -EINVAL; - } - - *result = val; - return 0; -} - -static int parse_u8(const char *str, uint8_t *result) -{ - unsigned long val; - - if (parse_ul(str, &val) || val > 0xff) { - return -EINVAL; - } - *result = (uint8_t)val; - return 0; -} - -/* Read bytes, dumping contents to console and printing on error. */ -static int do_read(const struct shell *sh, off_t offset, size_t len, - uint8_t *cmp_buf) -{ - uint8_t buf[64]; - int ret; - size_t read_len; - bool cmp_error = false; - - do { - read_len = len > sizeof(buf) ? sizeof(buf) : len; - ret = flash_read(flash_device, offset, buf, read_len); - if (ret != 0) { - PR_ERROR(sh, "flash_read error: %d\n", ret); - return ret; - } - ret = dump_buffer(sh, buf, read_len, cmp_buf); - if (ret == -EIO) { - cmp_error = true; - } - if (cmp_buf != NULL) { - cmp_buf += read_len; - } - len -= read_len; - offset += read_len; - } while (len > 0); - - if (cmp_error) { - PR_ERROR(sh, "Write verification error, unexpected values " - "marked red\n"); - } - - return 0; -} - -/* Erase area and printing on error. */ -static int do_erase(const struct shell *sh, off_t offset, size_t size) -{ - int ret; - - ret = flash_erase(flash_device, offset, size); - if (ret) { - PR_ERROR(sh, "flash_erase failed (err:%d).\n", ret); - return ret; - } - - return ret; -} - -/* Write bytes and printing on error. */ -static int do_write(const struct shell *sh, off_t offset, uint8_t *buf, - size_t len, bool read_back) -{ - int ret; - - ret = flash_write(flash_device, offset, buf, len); - if (ret) { - PR_ERROR(sh, "flash_write failed (err:%d).\n", ret); - return ret; - } - - if (read_back) { - PR_SHELL(sh, "Reading back written bytes:\n"); - ret = do_read(sh, offset, len, buf); - } - return ret; -} - -static int do_write_unaligned(const struct shell *sh, off_t offset, uint8_t *buf, - size_t len, bool read_back) -{ - int ret = 0; - size_t page_size = flash_get_write_block_size(flash_device); - size_t size_before = offset % page_size; - size_t size_after = page_size - ((size_before + len) % page_size); - size_t aligned_size = size_before + len + size_after; - off_t start_page = offset - size_before; - off_t last_page = start_page + aligned_size - page_size; - bool single_page_write = (size_before + len < page_size); - - char *before_data; - char *after_data; - - if (0 == size_before && 0 == size_after) { - /* Aligned write */ - flash_erase(flash_device, offset, len); - flash_write(flash_device, offset, buf, len); - - return 0; - } - - before_data = k_malloc(page_size); - after_data = k_malloc(page_size); - - if (!before_data || !after_data) { - PR_ERROR(sh, "No heap memory for flash manipulation\n"); - ret = -ENOMEM; - goto free_buffers; - } - - /* Stash useful data from the pages that will be affected. */ - if (single_page_write) { - /* Read old data before new data is written. */ - if (size_before) { - flash_read(flash_device, start_page, before_data, size_before); - } - /* Fill the with new data. */ - memcpy(before_data + size_before, buf, len); - /* Fill the last part of old data. */ - if (size_after) { - flash_read(flash_device, offset + len, - before_data + size_before + len, - size_after); - } - } else { - /* Multipage write, different start and end pages. */ - if (size_before) { - flash_read(flash_device, start_page, before_data, - size_before); - /* Fill the rest with new data. */ - memcpy(before_data + size_before, buf, - page_size - size_before); - } - if (size_after) { - /* Copy ending part of new data. */ - memcpy((void *)after_data, - (void *)(buf + len - - ((len + size_before) % page_size)), - page_size - size_after); - /* Copy ending part of flash page. */ - flash_read(flash_device, offset + len, - after_data + (page_size - size_after), - size_after); - } - } - - /* Erase all the pages that overlap with new data. */ - flash_erase(flash_device, start_page, aligned_size); - - /* Write stashed and new data. */ - if (single_page_write || size_before > 0) { - /* Write first page if available. */ - flash_write(flash_device, start_page, before_data, - page_size); - } - if (!single_page_write) { - size_t middle_data_len = aligned_size; - off_t middle_page_start = start_page; - off_t data_offset = (off_t)buf; - - /* Write the middle bit if available */ - if (size_before > 0) { - middle_page_start += page_size; - middle_data_len -= page_size; - data_offset += (page_size - size_before); - } - if (size_after > 0) { - middle_data_len -= page_size; - } - if (middle_data_len > 0) { - flash_write(flash_device, middle_page_start, - (const void *)data_offset, - middle_data_len); - } - - /* Write the last page if needed. */ - if (size_after > 0) { - flash_write(flash_device, last_page, after_data, - page_size); - } - } - - if (read_back) { - PR_SHELL(sh, "Reading back written bytes:\n"); - ret = do_read(sh, offset, len, buf); - } - -free_buffers: - k_free(before_data); - k_free(after_data); - - return ret; -} - -static int cmd_write_block_size(const struct shell *sh, size_t argc, - char **argv) -{ - ARG_UNUSED(argc); - ARG_UNUSED(argv); - - int err = check_flash_device(sh); - - if (!err) { - PR_SHELL(sh, "%zu\n", - flash_get_write_block_size(flash_device)); - } - - return err; -} - -static int cmd_read(const struct shell *sh, size_t argc, char **argv) -{ - int err = check_flash_device(sh); - unsigned long int offset, len; - - if (err) { - goto exit; - } - - if (parse_ul(argv[1], &offset) || parse_ul(argv[2], &len)) { - PR_ERROR(sh, "Invalid arguments.\n"); - err = -EINVAL; - goto exit; - } - - err = do_read(sh, offset, len, NULL); - -exit: - return err; -} - -static int cmd_erase(const struct shell *sh, size_t argc, char **argv) -{ - int err = check_flash_device(sh); - unsigned long int offset; - unsigned long int size; - - if (err) { - goto exit; - } - - if (parse_ul(argv[1], &offset) || parse_ul(argv[2], &size)) { - PR_ERROR(sh, "Invalid arguments.\n"); - err = -EINVAL; - goto exit; - } - - err = do_erase(sh, (off_t)offset, (size_t)size); -exit: - return err; -} - -static int cmd_write_template(const struct shell *sh, size_t argc, char **argv, bool unaligned) -{ - unsigned long int i, offset; - uint8_t buf[ARGC_MAX]; - - int err = check_flash_device(sh); - - if (err) { - goto exit; - } - - err = parse_ul(argv[1], &offset); - if (err) { - PR_ERROR(sh, "Invalid argument.\n"); - goto exit; - } - - if ((argc - 2) > ARGC_MAX) { - /* Can only happen if Zephyr limit is increased. */ - PR_ERROR(sh, "At most %lu bytes can be written.\n" - "In order to write more bytes please increase" - " parameter: CONFIG_SHELL_ARGC_MAX.\n", - (unsigned long)ARGC_MAX); - err = -EINVAL; - goto exit; - } - - /* skip cmd name and offset */ - argc -= 2; - argv += 2; - for (i = 0; i < argc; i++) { - if (parse_u8(argv[i], &buf[i])) { - PR_ERROR(sh, "Argument %lu (%s) is not a byte.\n" - "Bytes shall be passed in decimal" - " notation.\n", - i + 1, argv[i]); - err = -EINVAL; - goto exit; - } - } - - if (!unaligned) { - err = do_write(sh, offset, buf, i, true); - } else { - err = do_write_unaligned(sh, offset, buf, i, true); - } - -exit: - return err; -} - -static int cmd_write(const struct shell *sh, size_t argc, char **argv) -{ - return cmd_write_template(sh, argc, argv, false); -} - -static int cmd_write_unaligned(const struct shell *sh, size_t argc, char **argv) -{ - return cmd_write_template(sh, argc, argv, true); -} - -static int cmd_write_pattern(const struct shell *sh, size_t argc, char **argv) -{ - int err = check_flash_device(sh); - unsigned long int offset, len, i; - static uint8_t *buf; - - if (err) { - goto exit; - } - - if (parse_ul(argv[1], &offset) || parse_ul(argv[2], &len)) { - PR_ERROR(sh, "Invalid arguments.\n"); - err = -EINVAL; - goto exit; - } - - buf = k_malloc(len); - - if (!buf) { - PR_ERROR(sh, "No heap memory for data pattern\n"); - err = -ENOMEM; - goto exit; - } - - for (i = 0; i < len; i++) { - buf[i] = i & 0xFF; - } - - err = do_write_unaligned(sh, offset, buf, i, true); - - k_free(buf); - -exit: - return err; -} - -#ifdef CONFIG_FLASH_PAGE_LAYOUT -static int cmd_page_count(const struct shell *sh, size_t argc, char **argv) -{ - ARG_UNUSED(argv); - ARG_UNUSED(argc); - - int err = check_flash_device(sh); - size_t page_count; - - if (!err) { - page_count = flash_get_page_count(flash_device); - PR_SHELL(sh, "Flash device contains %lu pages.\n", - (unsigned long int)page_count); - } - - return err; -} - -struct page_layout_data { - unsigned long int start_page; - unsigned long int end_page; - const struct shell *sh; -}; - -static bool page_layout_cb(const struct flash_pages_info *info, void *datav) -{ - struct page_layout_data *data = datav; - unsigned long int sz; - - if (info->index < data->start_page) { - return true; - } else if (info->index > data->end_page) { - return false; - } - - sz = info->size; - PR_SHELL(data->sh, - "\tPage %u: start 0x%08x, length 0x%lx (%lu, %lu KB)\n", - info->index, (uint32_t)info->start_offset, sz, sz, sz / KB(1)); - return true; -} - -static int cmd_page_layout(const struct shell *sh, size_t argc, char **argv) -{ - unsigned long int start_page, end_page; - struct page_layout_data data; - - int err = check_flash_device(sh); - - if (err) { - goto bail; - } - - switch (argc) { - case 1: - start_page = 0; - end_page = flash_get_page_count(flash_device) - 1; - break; - case 2: - if (parse_ul(argv[1], &start_page)) { - err = -EINVAL; - goto bail; - } - end_page = flash_get_page_count(flash_device) - 1; - break; - case 3: - if (parse_ul(argv[1], &start_page) || - parse_ul(argv[2], &end_page)) { - err = -EINVAL; - goto bail; - } - break; - default: - PR_ERROR(sh, "Invalid argument count.\n"); - return -EINVAL; - } - - data.start_page = start_page; - data.end_page = end_page; - data.sh = sh; - flash_page_foreach(flash_device, page_layout_cb, &data); - return 0; - -bail: - PR_ERROR(sh, "Invalid arguments.\n"); - return err; -} - -static int cmd_page_read(const struct shell *sh, size_t argc, char **argv) -{ - unsigned long int page, offset, len; - struct flash_pages_info info; - int ret; - - ret = check_flash_device(sh); - if (ret) { - return ret; - } - - if (argc == 3) { - if (parse_ul(argv[1], &page) || parse_ul(argv[2], &len)) { - ret = -EINVAL; - goto bail; - } - offset = 0; - } else if (parse_ul(argv[1], &page) || parse_ul(argv[2], &offset) || - parse_ul(argv[3], &len)) { - ret = -EINVAL; - goto bail; - } - - ret = flash_get_page_info_by_idx(flash_device, page, &info); - if (ret) { - PR_ERROR(sh, "Function flash_page_info_by_idx returned an" - " error: %d\n", ret); - return ret; - } - offset += info.start_offset; - ret = do_read(sh, offset, len, NULL); - return ret; - - bail: - PR_ERROR(sh, "Invalid arguments.\n"); - return ret; -} - -static int cmd_page_erase(const struct shell *sh, size_t argc, char **argv) -{ - struct flash_pages_info info; - unsigned long int i, page, num; - int ret; - - ret = check_flash_device(sh); - if (ret) { - return ret; - } - - if (parse_ul(argv[1], &page)) { - ret = -EINVAL; - goto bail; - } - if (argc == 2) { - num = 1; - } else if (parse_ul(argv[2], &num)) { - goto bail; - } - - for (i = 0; i < num; i++) { - ret = flash_get_page_info_by_idx(flash_device, page + i, &info); - if (ret) { - PR_ERROR(sh, "flash_get_page_info_by_idx error:" - " %d\n", ret); - return ret; - } - PR_SHELL(sh, "Erasing page %u (start offset 0x%x," - " size 0x%x)\n", - info.index, (uint32_t)info.start_offset, (uint32_t)info.size); - ret = do_erase(sh, info.start_offset, (uint32_t)info.size); - if (ret) { - return ret; - } - } - - return ret; - - bail: - PR_ERROR(sh, "Invalid arguments.\n"); - return ret; -} - -static int cmd_page_write(const struct shell *sh, size_t argc, char **argv) -{ - struct flash_pages_info info; - unsigned long int page, off; - uint8_t buf[ARGC_MAX]; - size_t i; - int ret; - - ret = check_flash_device(sh); - if (ret) { - return ret; - } - - if (parse_ul(argv[1], &page) || parse_ul(argv[2], &off)) { - ret = -EINVAL; - goto bail; - } - - argc -= 3; - argv += 3; - for (i = 0; i < argc; i++) { - if (parse_u8(argv[i], &buf[i])) { - PR_ERROR(sh, "Argument %d (%s) is not a byte.\n", - (int)i + 2, argv[i]); - ret = -EINVAL; - goto bail; - } - } - - ret = flash_get_page_info_by_idx(flash_device, page, &info); - if (ret) { - PR_ERROR(sh, "flash_get_page_info_by_idx: %d\n", ret); - return ret; - } - ret = do_write(sh, info.start_offset + off, buf, i, true); - return ret; - - bail: - PR_ERROR(sh, "Invalid arguments.\n"); - return ret; -} -#endif /* CONFIG_FLASH_PAGE_LAYOUT */ - -static int cmd_set_dev(const struct shell *sh, size_t argc, char **argv) -{ - const struct device *dev; - const char *name; - - name = argv[1]; - - /* Run command. */ - dev = device_get_binding(name); - if (!dev) { - PR_ERROR(sh, "No device named %s.\n", name); - return -ENOEXEC; - } - if (flash_device) { - PR_SHELL(sh, "Leaving behind device %s\n", - flash_device->name); - } - flash_device = dev; - - return 0; -} +#include int main(void) { - if (device_is_ready(flash_device)) { - printk("Found flash controller %s.\n", flash_device->name); - printk("Flash I/O commands can be run.\n"); - } else { - flash_device = NULL; - printk("**Flash controller not ready or not found!**\n"); - printk("Run set_device to specify one " - "before using other commands.\n"); - } + printf("Flash shell sample"); + return 0; } - - -SHELL_STATIC_SUBCMD_SET_CREATE(sub_flash, - /* Alphabetically sorted to ensure correct Tab autocompletion. */ - SHELL_CMD_ARG(erase, NULL, ERASE_HELP, cmd_erase, 3, 0), -#ifdef CONFIG_FLASH_PAGE_LAYOUT - SHELL_CMD_ARG(page_count, NULL, PAGE_COUNT_HELP, cmd_page_count, 1, 0), - SHELL_CMD_ARG(page_erase, NULL, PAGE_ERASE_HELP, cmd_page_erase, 2, 1), - SHELL_CMD_ARG(page_layout, NULL, PAGE_LAYOUT_HELP, - cmd_page_layout, 1, 2), - SHELL_CMD_ARG(page_read, NULL, PAGE_READ_HELP, cmd_page_read, 3, 1), - SHELL_CMD_ARG(page_write, NULL, PAGE_WRITE_HELP, - cmd_page_write, 3, 255), -#endif - SHELL_CMD_ARG(read, NULL, READ_HELP, cmd_read, 3, 0), - SHELL_CMD_ARG(set_device, NULL, SET_DEV_HELP, cmd_set_dev, 2, 0), - SHELL_CMD_ARG(write, NULL, WRITE_HELP, cmd_write, 3, 255), - SHELL_CMD_ARG(write_block_size, NULL, WRITE_BLOCK_SIZE_HELP, - cmd_write_block_size, 1, 0), - SHELL_CMD_ARG(write_unaligned, NULL, WRITE_UNALIGNED_HELP, - cmd_write_unaligned, 3, 255), - SHELL_CMD_ARG(write_pattern, NULL, WRITE_PATTERN_HELP, - cmd_write_pattern, 3, 255), - SHELL_SUBCMD_SET_END /* Array terminated. */ -); - -SHELL_CMD_REGISTER(flash_sample, &sub_flash, "Flash related commands.", NULL); diff --git a/samples/drivers/gnss/CMakeLists.txt b/samples/drivers/gnss/CMakeLists.txt new file mode 100644 index 000000000000000..929f1b4da27ae0b --- /dev/null +++ b/samples/drivers/gnss/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(gnss_sample) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/gnss/README.rst b/samples/drivers/gnss/README.rst new file mode 100644 index 000000000000000..8d4749cd410a4e3 --- /dev/null +++ b/samples/drivers/gnss/README.rst @@ -0,0 +1,29 @@ +.. zephyr:code-sample:: gnss + :name: GNSS + :relevant-api: gnss_interface navigation + + Connect to a GNSS device to obtain time, navigation data, and satellite information. + +Overview +******** +This sample demonstrates how to use a GNSS device implementing the +GNSS device driver API. + +Requirements +************ + +This sample requires a board with a GNSS device present and enabled +in the devicetree. + +Sample Output +************* + +.. code-block:: console + + gnss: gnss_info: {satellites_cnt: 14, hdop: 0.850, fix_status: GNSS_FIX, fix_quality: GNSS_SPS} + gnss: navigation_data: {latitude: 57.162331699, longitude : 9.961104199, bearing 12.530, speed 0.25, altitude: 42.372} + gnss: gnss_time: {hour: 16, minute: 17, millisecond 36000, month_day 3, month: 10, century_year: 23} + gnss has fix! + gnss: gnss_satellite: {prn: 1, snr: 30, elevation 71, azimuth 276, system: GLONASS, is_tracked: 1} + gnss: gnss_satellite: {prn: 11, snr: 31, elevation 62, azimuth 221, system: GLONASS, is_tracked: 1} + gnss reported 2 satellites! diff --git a/samples/drivers/gnss/prj.conf b/samples/drivers/gnss/prj.conf new file mode 100644 index 000000000000000..5ed72c140c2f86b --- /dev/null +++ b/samples/drivers/gnss/prj.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_GNSS=y +CONFIG_GNSS_SATELLITES=y +CONFIG_LOG=y +CONFIG_LOG_BUFFER_SIZE=8192 +CONFIG_GNSS_DUMP_TO_LOG=y +CONFIG_GNSS_LOG_LEVEL_DBG=y diff --git a/samples/drivers/gnss/sample.yaml b/samples/drivers/gnss/sample.yaml new file mode 100644 index 000000000000000..385a4ca0b6796d6 --- /dev/null +++ b/samples/drivers/gnss/sample.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +sample: + name: GNSS sample +tests: + sample.drivers.gnss: + tags: + - drivers + - gnss + filter: dt_alias_exists("gnss") + depends_on: gnss diff --git a/samples/drivers/gnss/src/main.c b/samples/drivers/gnss/src/main.c new file mode 100644 index 000000000000000..16b812f3f84b599 --- /dev/null +++ b/samples/drivers/gnss/src/main.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +static void gnss_data_cb(const struct device *dev, const struct gnss_data *data) +{ + if (data->info.fix_status != GNSS_FIX_STATUS_NO_FIX) { + printf("%s has fix!\r\n", dev->name); + } +} + +GNSS_DATA_CALLBACK_DEFINE(DEVICE_DT_GET(DT_ALIAS(gnss)), gnss_data_cb); + +#if CONFIG_GNSS_SATELLITES +static void gnss_satellites_cb(const struct device *dev, const struct gnss_satellite *satellites, + uint16_t size) +{ + printf("%s reported %u satellites!\r\n", dev->name, size); +} +#endif + +GNSS_SATELLITES_CALLBACK_DEFINE(DEVICE_DT_GET(DT_ALIAS(gnss)), gnss_satellites_cb); + +int main(void) +{ + return 0; +} diff --git a/samples/drivers/i2s/output/CMakeLists.txt b/samples/drivers/i2s/output/CMakeLists.txt new file mode 100644 index 000000000000000..100cc967f236654 --- /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 000000000000000..d8e10d81e0e1303 --- /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 000000000000000..c27a69285c6c923 --- /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 000000000000000..92ffdea0a37bdd2 --- /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 000000000000000..c1378264b967cb3 --- /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 000000000000000..8763b5128b23be6 --- /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 000000000000000..34f1629ceb3098d --- /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 458f0c9f2564088..8386967632472cc 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 000000000000000..0bef3d481fdde52 --- /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 000000000000000..0bef3d481fdde52 --- /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 000000000000000..a8ee714a955969b --- /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 0292180dbf32fcf..000000000000000 --- 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 82a82514edfb8e3..000000000000000 --- 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 000000000000000..44114da84509a53 --- /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 000000000000000..80f7950333f2b2b --- /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 000000000000000..80f7950333f2b2b --- /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 000000000000000..80f7950333f2b2b --- /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 000000000000000..05a3de09ec11c34 --- /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 dfabff594dfb67d..553edc1f28b894d 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/boards/b_l4s5i_iot01a.conf b/samples/drivers/jesd216/boards/b_l4s5i_iot01a.conf deleted file mode 100644 index 6e3cf258b125497..000000000000000 --- a/samples/drivers/jesd216/boards/b_l4s5i_iot01a.conf +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) 2022 STMicroelectronics -# -# SPDX-License-Identifier: Apache-2.0 - -CONFIG_FLASH_STM32_OSPI=y -CONFIG_SPI_NOR_SFDP_RUNTIME=y -CONFIG_SPI_NOR=n diff --git a/samples/drivers/jesd216/boards/b_u585i_iot02a.conf b/samples/drivers/jesd216/boards/b_u585i_iot02a.conf deleted file mode 100644 index 6e3cf258b125497..000000000000000 --- a/samples/drivers/jesd216/boards/b_u585i_iot02a.conf +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) 2022 STMicroelectronics -# -# SPDX-License-Identifier: Apache-2.0 - -CONFIG_FLASH_STM32_OSPI=y -CONFIG_SPI_NOR_SFDP_RUNTIME=y -CONFIG_SPI_NOR=n diff --git a/samples/drivers/jesd216/boards/disco_l475_iot1.conf b/samples/drivers/jesd216/boards/disco_l475_iot1.conf deleted file mode 100644 index dbb7255d188a7f7..000000000000000 --- a/samples/drivers/jesd216/boards/disco_l475_iot1.conf +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_FLASH_STM32_QSPI=y -CONFIG_SPI_NOR_SFDP_RUNTIME=y -CONFIG_SPI_NOR=n diff --git a/samples/drivers/jesd216/boards/stm32h573i_dk.conf b/samples/drivers/jesd216/boards/stm32h573i_dk.conf deleted file mode 100644 index 4dd3e9965c42443..000000000000000 --- a/samples/drivers/jesd216/boards/stm32h573i_dk.conf +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) 2023 STMicroelectronics -# -# SPDX-License-Identifier: Apache-2.0 - -CONFIG_FLASH_STM32_OSPI=y -CONFIG_SPI_NOR_SFDP_RUNTIME=y -CONFIG_SPI_NOR=n diff --git a/samples/drivers/jesd216/boards/stm32h735g_disco.conf b/samples/drivers/jesd216/boards/stm32h735g_disco.conf deleted file mode 100644 index 6e3cf258b125497..000000000000000 --- a/samples/drivers/jesd216/boards/stm32h735g_disco.conf +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) 2022 STMicroelectronics -# -# SPDX-License-Identifier: Apache-2.0 - -CONFIG_FLASH_STM32_OSPI=y -CONFIG_SPI_NOR_SFDP_RUNTIME=y -CONFIG_SPI_NOR=n diff --git a/samples/drivers/jesd216/boards/stm32h747i_disco_m7.conf b/samples/drivers/jesd216/boards/stm32h747i_disco_m7.conf deleted file mode 100644 index dbb7255d188a7f7..000000000000000 --- a/samples/drivers/jesd216/boards/stm32h747i_disco_m7.conf +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_FLASH_STM32_QSPI=y -CONFIG_SPI_NOR_SFDP_RUNTIME=y -CONFIG_SPI_NOR=n diff --git a/samples/drivers/jesd216/boards/stm32l496g_disco.conf b/samples/drivers/jesd216/boards/stm32l496g_disco.conf deleted file mode 100644 index dbb7255d188a7f7..000000000000000 --- a/samples/drivers/jesd216/boards/stm32l496g_disco.conf +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_FLASH_STM32_QSPI=y -CONFIG_SPI_NOR_SFDP_RUNTIME=y -CONFIG_SPI_NOR=n diff --git a/samples/drivers/jesd216/boards/stm32l562e_dk.conf b/samples/drivers/jesd216/boards/stm32l562e_dk.conf deleted file mode 100644 index 6e3cf258b125497..000000000000000 --- a/samples/drivers/jesd216/boards/stm32l562e_dk.conf +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) 2022 STMicroelectronics -# -# SPDX-License-Identifier: Apache-2.0 - -CONFIG_FLASH_STM32_OSPI=y -CONFIG_SPI_NOR_SFDP_RUNTIME=y -CONFIG_SPI_NOR=n diff --git a/samples/drivers/jesd216/sample.yaml b/samples/drivers/jesd216/sample.yaml index af84cbc791e80d5..c50ce41d0f3183a 100644 --- a/samples/drivers/jesd216/sample.yaml +++ b/samples/drivers/jesd216/sample.yaml @@ -28,3 +28,6 @@ tests: platform_allow: nrf52840dk_nrf52840 integration_platforms: - nrf52840dk_nrf52840 + sample.drivers.stm32.jesd216: + filter: dt_compat_enabled("st,stm32-ospi-nor") or dt_compat_enabled("st,stm32-qspi-nor") + depends_on: spi diff --git a/samples/drivers/kscan_touch/CMakeLists.txt b/samples/drivers/kscan_touch/CMakeLists.txt deleted file mode 100644 index 1c5812ccffb1de2..000000000000000 --- a/samples/drivers/kscan_touch/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(kscan) - -FILE(GLOB app_sources src/*.c) -target_sources(app PRIVATE ${app_sources}) diff --git a/samples/drivers/kscan_touch/README.rst b/samples/drivers/kscan_touch/README.rst deleted file mode 100644 index 52ad2aa7095d315..000000000000000 --- a/samples/drivers/kscan_touch/README.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. zephyr:code-sample:: kscan-touch - :name: KSCAN touch panel - :relevant-api: kscan_interface - - Use the KSCAN API to interface with a touch panel. - -Overview -******** - -This sample demonstrates how to interface with a touch panel. When touches are -detected a log message is output on the console. - -Building and Running -******************** - -The sample can be built and executed on boards with a touch panel for example -stm32f746g_disco or mimxrt1060_evk. The boards dts file should contain an alias -to kscan0 - -Sample output -============= - -.. code-block:: console - - KSCAN test for touch panels. - Note: You are expected to see several callbacks - as you touch the screen. diff --git a/samples/drivers/kscan_touch/prj.conf b/samples/drivers/kscan_touch/prj.conf deleted file mode 100644 index b25816644e92d1b..000000000000000 --- a/samples/drivers/kscan_touch/prj.conf +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_STDOUT_CONSOLE=y -CONFIG_PRINTK=y -CONFIG_KSCAN=y diff --git a/samples/drivers/kscan_touch/sample.yaml b/samples/drivers/kscan_touch/sample.yaml deleted file mode 100644 index b555e9f9901f33c..000000000000000 --- a/samples/drivers/kscan_touch/sample.yaml +++ /dev/null @@ -1,14 +0,0 @@ -sample: - name: KSCAN touch driver api sample -tests: - sample.drivers.kscan_touch: - tags: - - drivers - - kscan_touch - harness: console - harness_config: - type: multi_line - ordered: true - regex: - - "kb data(.*)" - depends_on: kscan:touch diff --git a/samples/drivers/kscan_touch/src/main.c b/samples/drivers/kscan_touch/src/main.c deleted file mode 100644 index cfec920f732d5f3..000000000000000 --- a/samples/drivers/kscan_touch/src/main.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2020 Mark Olsson - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include - -#define LOG_LEVEL LOG_LEVEL_DBG -#include - -LOG_MODULE_REGISTER(main); - -const struct device *const kscan_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_keyboard_scan)); - -static void k_callback(const struct device *dev, uint32_t row, uint32_t col, - bool pressed) -{ - ARG_UNUSED(dev); - if (pressed) { - printk("row = %u col = %u\n", row, col); - } -} - -int main(void) -{ - printk("Kscan touch panel sample application\n"); - - if (!device_is_ready(kscan_dev)) { - LOG_ERR("kscan device %s not ready", kscan_dev->name); - return 0; - } - - kscan_config(kscan_dev, k_callback); - kscan_enable_callback(kscan_dev); - return 0; -} diff --git a/samples/drivers/led_ws2812/README.rst b/samples/drivers/led_ws2812/README.rst index 5529604b0a8caeb..183875520f2d27d 100644 --- a/samples/drivers/led_ws2812/README.rst +++ b/samples/drivers/led_ws2812/README.rst @@ -102,6 +102,8 @@ This sample uses different drivers depending on the selected board: I2S driver: - thingy52_nrf52832 +- nrf5340dk_nrf5340 (3.3V logic level, a logic level shifter may be required) + - should work for other boards featuring an nRF5340 host processor SPI driver: 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 000000000000000..9ccb06fb7bc12e3 --- /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 000000000000000..6805516207cddbf --- /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/led_ws2812/boards/nrf5340dk_nrf5340.conf b/samples/drivers/led_ws2812/boards/nrf5340dk_nrf5340.conf new file mode 100644 index 000000000000000..f5d64aaf5da02e0 --- /dev/null +++ b/samples/drivers/led_ws2812/boards/nrf5340dk_nrf5340.conf @@ -0,0 +1,5 @@ +CONFIG_SPI=n + +CONFIG_I2S=y +CONFIG_WS2812_STRIP=y +CONFIG_WS2812_STRIP_I2S=y diff --git a/samples/drivers/led_ws2812/boards/nrf5340dk_nrf5340.overlay b/samples/drivers/led_ws2812/boards/nrf5340dk_nrf5340.overlay new file mode 100644 index 000000000000000..738e79115326fee --- /dev/null +++ b/samples/drivers/led_ws2812/boards/nrf5340dk_nrf5340.overlay @@ -0,0 +1,36 @@ +#include + +&pinctrl { + i2s0_default_alt: i2s0_default_alt { + group1 { + /* Default I2S config for the nRF5340, P1.13 is the output */ + psels = , + , + , + ; + }; + }; +}; + +i2s_led: &i2s0 { + status = "okay"; + pinctrl-0 = <&i2s0_default_alt>; + pinctrl-names = "default"; +}; + +/ { + led_strip: ws2812 { + compatible = "worldsemi,ws2812-i2s"; + + i2s-dev = <&i2s_led>; + chain-length = <42>; /* arbitrary; change at will */ + color-mapping = ; + reset-delay = <500>; + }; + + aliases { + led-strip = &led_strip; + }; +}; diff --git a/samples/drivers/lora/receive/README.rst b/samples/drivers/lora/receive/README.rst new file mode 100644 index 000000000000000..8d08a5445ef6981 --- /dev/null +++ b/samples/drivers/lora/receive/README.rst @@ -0,0 +1,55 @@ +.. zephyr:code-sample:: lora-receive + :name: LoRa receive + :relevant-api: lora_api + + Receive packets in both synchronous and asynchronous mode using the LoRa + radio. + +Overview +******** + +This sample demonstrates how to use the LoRa radio driver to receive packets +both synchronously and asynchronously. + +In order to successfully receive messages, build and flash the accompanying +LoRa send sample :zephyr:code-sample:`lora-send` on another board within range. + +As this sample receives a finite number of packets and then sleeps infinitely, +the user must be ready to inspect the console output immediately after +resetting the device. + +Building and Running +******************** + +Build and flash the sample as follows, changing ``b_l072z_lrwan1`` for +your board, where your board has a ``lora0`` alias in the devicetree. + +.. zephyr-app-commands:: + :zephyr-app: zephyr/samples/drivers/lora/receive + :host-os: unix + :board: b_l072z_lrwan1 + :goals: build flash + :compact: + +Sample Output +============= + +.. code-block:: console + + [00:00:00.235,000] lora_receive: Synchronous reception + [00:00:00.956,000] lora_receive: Received data: helloworld (RSSI:-60dBm, SNR:7dBm) + [00:00:02.249,000] lora_receive: Received data: helloworld (RSSI:-57dBm, SNR:9dBm) + [00:00:03.541,000] lora_receive: Received data: helloworld (RSSI:-57dBm, SNR:9dBm) + [00:00:04.834,000] lora_receive: Received data: helloworld (RSSI:-55dBm, SNR:9dBm) + [00:00:04.834,000] lora_receive: Asynchronous reception + [00:00:06.127,000] lora_receive: Received data: helloworld (RSSI:-55dBm, SNR:9dBm) + [00:00:07.419,000] lora_receive: Received data: helloworld (RSSI:-55dBm, SNR:9dBm) + [00:00:08.712,000] lora_receive: Received data: helloworld (RSSI:-55dBm, SNR:9dBm) + [00:00:10.004,000] lora_receive: Received data: helloworld (RSSI:-55dBm, SNR:9dBm) + [00:00:11.297,000] lora_receive: Received data: helloworld (RSSI:-55dBm, SNR:9dBm) + [00:00:12.590,000] lora_receive: Received data: helloworld (RSSI:-55dBm, SNR:9dBm) + [00:00:13.884,000] lora_receive: Received data: helloworld (RSSI:-55dBm, SNR:9dBm) + [00:00:15.177,000] lora_receive: Received data: helloworld (RSSI:-55dBm, SNR:9dBm) + [00:00:16.470,000] lora_receive: Received data: helloworld (RSSI:-55dBm, SNR:9dBm) + [00:00:17.762,000] lora_receive: Received data: helloworld (RSSI:-55dBm, SNR:9dBm) + [00:00:17.762,000] lora_receive: Stopping packet receptions diff --git a/samples/drivers/lora/send/README.rst b/samples/drivers/lora/send/README.rst new file mode 100644 index 000000000000000..f2b46bcc917c26c --- /dev/null +++ b/samples/drivers/lora/send/README.rst @@ -0,0 +1,37 @@ +.. zephyr:code-sample:: lora-send + :name: LoRa send + :relevant-api: lora_api + + Transmit a preconfigured payload every second using the LoRa radio. + +Overview +******** + +This sample demonstrates how to use the LoRa radio driver to configure +the encoding settings and send data over the radio. + +Transmitted messages can be received by building and flashing the accompanying +LoRa receive sample :zephyr:code-sample:`lora-receive` on another board within +range. + +Building and Running +******************** + +Build and flash the sample as follows, changing ``b_l072z_lrwan1`` for +your board, where your board has a ``lora0`` alias in the devicetree. + +.. zephyr-app-commands:: + :zephyr-app: zephyr/samples/drivers/lora/send + :host-os: unix + :board: b_l072z_lrwan1 + :goals: build flash + :compact: + +Sample Output +============= + +.. code-block:: console + + [00:00:00.531,000] lora_send: Data sent! + [00:00:01.828,000] lora_send: Data sent! + [00:00:03.125,000] lora_send: Data sent! diff --git a/samples/drivers/mbox/CMakeLists.txt b/samples/drivers/mbox/CMakeLists.txt index d94fdffbfb1904d..4344f4f3ce9f5ce 100644 --- a/samples/drivers/mbox/CMakeLists.txt +++ b/samples/drivers/mbox/CMakeLists.txt @@ -1,40 +1,35 @@ # # Copyright (c) 2021 Carlo Caione +# Copyright 2023 NXP # # SPDX-License-Identifier: Apache-2.0 # cmake_minimum_required(VERSION 3.20.0) -set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/mbox_ipc_remote-prefix/src/mbox_ipc_remote-build/zephyr) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../remote/zephyr) -if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") - set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet") -elseif("${BOARD}" STREQUAL "adp_xc7k_ae350") - set(BOARD_REMOTE "adp_xc7k_ae350") -elseif("${BOARD}" STREQUAL "mimxrt595_evk_cm33") - set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet") +if(("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") OR + ("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") OR + ("${BOARD}" STREQUAL "adp_xc7k_ae350") OR + ("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7") OR + ("${BOARD}" STREQUAL "mimxrt1170_evk_cm7") OR + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm7") OR + ("${BOARD}" STREQUAL "mimxrt595_evk_cm33")) + message(STATUS "${BOARD} compile as Main in this sample") else() message(FATAL_ERROR "${BOARD} is not supported for this sample") endif() -message(STATUS "${BOARD} compile as Main in this sample") - -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(mbox_ipc) enable_language(C ASM) -target_sources(app PRIVATE src/main.c) +if(CONFIG_INCLUDE_REMOTE_DIR) + target_include_directories(zephyr_interface + INTERFACE ${REMOTE_ZEPHYR_DIR}/include/public) +endif() -include(ExternalProject) - -ExternalProject_Add( - mbox_ipc_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 -) +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/mbox/Kconfig b/samples/drivers/mbox/Kconfig new file mode 100644 index 000000000000000..3837c49b6e98485 --- /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 new file mode 100644 index 000000000000000..f472576df826461 --- /dev/null +++ b/samples/drivers/mbox/Kconfig.sysbuild @@ -0,0 +1,16 @@ +# Copyright 2023 Nordic Semiconductor ASA +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config REMOTE_BOARD +string + default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" + 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" diff --git a/samples/drivers/mbox/README.rst b/samples/drivers/mbox/README.rst index 35c421335f91ea9..cee903710f77372 100644 --- a/samples/drivers/mbox/README.rst +++ b/samples/drivers/mbox/README.rst @@ -21,6 +21,7 @@ Building the application for nrf5340dk_nrf5340_cpuapp :zephyr-app: samples/drivers/mbox/ :board: nrf5340dk_nrf5340_cpuapp :goals: debug + :west-args: --sysbuild Open a serial terminal (minicom, putty, etc.) and connect the board with the following settings: @@ -58,3 +59,23 @@ core: Pong (on channel 1) Ping (on channel 0) Pong (on channel 1) + + +Building the application for the simulated nrf5340bsim +****************************************************** + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/mbox/ + :host-os: unix + :board: nrf5340bsim_nrf5340_cpuapp + :goals: build + :west-args: --sysbuild + +Then you can execute your application using: + +.. code-block:: console + + $ ./build/zephyr/zephyr.exe -nosim + # Press Ctrl+C to exit + +You can expect a similar output as in the real HW in the invoking console. 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 000000000000000..583b495036082b1 --- /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 000000000000000..942f67ba6a9d728 --- /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 000000000000000..583b495036082b1 --- /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 000000000000000..942f67ba6a9d728 --- /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 000000000000000..0dfb100ed70476d --- /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 000000000000000..942f67ba6a9d728 --- /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 a2efccf2227f8fd..e7db9b8cadf89e4 100644 --- a/samples/drivers/mbox/remote/CMakeLists.txt +++ b/samples/drivers/mbox/remote/CMakeLists.txt @@ -1,20 +1,25 @@ # # Copyright (c) 2021 Carlo Caione +# Copyright 2023 NXP # # SPDX-License-Identifier: Apache-2.0 # cmake_minimum_required(VERSION 3.20.0) -if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpunet") - message(STATUS "${BOARD} compile as remote in this sample") -elseif("${BOARD}" STREQUAL "adp_xc7k_ae350") +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 "adp_xc7k_ae350")) message(STATUS "${BOARD} compile as remote in this sample") else() message(FATAL_ERROR "${BOARD} is not supported for this sample") endif() -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(mbox_ipc_remote) target_sources(app PRIVATE src/main.c) 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 000000000000000..0d36a72aec6a916 --- /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 000000000000000..cc05e9b96c1cbba --- /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 000000000000000..0d36a72aec6a916 --- /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 000000000000000..cc05e9b96c1cbba --- /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 000000000000000..0d36a72aec6a916 --- /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 000000000000000..392141712a9dec0 --- /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/remote/boards/nrf5340bsim_nrf5340_cpunet.conf b/samples/drivers/mbox/remote/boards/nrf5340bsim_nrf5340_cpunet.conf new file mode 100644 index 000000000000000..665e456f504ce1b --- /dev/null +++ b/samples/drivers/mbox/remote/boards/nrf5340bsim_nrf5340_cpunet.conf @@ -0,0 +1,2 @@ +CONFIG_MBOX_NRFX_IPC=y +CONFIG_BUILD_OUTPUT_EXE=n diff --git a/samples/drivers/mbox/remote/sample.yaml b/samples/drivers/mbox/remote/sample.yaml deleted file mode 100644 index 014ad53a126792c..000000000000000 --- a/samples/drivers/mbox/remote/sample.yaml +++ /dev/null @@ -1,9 +0,0 @@ -sample: - name: MBOX IPC sample (remote) -tests: - sample.drivers.mbox_remote: - platform_allow: nrf5340dk_nrf5340_cpunet adp_xc7k_ae350 - integration_platforms: - - nrf5340dk_nrf5340_cpunet - tags: mbox - harness: remote diff --git a/samples/drivers/mbox/sample.yaml b/samples/drivers/mbox/sample.yaml index eb5e5ac1a5d2aa2..e8015cf7c258add 100644 --- a/samples/drivers/mbox/sample.yaml +++ b/samples/drivers/mbox/sample.yaml @@ -1,12 +1,37 @@ sample: name: MBOX IPC sample +common: + sysbuild: true + tags: mbox tests: - sample.drivers.mbox: + sample.drivers.mbox.real_hw: platform_allow: - nrf5340dk_nrf5340_cpuapp - adp_xc7k_ae350 - mimxrt595_evk_cm33 + - mimxrt1170_evkb_cm7 + - mimxrt1170_evk_cm7 + - mimxrt1160_evk_cm7 integration_platforms: - nrf5340dk_nrf5340_cpuapp - tags: mbox - 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 + 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\\)" diff --git a/samples/drivers/mbox/sysbuild.cmake b/samples/drivers/mbox/sysbuild.cmake new file mode 100644 index 000000000000000..7a5d32d4c747221 --- /dev/null +++ b/samples/drivers/mbox/sysbuild.cmake @@ -0,0 +1,32 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# Copyright 2023 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} +) + +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" + ) + # 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 000000000000000..a67552bf52eb1d6 --- /dev/null +++ b/samples/drivers/mbox_data/CMakeLists.txt @@ -0,0 +1,29 @@ +# 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")) + 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 000000000000000..ee3874c39f9b22d --- /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 000000000000000..e355713e714cec4 --- /dev/null +++ b/samples/drivers/mbox_data/Kconfig.sysbuild @@ -0,0 +1,11 @@ +# 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" diff --git a/samples/drivers/mbox_data/README.rst b/samples/drivers/mbox_data/README.rst new file mode 100644 index 000000000000000..3ead1ec3b874886 --- /dev/null +++ b/samples/drivers/mbox_data/README.rst @@ -0,0 +1,95 @@ +.. 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 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 + +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/mimxrt1160_evk_cm7.conf b/samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.conf new file mode 100644 index 000000000000000..583b495036082b1 --- /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 000000000000000..870b9928faf9e2d --- /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 000000000000000..583b495036082b1 --- /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 000000000000000..870b9928faf9e2d --- /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 000000000000000..0dfb100ed70476d --- /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 000000000000000..870b9928faf9e2d --- /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 000000000000000..293e2834f2535c3 --- /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 000000000000000..31f6db9b64128a2 --- /dev/null +++ b/samples/drivers/mbox_data/remote/CMakeLists.txt @@ -0,0 +1,20 @@ +# 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")) + 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/mimxrt1160_evk_cm4.conf b/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.conf new file mode 100644 index 000000000000000..0d36a72aec6a916 --- /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 000000000000000..3f6115b9c583b7d --- /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 000000000000000..0d36a72aec6a916 --- /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 000000000000000..3f6115b9c583b7d --- /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 000000000000000..0d36a72aec6a916 --- /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 000000000000000..e35768267025544 --- /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 000000000000000..473e428060171af --- /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 000000000000000..9fccf155c23bf2a --- /dev/null +++ b/samples/drivers/mbox_data/remote/src/main.c @@ -0,0 +1,75 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#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); + + 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 = 4; + + 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 000000000000000..5484233b2e8d185 --- /dev/null +++ b/samples/drivers/mbox_data/sample.yaml @@ -0,0 +1,27 @@ +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 + integration_platforms: + - mimxrt1160_evk_cm7 + 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 000000000000000..27c29b07554a17d --- /dev/null +++ b/samples/drivers/mbox_data/src/main.c @@ -0,0 +1,74 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#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); + + 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 = 4; + + 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 000000000000000..5c536a6229aaadf --- /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/memc/CMakeLists.txt b/samples/drivers/memc/CMakeLists.txt index 1e46e72f25b8f37..04025a6b0fb13a7 100644 --- a/samples/drivers/memc/CMakeLists.txt +++ b/samples/drivers/memc/CMakeLists.txt @@ -5,4 +5,9 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(memc) + +if(CONFIG_MEMC_MCUX_FLEXSPI) + target_include_directories(app PRIVATE ${ZEPHYR_BASE}/drivers/memc) +endif() + target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/memc/src/main.c b/samples/drivers/memc/src/main.c index 86b7ff86b60dfe7..60bc1170761d15a 100644 --- a/samples/drivers/memc/src/main.c +++ b/samples/drivers/memc/src/main.c @@ -7,8 +7,11 @@ #include #if DT_HAS_COMPAT_STATUS_OKAY(nxp_imx_flexspi) -/* FlexSPI memory mapped region is second register property of parent dev */ -#define MEMC_BASE DT_REG_ADDR_BY_IDX(DT_PARENT(DT_ALIAS(sram_ext)), 1) +/* Use memc API to get AHB base address for the device */ +#include "memc_mcux_flexspi.h" +#define FLEXSPI_DEV DEVICE_DT_GET(DT_PARENT(DT_ALIAS(sram_ext))) +#define MEMC_PORT DT_REG_ADDR(DT_ALIAS(sram_ext)) +#define MEMC_BASE memc_flexspi_get_ahb_address(FLEXSPI_DEV, MEMC_PORT, 0) #define MEMC_SIZE (DT_PROP(DT_ALIAS(sram_ext), size) / 8) #endif @@ -49,7 +52,7 @@ int main(void) for (i = 0; i < BUF_SIZE; i++) { memc_write_buffer[i] = (uint8_t)i; } - printk("Writing to memory region with base 0x%0x, size 0x%0x\n\n", + printk("Writing to memory region with base %p, size 0x%0x\n\n", MEMC_BASE, MEMC_SIZE); /* Copy write buffer into memc region */ for (i = 0, j = 0; j < (MEMC_SIZE / BUF_SIZE); i += BUF_SIZE, j++) { diff --git a/samples/drivers/ps2/prj.conf b/samples/drivers/ps2/prj.conf index 743787bd855c123..182a536650fb44b 100644 --- a/samples/drivers/ps2/prj.conf +++ b/samples/drivers/ps2/prj.conf @@ -2,3 +2,4 @@ CONFIG_STDOUT_CONSOLE=y CONFIG_PRINTK=y CONFIG_PS2=y CONFIG_PM_DEVICE=y +CONFIG_PM=y diff --git a/samples/drivers/smbus/README.rst b/samples/drivers/smbus/README.rst index cd2e7ed90d17e34..28558247706b50c 100644 --- a/samples/drivers/smbus/README.rst +++ b/samples/drivers/smbus/README.rst @@ -27,13 +27,17 @@ The sample can be built and run as follows for the ``qemu_x86_64`` board: Sample Output ************* -Output from console when application started:: +Output from console when application started: + +.. code-block:: console *** Booting Zephyr OS build zephyr-v3.2.0-804-gfedd72615e82 *** Start SMBUS shell sample qemu_x86_64 uart:~$ -List available SMBus shell commands with:: +List available SMBus shell commands with: + +.. code-block:: console uart:~$ smbus smbus - smbus commands @@ -59,7 +63,9 @@ List available SMBus shell commands with:: block_read :SMBus: Block Read command Usage: block_read -Scan for available SMBus devices with command:: +Scan for available SMBus devices with command: + +.. code-block:: console uart:~$ smbus scan smbus@fb00 0 1 2 3 4 5 6 7 8 9 a b c d e f diff --git a/samples/drivers/smbus/prj.conf b/samples/drivers/smbus/prj.conf index a02baae7ec92afd..8ed31bb9e29d06a 100644 --- a/samples/drivers/smbus/prj.conf +++ b/samples/drivers/smbus/prj.conf @@ -1,4 +1,5 @@ CONFIG_SMBUS=y +CONFIG_SMBUS_SHELL=y CONFIG_SMBUS_INTEL_PCH=y CONFIG_SMBUS_LOG_LEVEL_DBG=y CONFIG_USERSPACE=y diff --git a/samples/drivers/soc_flash_nand/CMakeLists.txt b/samples/drivers/soc_flash_nand/CMakeLists.txt new file mode 100644 index 000000000000000..ea5e877d899249a --- /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 000000000000000..1275aa15a25499b --- /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 000000000000000..463cd27a152ef20 --- /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 000000000000000..1e68da3131a7931 --- /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 000000000000000..ddcd8fcba915128 --- /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/soc_flash_nrf/README.rst b/samples/drivers/soc_flash_nrf/README.rst index 496688e8b65f2f9..2ee87739aad0026 100644 --- a/samples/drivers/soc_flash_nrf/README.rst +++ b/samples/drivers/soc_flash_nrf/README.rst @@ -62,7 +62,7 @@ Sample Output Data read: 1234 Data read matches data written. Good! - Test 3: Flash erase (4 pages at 0x80000) + Test 3: Flash erase (2 pages at 0x80000) Flash erase succeeded! Test 4: Flash write (word array 2) @@ -131,3 +131,5 @@ Sample Output Test 8: Write block size API write-block-size = 1 + + Finished! diff --git a/samples/drivers/soc_flash_nrf/prj.conf b/samples/drivers/soc_flash_nrf/prj.conf index 9909ef3b29f8cac..48e64121b6a16f6 100644 --- a/samples/drivers/soc_flash_nrf/prj.conf +++ b/samples/drivers/soc_flash_nrf/prj.conf @@ -3,3 +3,7 @@ CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_MPU_ALLOW_FLASH_WRITE=y CONFIG_SOC_FLASH_NRF_EMULATE_ONE_BYTE_WRITE_ACCESS=y +CONFIG_FCB=y +CONFIG_FLASH_MAP=y +CONFIG_SETTINGS=y +CONFIG_SETTINGS_FCB=y diff --git a/samples/drivers/soc_flash_nrf/sample.yaml b/samples/drivers/soc_flash_nrf/sample.yaml index 6557988b6e3a572..d1f635ca93faa73 100644 --- a/samples/drivers/soc_flash_nrf/sample.yaml +++ b/samples/drivers/soc_flash_nrf/sample.yaml @@ -10,8 +10,7 @@ tests: - nrf52dk_nrf52832 tags: - flash - - nrf52 - - nrf9160 + - drivers harness: console harness_config: fixture: external_flash @@ -30,3 +29,4 @@ tests: - "Data read matches data written. Good!" - "SoC flash consists of \\d+ pages." - "write-block-size = 1" + - "Finished!" diff --git a/samples/drivers/soc_flash_nrf/src/main.c b/samples/drivers/soc_flash_nrf/src/main.c index a438a67cf2fc5e4..29606a9ca5dfeba 100644 --- a/samples/drivers/soc_flash_nrf/src/main.c +++ b/samples/drivers/soc_flash_nrf/src/main.c @@ -13,11 +13,7 @@ #include -#ifdef CONFIG_TRUSTED_EXECUTION_NONSECURE -#define TEST_PARTITION slot1_ns_partition -#else -#define TEST_PARTITION slot1_partition -#endif +#define TEST_PARTITION storage_partition #define TEST_PARTITION_OFFSET FIXED_PARTITION_OFFSET(TEST_PARTITION) #define TEST_PARTITION_DEVICE FIXED_PARTITION_DEVICE(TEST_PARTITION) @@ -84,9 +80,9 @@ int main(void) } } - offset = TEST_PARTITION_OFFSET - FLASH_PAGE_SIZE * 2; - printf("\nTest 3: Flash erase (4 pages at 0x%x)\n", offset); - if (flash_erase(flash_dev, offset, FLASH_PAGE_SIZE * 4) != 0) { + offset = TEST_PARTITION_OFFSET; + printf("\nTest 3: Flash erase (2 pages at 0x%x)\n", offset); + if (flash_erase(flash_dev, offset, FLASH_PAGE_SIZE * 2) != 0) { printf(" Flash erase failed!\n"); } else { printf(" Flash erase succeeded!\n"); @@ -191,5 +187,7 @@ int main(void) printf("\nTest 8: Write block size API\n"); printf(" write-block-size = %u\n", flash_get_write_block_size(flash_dev)); + + printf("\nFinished!\n"); return 0; } diff --git a/samples/drivers/spi_flash/README.rst b/samples/drivers/spi_flash/README.rst index 70b523a58a44ba3..6f2e81959be408e 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 e24f9a005254016..b3bec006e9cb0ce 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 c0fa477a106fc96..528ed22fc56acc0 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/native_tty/README.rst b/samples/drivers/uart/native_tty/README.rst index 8571ad1c538d66c..78c101dea1f71a4 100644 --- a/samples/drivers/uart/native_tty/README.rst +++ b/samples/drivers/uart/native_tty/README.rst @@ -15,7 +15,7 @@ The source code for this sample application can be found at: :zephyr_file:`samples/drivers/uart/native-tty`. You can learn more about the Native TTY UART driver in the -:ref:`TTY UART ` section of the Native posix board +:ref:`TTY UART ` section of the native_sim board documentation. Requirements @@ -28,18 +28,18 @@ Requirements ``/dev/ttyUSB0`` and ``/dev/ttyUSB1`` in the system. You can check what they are in your system by running the command ``ls -l /dev/tty*``. If that is not the case on your machine you can either change the ``serial-port`` properties - in the ``boards/native_posix.overlay`` file or using the command line options + in the ``boards/native_sim.overlay`` file or using the command line options ``-uart_port`` and ``-uart_port2``. Building and Running ******************** -This application can be built and executed on Native Posix as follows: +This application can be built and executed on :ref:`native_sim ` as follows: .. zephyr-app-commands:: :zephyr-app: samples/drivers/uart/native_tty :host-os: unix - :board: native_posix + :board: native_sim :goals: run :compact: diff --git a/samples/drivers/uart/native_tty/boards/native_posix.overlay b/samples/drivers/uart/native_tty/boards/native_posix.overlay index 24f1bd95705bda3..6a3daca3241ac6e 100644 --- a/samples/drivers/uart/native_tty/boards/native_posix.overlay +++ b/samples/drivers/uart/native_tty/boards/native_posix.overlay @@ -1,15 +1 @@ -/ { - uart0: uart { - status = "okay"; - compatible = "zephyr,native-tty-uart"; - current-speed = <115200>; - serial-port = "/dev/ttyUSB0"; - }; - - uart2: uart2 { - status = "okay"; - compatible = "zephyr,native-tty-uart"; - current-speed = <115200>; - serial-port = "/dev/ttyUSB1"; - }; -}; +#include "native_sim.overlay" diff --git a/samples/drivers/uart/native_tty/boards/native_sim.overlay b/samples/drivers/uart/native_tty/boards/native_sim.overlay index 2b055bf3de6def2..24f1bd95705bda3 100644 --- a/samples/drivers/uart/native_tty/boards/native_sim.overlay +++ b/samples/drivers/uart/native_tty/boards/native_sim.overlay @@ -1 +1,15 @@ -#include "native_posix.overlay" +/ { + uart0: uart { + status = "okay"; + compatible = "zephyr,native-tty-uart"; + current-speed = <115200>; + serial-port = "/dev/ttyUSB0"; + }; + + uart2: uart2 { + status = "okay"; + compatible = "zephyr,native-tty-uart"; + current-speed = <115200>; + serial-port = "/dev/ttyUSB1"; + }; +}; diff --git a/samples/drivers/uart/native_tty/prj.conf b/samples/drivers/uart/native_tty/prj.conf index ef2861c789f8d14..7958f8c58bf29a6 100644 --- a/samples/drivers/uart/native_tty/prj.conf +++ b/samples/drivers/uart/native_tty/prj.conf @@ -1 +1,2 @@ CONFIG_SERIAL=y +CONFIG_UART_USE_RUNTIME_CONFIGURE=y diff --git a/samples/drivers/uart/passthrough/CMakeLists.txt b/samples/drivers/uart/passthrough/CMakeLists.txt new file mode 100644 index 000000000000000..ca7c7f7faa5124b --- /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 000000000000000..94d58f3dca17abb --- /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 000000000000000..5292b54e5f5a75f --- /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 000000000000000..70eec2fbac3df85 --- /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 000000000000000..5e4abf91f4d0ee3 --- /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 000000000000000..2168207a7516dab --- /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 000000000000000..660b55c05121d45 --- /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 000000000000000..6bcb1dc5909d3d9 --- /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 000000000000000..6bcb1dc5909d3d9 --- /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 000000000000000..66157d79fb36ff9 --- /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/drivers/watchdog/boards/up_squared_pro_7000.overlay b/samples/drivers/watchdog/boards/up_squared_pro_7000.overlay new file mode 100644 index 000000000000000..660b55c05121d45 --- /dev/null +++ b/samples/drivers/watchdog/boards/up_squared_pro_7000.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/xmc45_relax_kit.overlay b/samples/drivers/watchdog/boards/xmc45_relax_kit.overlay new file mode 100644 index 000000000000000..44cc7a91cda175d --- /dev/null +++ b/samples/drivers/watchdog/boards/xmc45_relax_kit.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 SLB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&wdt0 { + status = "okay"; +}; diff --git a/samples/drivers/watchdog/boards/xmc47_relax_kit.overlay b/samples/drivers/watchdog/boards/xmc47_relax_kit.overlay new file mode 100644 index 000000000000000..44cc7a91cda175d --- /dev/null +++ b/samples/drivers/watchdog/boards/xmc47_relax_kit.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 SLB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&wdt0 { + status = "okay"; +}; diff --git a/samples/drivers/watchdog/sample.yaml b/samples/drivers/watchdog/sample.yaml index d9c908d536d41b9..f3e11dda9b5c347 100644 --- a/samples/drivers/watchdog/sample.yaml +++ b/samples/drivers/watchdog/sample.yaml @@ -20,6 +20,8 @@ tests: platform_exclude: - s32z270dc2_rtu0_r52 - s32z270dc2_rtu1_r52 + - s32z270dc2_rtu0_r52@D + - s32z270dc2_rtu1_r52@D sample.drivers.watchdog.stm32_wwdg: extra_args: DTC_OVERLAY_FILE=boards/stm32_wwdg.overlay filter: dt_compat_enabled("st,stm32-window-watchdog") @@ -106,3 +108,5 @@ tests: platform_allow: - s32z270dc2_rtu0_r52 - s32z270dc2_rtu1_r52 + - s32z270dc2_rtu0_r52@D + - s32z270dc2_rtu1_r52@D diff --git a/samples/hello_world/sample.yaml b/samples/hello_world/sample.yaml index 60cbe49360f6b6b..1bcb7db62f25553 100644 --- a/samples/hello_world/sample.yaml +++ b/samples/hello_world/sample.yaml @@ -5,7 +5,7 @@ sample: common: tags: introduction integration_platforms: - - native_posix + - native_sim harness: console harness_config: type: one_line diff --git a/samples/kernel/condition_variables/condvar/README.rst b/samples/kernel/condition_variables/condvar/README.rst index 51f4cf0beb23d13..bd84d54854a7c5c 100644 --- a/samples/kernel/condition_variables/condvar/README.rst +++ b/samples/kernel/condition_variables/condvar/README.rst @@ -20,16 +20,16 @@ the console. Building and Running ******************** -This application can be built and executed on Native Posix as follows: +This application can be built and executed on :ref:`native_sim ` as follows: .. zephyr-app-commands:: :zephyr-app: samples/kernel/condition_variables/condvar :host-os: unix - :board: native_posix + :board: native_sim :goals: run :compact: -To build for another board, change "native_posix" above to that board's name. +To build for another board, change ``native_sim`` above to that board's name. Sample Output ============= diff --git a/samples/kernel/condition_variables/condvar/sample.yaml b/samples/kernel/condition_variables/condvar/sample.yaml index a6e1515c67b05c9..d2a68fbdce4977c 100644 --- a/samples/kernel/condition_variables/condvar/sample.yaml +++ b/samples/kernel/condition_variables/condvar/sample.yaml @@ -1,7 +1,7 @@ tests: sample.kernel.cond_var: integration_platforms: - - native_posix + - native_sim tags: - kernel - condition_variables diff --git a/samples/kernel/condition_variables/simple/README.rst b/samples/kernel/condition_variables/simple/README.rst index 42199d31c5bda34..2977b72cc9739b5 100644 --- a/samples/kernel/condition_variables/simple/README.rst +++ b/samples/kernel/condition_variables/simple/README.rst @@ -19,16 +19,16 @@ the console. Building and Running ******************** -This application can be built and executed on Native Posix as follows: +This application can be built and executed on :ref:`native_sim ` as follows: .. zephyr-app-commands:: :zephyr-app: samples/kernel/condition_variables/simple :host-os: unix - :board: native_posix + :board: native_sim :goals: run :compact: -To build for another board, change "native_posix" above to that board's name. +To build for another board, change ``native_sim`` above to that board's name. Sample Output ============= diff --git a/samples/kernel/condition_variables/simple/sample.yaml b/samples/kernel/condition_variables/simple/sample.yaml index 556fc8e9f03ec72..0b260a8a7e30cc9 100644 --- a/samples/kernel/condition_variables/simple/sample.yaml +++ b/samples/kernel/condition_variables/simple/sample.yaml @@ -1,7 +1,7 @@ tests: sample.kernel.cond_var.simple: integration_platforms: - - native_posix + - native_sim tags: - kernel - condition_variables diff --git a/samples/kernel/metairq_dispatch/README.rst b/samples/kernel/metairq_dispatch/README.rst index ef7e96afa17e691..1e9fda7927c03e0 100644 --- a/samples/kernel/metairq_dispatch/README.rst +++ b/samples/kernel/metairq_dispatch/README.rst @@ -60,7 +60,7 @@ kHz). Note that because the test is fundamentally measuring thread preemption behavior, it does not run without modification on -native_posix platforms. In that emulation environment, threads will +native_sim platforms. In that emulation environment, threads will not be preempted except at specific instrumentation points (e.g. in k_busy_wait()) where they will voluntarily release the CPU. diff --git a/samples/kernel/metairq_dispatch/sample.yaml b/samples/kernel/metairq_dispatch/sample.yaml index 201166f7e78c2fb..82090751b33fc59 100644 --- a/samples/kernel/metairq_dispatch/sample.yaml +++ b/samples/kernel/metairq_dispatch/sample.yaml @@ -14,7 +14,7 @@ common: regex: - "MetaIRQ Test Complete" -# Note that native_posix architectures are filtered, they require +# Note that boards based on the POSIX architecture are filtered as they require # instrumentation (e.g. a k_busy_wait()) inside the worker threads # "busy" loops in order for the interrupts to fire on time, and the # sample is designed to demonstrate completely arbitrary CPU work. diff --git a/samples/modules/canopennode/README.rst b/samples/modules/canopennode/README.rst index ae6f135ae30d9ca..50b53aab99f1f72 100644 --- a/samples/modules/canopennode/README.rst +++ b/samples/modules/canopennode/README.rst @@ -26,6 +26,13 @@ Requirements Building and Running ******************** +First, ensure the optional CANopenNode module is enabled and available: + + .. code-block:: console + + west config manifest.project-filter +canopennode + west update canopennode + Building and Running for TWR-KE18F ================================== The :ref:`twr_ke18f` board is equipped with an onboard CAN diff --git a/samples/modules/chre/README.rst b/samples/modules/chre/README.rst index 54b9244d3dcad46..22a43a58432e9d6 100644 --- a/samples/modules/chre/README.rst +++ b/samples/modules/chre/README.rst @@ -31,7 +31,7 @@ To build the sample use the following west command: .. zephyr-app-commands:: :zephyr-app: samples/modules/chre - :board: native_posix + :board: native_sim :goals: build Once built and run, the sample application should: diff --git a/samples/modules/chre/sample.yaml b/samples/modules/chre/sample.yaml index 65f64e9453dc4f6..9442decc83df545 100644 --- a/samples/modules/chre/sample.yaml +++ b/samples/modules/chre/sample.yaml @@ -24,5 +24,5 @@ tests: - "EchoApp::nanoappEnd\\(\\)" - "I: Exiting EventLoop.*" integration_platforms: - - native_posix + - native_sim filter: CONFIG_FULL_LIBC_SUPPORTED diff --git a/samples/modules/chre/src/main.cpp b/samples/modules/chre/src/main.cpp index f9b2b16cb52f327..675e57e89324280 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/accelerometer_chart/CMakeLists.txt b/samples/modules/lvgl/accelerometer_chart/CMakeLists.txt new file mode 100644 index 000000000000000..6c4a568b1e51d82 --- /dev/null +++ b/samples/modules/lvgl/accelerometer_chart/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(accelerometer_chart) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/modules/lvgl/accelerometer_chart/Kconfig b/samples/modules/lvgl/accelerometer_chart/Kconfig new file mode 100644 index 000000000000000..bba256103be6c85 --- /dev/null +++ b/samples/modules/lvgl/accelerometer_chart/Kconfig @@ -0,0 +1,17 @@ +# Copyright (c) 2023 Benjamin Cabé +# SPDX-License-Identifier: Apache-2.0 + +config SAMPLE_CHART_POINTS_PER_SERIES + int "Number of points per series" + default 50 + range 10 200 + help + Maximum number of points per series in the accelerometer chart. + Warning: More points means more memory usage, and slower rendering! + +config SAMPLE_ACCEL_SAMPLING_RATE + int "Accelerometer sampling rate (Hz)" + default 50 + range 1 100 + +source "Kconfig.zephyr" diff --git a/samples/modules/lvgl/accelerometer_chart/README.rst b/samples/modules/lvgl/accelerometer_chart/README.rst new file mode 100644 index 000000000000000..69f90b4f4de610b --- /dev/null +++ b/samples/modules/lvgl/accelerometer_chart/README.rst @@ -0,0 +1,51 @@ +.. zephyr:code-sample:: lvgl-accelerometer-chart + :name: LVGL line chart with accelerometer data + :relevant-api: display_interface sensor_interface + + Display acceleration data on a real-time chart using LVGL. + +Overview +******** + +A sample application that demonstrates how to use LVGL and the :ref:`sensor API ` to +display acceleration data on a line chart that is updated in real time. + +This sample creates a line chart with three series, one for each axis of the accelerometer. An LVGL +timer fetches the latest acceleration data from the sensor every 20 ms (default value) and updates +the chart. The update period is configurable, see +:ref:`lvgl_accelerometer_chart_building_and_running` below. + +Requirements +************ + +* A board with a display. +* A sensor that provides acceleration data (:c:enumerator:`SENSOR_CHAN_ACCEL_XYZ`) and available + under the ``&accel0`` Devicetree alias. + +.. note:: + + A Devicetree overlay declaring an emulated BMI160 accelerometer is provided for the + ``native_posix*`` and ``native_sim*`` board variants, making it possible to run this sample on + your local machine. + +.. _lvgl_accelerometer_chart_building_and_running: + +Building and Running +******************** + +The maximum number of points to display for each series and the sampling rate of the +accelerometer can be configured using the :kconfig:option:`CONFIG_SAMPLE_CHART_POINTS_PER_SERIES` +and :kconfig:option:`CONFIG_SAMPLE_ACCEL_SAMPLING_RATE` Kconfig options, respectively. + +The default sampling rate is 50 Hz, and the default maximum number of points per series is 50. + +The demo can be built as follows (note how in this particular case the sampling rate is set to a +custom value of 20 Hz): + +.. zephyr-app-commands:: + :zephyr-app: samples/modules/lvgl/accelerometer_chart + :host-os: unix + :board: native_sim + :gen-args: -DCONFIG_SAMPLE_ACCEL_SAMPLING_RATE=20 + :goals: run + :compact: diff --git a/samples/modules/lvgl/accelerometer_chart/boards/native_posix.conf b/samples/modules/lvgl/accelerometer_chart/boards/native_posix.conf new file mode 100644 index 000000000000000..e01c80e9dfa5e39 --- /dev/null +++ b/samples/modules/lvgl/accelerometer_chart/boards/native_posix.conf @@ -0,0 +1 @@ +CONFIG_BMI160_TRIGGER_NONE=y diff --git a/samples/modules/lvgl/accelerometer_chart/boards/native_posix.overlay b/samples/modules/lvgl/accelerometer_chart/boards/native_posix.overlay new file mode 100644 index 000000000000000..dc4174b58d73883 --- /dev/null +++ b/samples/modules/lvgl/accelerometer_chart/boards/native_posix.overlay @@ -0,0 +1,16 @@ +/* Copyright (c) 2023 Benjamin Cabé + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + accel0 = &bmi_i2c; + }; +}; + +&i2c0 { + bmi_i2c: bmi@68 { + compatible = "bosch,bmi160"; + reg = <0x68>; + }; +}; diff --git a/samples/modules/lvgl/accelerometer_chart/boards/native_posix_64.conf b/samples/modules/lvgl/accelerometer_chart/boards/native_posix_64.conf new file mode 100644 index 000000000000000..e01c80e9dfa5e39 --- /dev/null +++ b/samples/modules/lvgl/accelerometer_chart/boards/native_posix_64.conf @@ -0,0 +1 @@ +CONFIG_BMI160_TRIGGER_NONE=y diff --git a/tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_posix_64.overlay b/samples/modules/lvgl/accelerometer_chart/boards/native_posix_64.overlay similarity index 100% rename from tests/drivers/gpio/gpio_enable_disable_interrupt/boards/native_posix_64.overlay rename to samples/modules/lvgl/accelerometer_chart/boards/native_posix_64.overlay diff --git a/samples/modules/lvgl/accelerometer_chart/boards/native_sim.conf b/samples/modules/lvgl/accelerometer_chart/boards/native_sim.conf new file mode 100644 index 000000000000000..e01c80e9dfa5e39 --- /dev/null +++ b/samples/modules/lvgl/accelerometer_chart/boards/native_sim.conf @@ -0,0 +1 @@ +CONFIG_BMI160_TRIGGER_NONE=y diff --git a/tests/drivers/gpio/gpio_get_direction/boards/native_posix_64.overlay b/samples/modules/lvgl/accelerometer_chart/boards/native_sim.overlay similarity index 100% rename from tests/drivers/gpio/gpio_get_direction/boards/native_posix_64.overlay rename to samples/modules/lvgl/accelerometer_chart/boards/native_sim.overlay diff --git a/samples/modules/lvgl/accelerometer_chart/boards/native_sim_64.conf b/samples/modules/lvgl/accelerometer_chart/boards/native_sim_64.conf new file mode 100644 index 000000000000000..e01c80e9dfa5e39 --- /dev/null +++ b/samples/modules/lvgl/accelerometer_chart/boards/native_sim_64.conf @@ -0,0 +1 @@ +CONFIG_BMI160_TRIGGER_NONE=y diff --git a/samples/modules/lvgl/accelerometer_chart/boards/native_sim_64.overlay b/samples/modules/lvgl/accelerometer_chart/boards/native_sim_64.overlay new file mode 100644 index 000000000000000..6a3daca3241ac6e --- /dev/null +++ b/samples/modules/lvgl/accelerometer_chart/boards/native_sim_64.overlay @@ -0,0 +1 @@ +#include "native_sim.overlay" diff --git a/samples/modules/lvgl/accelerometer_chart/prj.conf b/samples/modules/lvgl/accelerometer_chart/prj.conf new file mode 100644 index 000000000000000..a5d6e2e831e7fba --- /dev/null +++ b/samples/modules/lvgl/accelerometer_chart/prj.conf @@ -0,0 +1,9 @@ +CONFIG_MAIN_STACK_SIZE=4096 +CONFIG_LOG=y + +CONFIG_LVGL=y +CONFIG_LV_Z_MEM_POOL_SIZE=16384 + +CONFIG_DISPLAY=y +CONFIG_INPUT=y +CONFIG_SENSOR=y diff --git a/samples/modules/lvgl/accelerometer_chart/sample.yaml b/samples/modules/lvgl/accelerometer_chart/sample.yaml new file mode 100644 index 000000000000000..943a242d00cf5b2 --- /dev/null +++ b/samples/modules/lvgl/accelerometer_chart/sample.yaml @@ -0,0 +1,18 @@ +sample: + description: Real-time visualization of acceleration data using LVGL chart widget + name: LVGL acceleration chart +tests: + sample.modules.lvgl.accelerometer_chart: + filter: dt_chosen_enabled("zephyr,display") and dt_alias_exists("accel0") + min_flash: 250 + min_ram: 32 + harness: none + tags: + - samples + - display + - gui + - lvgl + modules: + - lvgl + integration_platforms: + - native_sim_64 diff --git a/samples/modules/lvgl/accelerometer_chart/src/main.c b/samples/modules/lvgl/accelerometer_chart/src/main.c new file mode 100644 index 000000000000000..2aaee9fad0d43d6 --- /dev/null +++ b/samples/modules/lvgl/accelerometer_chart/src/main.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 Benjamin Cabé + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(app, CONFIG_LOG_DEFAULT_LEVEL); + +static lv_obj_t *chart1; +static lv_chart_series_t *ser_x; +static lv_chart_series_t *ser_y; +static lv_chart_series_t *ser_z; +static lv_timer_t *sensor_timer; + +const struct device *accel_sensor; + +/* Timer handler: fetches sensor data and appends it to the chart */ +static void sensor_timer_cb(lv_timer_t *timer) +{ + struct sensor_value accel[3]; + int rc = sensor_sample_fetch(accel_sensor); + + if (rc == 0) { + rc = sensor_channel_get(accel_sensor, SENSOR_CHAN_ACCEL_XYZ, accel); + } + if (rc < 0) { + LOG_ERR("ERROR: Update failed: %d\n", rc); + return; + } + lv_chart_set_next_value(chart1, ser_x, sensor_value_to_double(&accel[0])); + lv_chart_set_next_value(chart1, ser_y, sensor_value_to_double(&accel[1])); + lv_chart_set_next_value(chart1, ser_z, sensor_value_to_double(&accel[2])); +} + +static void create_accelerometer_chart(lv_obj_t *parent) +{ + chart1 = lv_chart_create(parent); + lv_obj_set_size(chart1, LV_HOR_RES, LV_VER_RES); + lv_chart_set_type(chart1, LV_CHART_TYPE_LINE); + lv_chart_set_div_line_count(chart1, 5, 8); + lv_chart_set_range(chart1, LV_CHART_AXIS_PRIMARY_Y, -20, 20); /* roughly -/+ 2G */ + lv_chart_set_update_mode(chart1, LV_CHART_UPDATE_MODE_SHIFT); + + ser_x = lv_chart_add_series(chart1, lv_palette_main(LV_PALETTE_RED), + LV_CHART_AXIS_PRIMARY_Y); + ser_y = lv_chart_add_series(chart1, lv_palette_main(LV_PALETTE_BLUE), + LV_CHART_AXIS_PRIMARY_Y); + ser_z = lv_chart_add_series(chart1, lv_palette_main(LV_PALETTE_GREEN), + LV_CHART_AXIS_PRIMARY_Y); + + lv_chart_set_point_count(chart1, CONFIG_SAMPLE_CHART_POINTS_PER_SERIES); + + /* Do not display point markers on the data */ + lv_obj_set_style_size(chart1, 0, LV_PART_INDICATOR); +} + +int main(void) +{ + const struct device *display_dev; + + display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display)); + if (!device_is_ready(display_dev)) { + LOG_ERR("Device not ready, aborting test"); + return -ENODEV; + } + + accel_sensor = DEVICE_DT_GET(DT_ALIAS(accel0)); + if (!device_is_ready(accel_sensor)) { + LOG_ERR("Device %s is not ready\n", accel_sensor->name); + return -ENODEV; + } + + create_accelerometer_chart(lv_scr_act()); + sensor_timer = lv_timer_create(sensor_timer_cb, + 1000 / CONFIG_SAMPLE_ACCEL_SAMPLING_RATE, + NULL); + lv_task_handler(); + display_blanking_off(display_dev); + + while (1) { + k_msleep(lv_task_handler()); + } + + return 0; +} diff --git a/samples/modules/lvgl/demos/CMakeLists.txt b/samples/modules/lvgl/demos/CMakeLists.txt index 78185c611965f6e..c80e3b4364b1908 100644 --- a/samples/modules/lvgl/demos/CMakeLists.txt +++ b/samples/modules/lvgl/demos/CMakeLists.txt @@ -81,3 +81,10 @@ target_sources_ifdef(CONFIG_LV_USE_DEMO_BENCHMARK app PRIVATE target_sources_ifdef(CONFIG_LV_USE_DEMO_STRESS app PRIVATE ${LVGL_DIR}/demos/stress/lv_demo_stress.c ) + +target_sources_ifdef(CONFIG_LV_USE_DEMO_WIDGETS app PRIVATE + ${LVGL_DIR}/demos/widgets/assets/img_clothes.c + ${LVGL_DIR}/demos/widgets/assets/img_demo_widgets_avatar.c + ${LVGL_DIR}/demos/widgets/assets/img_lvgl_logo.c + ${LVGL_DIR}/demos/widgets/lv_demo_widgets.c +) diff --git a/samples/modules/lvgl/demos/Kconfig b/samples/modules/lvgl/demos/Kconfig index 01cf2f401955f21..6f61694f65181f5 100644 --- a/samples/modules/lvgl/demos/Kconfig +++ b/samples/modules/lvgl/demos/Kconfig @@ -25,6 +25,12 @@ config LV_Z_DEMO_STRESS help Build stress testing demo application. +config LV_Z_DEMO_WIDGETS + bool "LVGL widgets demo" + select LV_USE_DEMO_WIDGETS + help + Build stress testing demo application. + endchoice source "Kconfig.zephyr" diff --git a/samples/modules/lvgl/demos/README.rst b/samples/modules/lvgl/demos/README.rst index c27c71fa04dec26..cbc97616808a080 100644 --- a/samples/modules/lvgl/demos/README.rst +++ b/samples/modules/lvgl/demos/README.rst @@ -15,6 +15,8 @@ A sample showcasing upstream LVGL demos. The benchmark demo tests the performance in various cases. For example rectangle, border, shadow, text, image blending, image transformation, blending modes, etc. * Stress A stress test for LVGL. It contains a lot of object creation, deletion, animations, styles usage, and so on. It can be used if there is any memory corruption during heavy usage or any memory leaks. +* Widgets + Shows how the widgets look like out of the box using the built-in material theme. Requirements ************ @@ -29,7 +31,7 @@ These demos can be built as follows: .. zephyr-app-commands:: :zephyr-app: samples/modules/lvgl/demos :host-os: unix - :board: native_posix + :board: native_sim :gen-args: -DCONFIG_LV_Z_DEMO_MUSIC=y :goals: run :compact: @@ -37,7 +39,7 @@ These demos can be built as follows: .. zephyr-app-commands:: :zephyr-app: samples/modules/lvgl/demos :host-os: unix - :board: native_posix + :board: native_sim :gen-args: -DCONFIG_LV_Z_DEMO_BENCHMARK=y :goals: run :compact: @@ -45,7 +47,15 @@ These demos can be built as follows: .. zephyr-app-commands:: :zephyr-app: samples/modules/lvgl/demos :host-os: unix - :board: native_posix + :board: native_sim :gen-args: -DCONFIG_LV_Z_DEMO_STRESS=y :goals: run :compact: + +.. zephyr-app-commands:: + :zephyr-app: samples/modules/lvgl/demos + :host-os: unix + :board: native_sim + :gen-args: -DCONFIG_LV_Z_DEMO_WIDGETS=y + :goals: run + :compact: diff --git a/samples/modules/lvgl/demos/prj.conf b/samples/modules/lvgl/demos/prj.conf index 0b7217242f20da1..3392d5c4fd3128a 100644 --- a/samples/modules/lvgl/demos/prj.conf +++ b/samples/modules/lvgl/demos/prj.conf @@ -1,9 +1,9 @@ -CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_MAIN_STACK_SIZE=4096 CONFIG_LOG=y CONFIG_SHELL=y CONFIG_LVGL=y -CONFIG_LV_Z_MEM_POOL_SIZE=16384 +CONFIG_LV_Z_MEM_POOL_SIZE=49152 CONFIG_LV_Z_SHELL=y CONFIG_LV_USE_MONKEY=y diff --git a/samples/modules/lvgl/demos/sample.yaml b/samples/modules/lvgl/demos/sample.yaml index b928d9f37f0755e..2b9939eb4fd24a3 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,19 @@ tests: sample.modules.lvgl.demo_stress: extra_configs: - CONFIG_LV_Z_DEMO_STRESS=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/lvgl/demos/src/main.c b/samples/modules/lvgl/demos/src/main.c index c17ba02c88f2fe1..2e3785d82984a70 100644 --- a/samples/modules/lvgl/demos/src/main.c +++ b/samples/modules/lvgl/demos/src/main.c @@ -29,9 +29,11 @@ int main(void) lv_demo_benchmark(); #elif defined(CONFIG_LV_USE_DEMO_STRESS) lv_demo_stress(); +#elif defined(CONFIG_LV_USE_DEMO_WIDGETS) + lv_demo_widgets(); #else -#error Enable one of the demos CONFIG_LV_USE_DEMO_MUSIC, CONFIG_LV_USE_DEMO_BENCHMARK \ -or CONFIG_LV_USE_DEMO_STRESS. +#error Enable one of the demos CONFIG_LV_USE_DEMO_MUSIC, CONFIG_LV_USE_DEMO_BENCHMARK ,\ + CONFIG_LV_USE_DEMO_STRESS, or CONFIG_LV_USE_DEMO_WIDGETS #endif lv_task_handler(); diff --git a/samples/modules/nanopb/README.rst b/samples/modules/nanopb/README.rst index 071498668a4443b..6e6d567f29c0cdf 100644 --- a/samples/modules/nanopb/README.rst +++ b/samples/modules/nanopb/README.rst @@ -22,7 +22,7 @@ make sure the ``protoc`` executable is installed and available. Use ``apt`` to install dependency: - .. code-block:: bash + .. code-block:: shell sudo apt install protobuf-compiler @@ -30,7 +30,7 @@ make sure the ``protoc`` executable is installed and available. Use ``brew`` to install dependency: - .. code-block:: bash + .. code-block:: shell brew install protobuf @@ -38,10 +38,19 @@ make sure the ``protoc`` executable is installed and available. Use ``choco`` to install dependency: - .. code-block:: console + .. code-block:: shell choco install protoc + +Additionally Nanopb is an optional module and needs to be added explicitly to the workspace: + +.. code-block:: shell + + west config manifest.project-filter -- +nanopb + west update + + Building and Running ******************** diff --git a/samples/modules/nanopb/sample.yaml b/samples/modules/nanopb/sample.yaml index 2ea497b0f10817d..eb990848d18eea0 100644 --- a/samples/modules/nanopb/sample.yaml +++ b/samples/modules/nanopb/sample.yaml @@ -15,5 +15,5 @@ tests: - samples - nanopb integration_platforms: - - native_posix - - native_posix_64 + - native_sim + - native_sim_64 diff --git a/samples/modules/tflite-micro/hello_world/README.rst b/samples/modules/tflite-micro/hello_world/README.rst index 6ab9bcbbc2b47d5..9d6fff4db93cb45 100644 --- a/samples/modules/tflite-micro/hello_world/README.rst +++ b/samples/modules/tflite-micro/hello_world/README.rst @@ -94,7 +94,7 @@ TensorFlow, you must enable the below Kconfig options in your :file:`prj.conf`: .. code-block:: kconfig CONFIG_CPP=y - CONFIG_NEWLIB_LIBC=y + CONFIG_REQUIRES_FULL_LIBC=y CONFIG_TENSORFLOW_LITE_MICRO=y Note that the CMSIS-NN kernel sample demonstrates how to use CMSIS-NN optimized kernels with diff --git a/samples/modules/tflite-micro/hello_world/sample.yaml b/samples/modules/tflite-micro/hello_world/sample.yaml index ed70d085631620a..bfd142f67027945 100644 --- a/samples/modules/tflite-micro/hello_world/sample.yaml +++ b/samples/modules/tflite-micro/hello_world/sample.yaml @@ -20,7 +20,7 @@ tests: integration_platforms: - qemu_x86 tags: tensorflow - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED sample.tensorflow.helloworld.cmsis_nn: tags: tensorflow platform_allow: mps3_an547 diff --git a/samples/modules/tflite-micro/magic_wand/README.rst b/samples/modules/tflite-micro/magic_wand/README.rst index b020f23d9b16f58..4a3dadbf7c444d7 100644 --- a/samples/modules/tflite-micro/magic_wand/README.rst +++ b/samples/modules/tflite-micro/magic_wand/README.rst @@ -107,7 +107,7 @@ TensorFlow, you must enable the below Kconfig options in your :file:`prj.conf`: .. code-block:: kconfig CONFIG_CPP=y - CONFIG_NEWLIB_LIBC=y + CONFIG_REQUIRES_FULL_LIBC=y CONFIG_TENSORFLOW_LITE_MICRO=y Training diff --git a/samples/modules/tflite-micro/magic_wand/prj.conf b/samples/modules/tflite-micro/magic_wand/prj.conf index ff2119e62b8863d..2774abb66e2dc99 100644 --- a/samples/modules/tflite-micro/magic_wand/prj.conf +++ b/samples/modules/tflite-micro/magic_wand/prj.conf @@ -14,7 +14,7 @@ # ============================================================================== CONFIG_CPP=y CONFIG_STD_CPP17=y -CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y +CONFIG_REQUIRES_FLOAT_PRINTF=y CONFIG_SENSOR=y CONFIG_NETWORKING=n CONFIG_MAIN_STACK_SIZE=4096 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 0491f7a79624706..13733aaa0c606ee 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/tflite-micro/tflm_ethosu/src/main.cpp b/samples/modules/tflite-micro/tflm_ethosu/src/main.cpp index 19a4afad9c2050c..5671b0a0718541b 100644 --- a/samples/modules/tflite-micro/tflm_ethosu/src/main.cpp +++ b/samples/modules/tflite-micro/tflm_ethosu/src/main.cpp @@ -149,6 +149,8 @@ void inferenceProcessTask(void *_name, void *heap, void *_params) } k_thread_abort(k_current_get()); + + CODE_UNREACHABLE; } /* inferenceSenderTask - Creates NUM_INFERENCE_JOBS jobs, queues them, and then diff --git a/samples/modules/thrift/hello/README.rst b/samples/modules/thrift/hello/README.rst index 90a6d089a92b30e..a773bc547b56d23 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 95e1c45f160bcf3..35a97d3e8315161 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/cloud/aws_iot_mqtt/prj.conf b/samples/net/cloud/aws_iot_mqtt/prj.conf index 8f6bbb82c6b194c..6738212e44c0457 100644 --- a/samples/net/cloud/aws_iot_mqtt/prj.conf +++ b/samples/net/cloud/aws_iot_mqtt/prj.conf @@ -9,7 +9,7 @@ CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_INIT_STACKS=y CONFIG_HW_STACK_PROTECTION=y -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y CONFIG_SNTP=y CONFIG_JSON_LIBRARY=y CONFIG_POSIX_CLOCK=y diff --git a/samples/net/cloud/aws_iot_mqtt/sample.yaml b/samples/net/cloud/aws_iot_mqtt/sample.yaml index 4dc5c5153acb143..314dfc252b62e96 100644 --- a/samples/net/cloud/aws_iot_mqtt/sample.yaml +++ b/samples/net/cloud/aws_iot_mqtt/sample.yaml @@ -4,7 +4,7 @@ sample: common: tags: net mqtt cloud harness: net - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC extra_args: USE_DUMMY_CREDS=1 tests: sample.net.cloud.aws_iot_mqtt: diff --git a/samples/net/cloud/mqtt_azure/prj.conf b/samples/net/cloud/mqtt_azure/prj.conf index e3b8ac83edb4261..27b703bf5858ebb 100644 --- a/samples/net/cloud/mqtt_azure/prj.conf +++ b/samples/net/cloud/mqtt_azure/prj.conf @@ -47,7 +47,7 @@ CONFIG_DNS_RESOLVER=y CONFIG_DNS_SERVER_IP_ADDRESSES=y CONFIG_DNS_SERVER1="8.8.8.8" CONFIG_DNS_RESOLVER_ADDITIONAL_BUF_CTR=2 -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y CONFIG_INIT_STACKS=y CONFIG_NET_SHELL=y diff --git a/samples/net/cloud/mqtt_azure/sample.yaml b/samples/net/cloud/mqtt_azure/sample.yaml index 2f234d39481be77..ffa3e86689540f9 100644 --- a/samples/net/cloud/mqtt_azure/sample.yaml +++ b/samples/net/cloud/mqtt_azure/sample.yaml @@ -1,5 +1,5 @@ common: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED sample: description: MQTT sample app to Azure cloud name: mqtt-azure diff --git a/samples/net/dsa/prj.conf b/samples/net/dsa/prj.conf index 952aa9d272fbcc8..6309976db0680e1 100644 --- a/samples/net/dsa/prj.conf +++ b/samples/net/dsa/prj.conf @@ -49,7 +49,7 @@ CONFIG_NET_TC_TX_COUNT=6 CONFIG_NET_TC_RX_COUNT=4 CONFIG_NET_CONFIG_INIT_TIMEOUT=10 -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y CONFIG_NET_IF_MAX_IPV4_COUNT=4 CONFIG_NET_IF_MAX_IPV6_COUNT=4 diff --git a/samples/net/eth_native_posix/CMakeLists.txt b/samples/net/eth_native_posix/CMakeLists.txt deleted file mode 100644 index 4b116d7f47f929d..000000000000000 --- a/samples/net/eth_native_posix/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(eth_native_posix) - -target_sources(app PRIVATE src/main.c) - -include(${ZEPHYR_BASE}/samples/net/common/common.cmake) diff --git a/samples/net/eth_native_posix/README.rst b/samples/net/eth_native_posix/README.rst deleted file mode 100644 index 7d7232acd5c3396..000000000000000 --- a/samples/net/eth_native_posix/README.rst +++ /dev/null @@ -1,147 +0,0 @@ -.. zephyr:code-sample:: eth-native-posix - :name: Native POSIX Ethernet - :relevant-api: net_core ethernet - - Create a network interface to the host system. - -Overview -******** - -The eth_native_posix sample application for Zephyr creates a **zeth** network -interface to the host system. One can communicate with Zephyr via this network -interface. - -The source code for this sample application can be found at: -:zephyr_file:`samples/net/eth_native_posix`. - -Building And Running -******************** - -To build the eth_native_posix sample application, follow the steps -below. - -.. zephyr-app-commands:: - :zephyr-app: samples/net/eth_native_posix - :host-os: unix - :board: native_posix - :conf: - :goals: build - :compact: - -Normally one needs extra privileges to create and configure the TAP device in -the host system. If the user has set the -:kconfig:option:`CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC` option (this is disabled -by default), then the user needs to use ``sudo`` to execute the Zephyr process -with admin privileges, like this: - -.. code-block:: console - - sudo --preserve-env=ZEPHYR_BASE make -Cbuild run - -If the ``sudo --preserve-env=ZEPHYR_BASE`` gives an error, -just use ``sudo --preserve-env`` instead. - -If the :kconfig:option:`CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC` option -is not enabled (this is the default), then the user should -execute the ``net-setup.sh`` script from Zephyr `net-tools`_ repository. -The script should be run before executing the Zephyr process. The script -will create the zeth interface and set up IP addresses and routes. -While running ``net-setup.sh`` requires root access, afterwards Zephyr -process can be run as a non-root user. - -You can run the ``net-setup.sh`` script like this:: - - cd net-tools - sudo ./net-setup.sh - -or:: - - sudo ./net-setup.sh --config ./zeth-vlan.conf - -See also other command line options by typing ``net-setup.sh --help``. - -When the network interface is set up manually, you can leave the wireshark -to monitor the interface, and then start and stop the zephyr process without -stopping the wireshark. - -Setting things manually works the same as working with SLIP connectivity -in QEMU. - -If you want to connect two Zephyr instances together, you can do it like this: - -Create two Zephyr config files prj1.conf and prj2.conf. You can use -:zephyr_file:`samples/net/eth_native_posix/prj.conf` as a base. - -Set prj1.conf IP address configuration like this: - -.. code-block:: console - - CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8:100::1" - CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8:100::2" - CONFIG_NET_CONFIG_MY_IPV4_ADDR="198.51.100.1" - CONFIG_NET_CONFIG_PEER_IPV4_ADDR="198.51.100.2" - CONFIG_NET_CONFIG_MY_IPV4_GW="203.0.113.1" - CONFIG_ETH_NATIVE_POSIX_RANDOM_MAC=n - CONFIG_ETH_NATIVE_POSIX_MAC_ADDR="00:00:5e:00:53:64" - CONFIG_ETH_NATIVE_POSIX_SETUP_SCRIPT="echo" - CONFIG_ETH_NATIVE_POSIX_DRV_NAME="zeth.1" - -Set prj2.conf IP address configuration like this: - -.. code-block:: console - - CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8:200::1" - CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8:200::2" - CONFIG_NET_CONFIG_MY_IPV4_ADDR="203.0.113.1" - CONFIG_NET_CONFIG_PEER_IPV4_ADDR="203.0.113.2" - CONFIG_NET_CONFIG_MY_IPV4_GW="198.51.100.1" - CONFIG_ETH_NATIVE_POSIX_RANDOM_MAC=n - CONFIG_ETH_NATIVE_POSIX_MAC_ADDR="00:00:5e:00:53:c8" - CONFIG_ETH_NATIVE_POSIX_SETUP_SCRIPT="echo" - CONFIG_ETH_NATIVE_POSIX_DRV_NAME="zeth.2" - -Then compile and run two Zephyr instances -(if ``sudo --preserve-env=ZEPHYR_BASE`` gives an error, -just use ``sudo --preserve-env`` instead): - -.. code-block:: console - - cmake -DCONF_FILE=prj1.conf -DBOARD=native_posix -Bbuild1/native_posix . - make -s -C build1/native_posix - sudo --preserve-env=ZEPHYR_BASE make -s -C build1/native_posix run - -.. code-block:: console - - cmake -DCONF_FILE=prj2.conf -DBOARD=native_posix -Bbuild2/native_posix . - make -s -C build2/native_posix - sudo --preserve-env=ZEPHYR_BASE make -s -C build2/native_posix run - -Bridge the two Zephyr instances together: - -.. code-block:: console - - sudo brctl addbr zeth-br - sudo brctl addif zeth-br zeth.1 - sudo brctl addif zeth-br zeth.2 - sudo ifconfig zeth-br up - -After this, you are able to ping device 1 from device 2 in net-shell: - -.. code-block:: console - - # In device 1 - net ping 2001:db8:200::1 - net ping 203.0.113.1 - -.. code-block:: console - - # In device 2 - net ping 2001:db8:100::1 - net ping 198.51.100.1 - -Note that in this setup you cannot access these two Zephyr devices from -your host. If you want to do that, then you could create a new network -interface with proper IP addresses and add that interface to the Zephyr -bridge. - -.. _`net-tools`: https://github.com/zephyrproject-rtos/net-tools diff --git a/samples/net/eth_native_posix/net_setup_host b/samples/net/eth_native_posix/net_setup_host deleted file mode 100755 index e1ee7b80c095174..000000000000000 --- a/samples/net/eth_native_posix/net_setup_host +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2018 Intel Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This script is called by native-posix board when TAP network interface -# is taken up by Zephyr. The script should setup the host system so that -# connectivity will work with Zephyr. - -while [ $# -gt 0 ]; do - case "$1" in - -f|--file) - CONF_FILE="$2" - shift - shift;; - -i|--interface) - # Only first -i option is taken into account. This way - # the driver added -i option is ignored if user has specified - # the -i option to host setup script command. - if [ -z "$IFACE" ]; then - IFACE="$2" - fi - shift - shift;; - *) - shift;; - esac -done - -if [ `id -u` != 0 ]; then - echo "Warning: This script will need admin rights to setup \ -network interface!" -fi - -if [ -z "$IFACE" ]; then - IFACE="zeth" -fi - -if [ -z "$CONF_FILE" ]; then - DIR=`dirname $0` - CONF_FILE="$DIR/net_setup_host.conf" -fi - -if [ -f "$CONF_FILE" ]; then - . $CONF_FILE -else - echo "Warning: config file $CONF_FILE does not exist!" -fi - -ip link set dev $IFACE up - -if [ ! -z "$HWADDR" ]; then - ip link set dev $IFACE address $HWADDR -fi - -if [ ! -z "$IPV6_ADDR_1" ]; then - ip -6 address add $IPV6_ADDR_1 dev $IFACE -fi - -if [ ! -z "$IPV6_ROUTE_1" ]; then - ip -6 route add $IPV6_ROUTE_1 dev $IFACE -fi - -if [ ! -z "$IPV4_ADDR_1" ]; then - ip address add $IPV4_ADDR_1 dev $IFACE -fi - -if [ ! -z "$IPV4_ROUTE_1" ]; then - ip route add $IPV4_ROUTE_1 dev $IFACE -fi diff --git a/samples/net/eth_native_posix/net_setup_host.conf b/samples/net/eth_native_posix/net_setup_host.conf deleted file mode 100644 index 4e6ab7a557410bc..000000000000000 --- a/samples/net/eth_native_posix/net_setup_host.conf +++ /dev/null @@ -1,11 +0,0 @@ -# -# Configuration options for setting up the host network interface -# - -HWADDR="00:00:5e:00:53:ff" - -IPV6_ADDR_1="2001:db8::2" -IPV6_ROUTE_1="2001:db8::/64" - -IPV4_ADDR_1="192.0.2.2" -IPV4_ROUTE_1="192.0.2.0/24" diff --git a/samples/net/eth_native_posix/net_start_wireshark.sh b/samples/net/eth_native_posix/net_start_wireshark.sh deleted file mode 100755 index 2fcdeded9d1faab..000000000000000 --- a/samples/net/eth_native_posix/net_start_wireshark.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2018 Intel Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This script can be called by native-posix board when TAP network interface -# is created. This script will start wireshark so that it is possible to -# monitor the network traffic for the interface. - -if [ ! -z "$1" ]; then - IFACE="$1" -else - IFACE="zeth" -fi - -WIRESHARK="wireshark -k -i $IFACE" - -echo "Starting \"$WIRESHARK\" as \"`id -u -n`\" user." - -$WIRESHARK & - -# The startup of wireshark is slow so sleep here a bit so that everything -# in wireshark is setup properly before continuing with zephyr startup. -sleep 5 diff --git a/samples/net/eth_native_posix/prj.conf b/samples/net/eth_native_posix/prj.conf deleted file mode 100644 index dedd8e86bfc60ac..000000000000000 --- a/samples/net/eth_native_posix/prj.conf +++ /dev/null @@ -1,40 +0,0 @@ -CONFIG_NETWORKING=y -CONFIG_NET_UDP=y -CONFIG_NET_TCP=y -CONFIG_NET_IPV6=y -CONFIG_NET_IPV4=y -#CONFIG_NET_DHCPV4=y - -CONFIG_ENTROPY_GENERATOR=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_INIT_STACKS=y - -CONFIG_NET_LOG=y -CONFIG_LOG=y - -CONFIG_NET_STATISTICS=y - -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_IF_UNICAST_IPV6_ADDR_COUNT=3 -CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 -CONFIG_NET_MAX_CONTEXTS=10 - -CONFIG_NET_SHELL=y - -CONFIG_NET_CONFIG_SETTINGS=y -CONFIG_NET_CONFIG_NEED_IPV6=y -CONFIG_NET_CONFIG_NEED_IPV4=y -CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" -CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" -CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" - -CONFIG_NET_L2_ETHERNET=y - -CONFIG_ETH_NATIVE_POSIX=y -CONFIG_ETH_NATIVE_POSIX_RANDOM_MAC=y -#CONFIG_ETH_NATIVE_POSIX_MAC_ADDR="00:00:5e:00:53:2a" diff --git a/samples/net/eth_native_posix/sample.yaml b/samples/net/eth_native_posix/sample.yaml deleted file mode 100644 index d60d6adf68b56a3..000000000000000 --- a/samples/net/eth_native_posix/sample.yaml +++ /dev/null @@ -1,13 +0,0 @@ -common: - harness: net - tags: net -sample: - description: Can be used to test native posix connectivity via ethernet. - name: Native posix ethernet demo application -tests: - sample.net.eth_native_posix: - platform_allow: - - native_posix - - native_posix_64 - integration_platforms: - - native_posix diff --git a/samples/net/eth_native_posix/src/main.c b/samples/net/eth_native_posix/src/main.c deleted file mode 100644 index fccb0ddde9d1c29..000000000000000 --- a/samples/net/eth_native_posix/src/main.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_REGISTER(net_native_posix_sample, LOG_LEVEL_DBG); - -#include -#include - -#include - -/* This application itself does nothing as there is net-shell that can be used - * to monitor things. - */ -int main(void) -{ - LOG_INF("Start application"); - return 0; -} diff --git a/samples/net/gptp/README.rst b/samples/net/gptp/README.rst index a2c8696d95a3c21..f0c1b39e9581dd9 100644 --- a/samples/net/gptp/README.rst +++ b/samples/net/gptp/README.rst @@ -19,13 +19,13 @@ Requirements ************ For generic host connectivity, that can be used for debugging purposes, see -:ref:`networking_with_native_posix` for details. +:ref:`networking_with_native_sim` for details. Building and Running ******************** A good way to run this sample is to run this gPTP application inside -native_posix board as described in :ref:`networking_with_native_posix` or with +native_sim board as described in :ref:`networking_with_native_sim` or with embedded device like NXP FRDM-K64F, Nucleo-H743-ZI, Nucleo-H745ZI-Q, Nucleo-F767ZI or Atmel SAM-E70 Xplained. Note that gPTP is only supported for boards that have an Ethernet port and which has support for collecting @@ -51,7 +51,7 @@ Setting up Linux Host If you need VLAN support in your network, then the :zephyr_file:`samples/net/vlan/vlan-setup-linux.sh` provides a script that can be executed on the Linux host. It creates two VLANs on the Linux host and creates -routes to Zephyr. If you are using native_posix board, then +routes to Zephyr. If you are using native_sim board, then the ``net-setup.sh`` will create VLAN setup automatically with this command: .. code-block:: console @@ -61,9 +61,9 @@ the ``net-setup.sh`` will create VLAN setup automatically with this command: The OpenAVNU repository at https://github.com/AVnu contains gPTP daemon that can be run in Linux host and which can act as a grandmaster for the IEEE 801.1AS network. Note that OpenAVNU will not work with -native_posix board as that board only supports software timestamping and +native_sim board as that board only supports software timestamping and OpenAVNU only supports hardware timestamping. See instructions at the end -of this chapter how to run linuxptp daemon with native_posix board. +of this chapter how to run linuxptp daemon with native_sim board. Get OpenAvnu/gPTP project sources @@ -126,7 +126,7 @@ By default gPTP in Zephyr will not print any gPTP debug messages to console. One can enable debug prints by setting :kconfig:option:`CONFIG_NET_GPTP_LOG_LEVEL_DBG` in the config file. -For native_posix board, use ``linuxptp`` project as that supports +For native_sim board, use ``linuxptp`` project as that supports software timestamping. Get linuxptp project sources @@ -150,7 +150,7 @@ Multiport Setup If you set :kconfig:option:`CONFIG_NET_GPTP_NUM_PORTS` larger than 1, then gPTP sample will create multiple TSN ports. This configuration is currently only supported -in native_posix board. +in native_sim board. You need to enable the ports in the net-tools. If the number of ports is set to 2, then give following commands to create the network interfaces in host @@ -163,7 +163,7 @@ side: After that you can start ptp4l daemon for both interfaces. Please use two terminals when starting ptp4l daemon. Note that you must use ptp4l as OpenAVNU -does not work with software clock available in native_posix. +does not work with software clock available in native_sim. .. code-block:: console @@ -175,7 +175,7 @@ Compile Zephyr application. .. zephyr-app-commands:: :zephyr-app: samples/net/gptp - :board: native_posix + :board: native_sim :goals: build :compact: diff --git a/samples/net/gptp/boards/mimxrt1050_evk.conf b/samples/net/gptp/boards/mimxrt1050_evk.conf index eeef6eaba023051..2819d3afd664911 100644 --- a/samples/net/gptp/boards/mimxrt1050_evk.conf +++ b/samples/net/gptp/boards/mimxrt1050_evk.conf @@ -7,5 +7,5 @@ CONFIG_ETH_MCUX_PTP_CLOCK_SRC_HZ=25000000 CONFIG_ETH_MCUX_RX_BUFFERS=6 CONFIG_ETH_MCUX_TX_BUFFERS=4 CONFIG_NET_GPTP_STATISTICS=y -CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y +CONFIG_REQUIRES_FLOAT_PRINTF=y diff --git a/samples/net/gptp/boards/mimxrt1060_evk.conf b/samples/net/gptp/boards/mimxrt1060_evk.conf index f12f5ebf34d0e71..114cebd8fe88112 100644 --- a/samples/net/gptp/boards/mimxrt1060_evk.conf +++ b/samples/net/gptp/boards/mimxrt1060_evk.conf @@ -6,6 +6,6 @@ CONFIG_NET_GPTP_CLOCK_ACCURACY_25MS=y #CONFIG_ETH_MCUX_RX_BUFFERS=6 #CONFIG_ETH_MCUX_TX_BUFFERS=8 CONFIG_NET_GPTP_STATISTICS=y -CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FLOAT_PRINTF=y +CONFIG_REQUIRES_FULL_LIBC=y CONFIG_NET_GPTP_INIT_LOG_PDELAY_REQ_ITV=-3 diff --git a/samples/net/gptp/boards/native_sim.conf b/samples/net/gptp/boards/native_sim.conf new file mode 100644 index 000000000000000..c514520186c2bbe --- /dev/null +++ b/samples/net/gptp/boards/native_sim.conf @@ -0,0 +1,8 @@ +# Settings for native_posix ethernet driver +CONFIG_ETH_NATIVE_POSIX_PTP_CLOCK=y + +#CONFIG_ETH_NATIVE_POSIX_RANDOM_MAC=y +CONFIG_ETH_NATIVE_POSIX_MAC_ADDR="00:00:5e:00:53:2a" + +# Assume 1 ms accuracy for native_posix simulated clock +CONFIG_NET_GPTP_CLOCK_ACCURACY_1MS=y diff --git a/samples/net/gptp/boards/native_sim_64.conf b/samples/net/gptp/boards/native_sim_64.conf new file mode 100644 index 000000000000000..c514520186c2bbe --- /dev/null +++ b/samples/net/gptp/boards/native_sim_64.conf @@ -0,0 +1,8 @@ +# Settings for native_posix ethernet driver +CONFIG_ETH_NATIVE_POSIX_PTP_CLOCK=y + +#CONFIG_ETH_NATIVE_POSIX_RANDOM_MAC=y +CONFIG_ETH_NATIVE_POSIX_MAC_ADDR="00:00:5e:00:53:2a" + +# Assume 1 ms accuracy for native_posix simulated clock +CONFIG_NET_GPTP_CLOCK_ACCURACY_1MS=y 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 000000000000000..720b511fdb9741f --- /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/docker-test.sh b/samples/net/gptp/docker-test.sh index 03ab0f48aa7d447..bc791584c0b58d6 100644 --- a/samples/net/gptp/docker-test.sh +++ b/samples/net/gptp/docker-test.sh @@ -14,7 +14,7 @@ start_docker \ "/usr/local/sbin/ptp4l -2 -f /etc/gptp.cfg -m -q -l 6 -S -i eth0" \ || return $? -# For native_posix gPTP run, the delay threshold needs to be huge +# For native_sim gPTP run, the delay threshold needs to be huge start_zephyr "$overlay" "-DCONFIG_NET_SAMPLE_RUN_DURATION=10" \ "-DCONFIG_NET_GPTP_NEIGHBOR_PROP_DELAY_THR=12000000" diff --git a/samples/net/gptp/sample.yaml b/samples/net/gptp/sample.yaml index 0184353569eacfe..e65327ef47a565b 100644 --- a/samples/net/gptp/sample.yaml +++ b/samples/net/gptp/sample.yaml @@ -13,9 +13,18 @@ tests: - sam_e70_xplained - native_posix - native_posix_64 + - native_sim + - native_sim_64 - nucleo_f767zi - nucleo_h743zi - nucleo_h745zi_q_m7 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/ipv4_autoconf/sample.yaml b/samples/net/ipv4_autoconf/sample.yaml index bb1f529ef4b380d..07260fee0add16c 100644 --- a/samples/net/ipv4_autoconf/sample.yaml +++ b/samples/net/ipv4_autoconf/sample.yaml @@ -7,8 +7,10 @@ common: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim sample: description: Test IPv4 autoconf functionality name: IPv4 autoconf sample app diff --git a/samples/net/lldp/sample.yaml b/samples/net/lldp/sample.yaml index 78b61768ee674be..4daf567dca29723 100644 --- a/samples/net/lldp/sample.yaml +++ b/samples/net/lldp/sample.yaml @@ -11,6 +11,8 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim depends_on: netif diff --git a/samples/net/lwm2m_client/Kconfig b/samples/net/lwm2m_client/Kconfig index 22fab04bbef7d57..2037d281ce0c322 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/README.rst b/samples/net/lwm2m_client/README.rst index 4e231ba005112ca..2225f789c0c8151 100644 --- a/samples/net/lwm2m_client/README.rst +++ b/samples/net/lwm2m_client/README.rst @@ -25,7 +25,7 @@ The source code for this sample application can be found at: Requirements ************ -- :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` or :ref:`networking_with_native_posix` +- :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` or :ref:`networking_with_native_sim` - Linux machine - Leshan Demo Server (https://eclipse.org/leshan/) @@ -68,8 +68,8 @@ Build the lwm2m-client sample application like this: :compact: The easiest way to setup this sample application is to build and run it -as native POSIX application or as a QEMU target using the default configuration :file:`prj.conf`. -This requires a small amount of setup described in :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` and :ref:`networking_with_native_posix`. +as a native_sim application or as a QEMU target using the default configuration :file:`prj.conf`. +This requires a small amount of setup described in :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` and :ref:`networking_with_native_sim`. Download and run the latest build of the Leshan Demo Server: diff --git a/samples/net/lwm2m_client/boards/native_sim.conf b/samples/net/lwm2m_client/boards/native_sim.conf new file mode 100644 index 000000000000000..3e21f837f7c2efe --- /dev/null +++ b/samples/net/lwm2m_client/boards/native_sim.conf @@ -0,0 +1,5 @@ +CONFIG_DNS_RESOLVER=y +CONFIG_DNS_SERVER_IP_ADDRESSES=y +CONFIG_DNS_SERVER1="192.0.2.2" +CONFIG_LWM2M_DNS_SUPPORT=y +CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2" diff --git a/samples/net/lwm2m_client/boards/qemu_x86.conf b/samples/net/lwm2m_client/boards/qemu_x86.conf index c099c8e81dfb8a0..5a1dc0925c37466 100644 --- a/samples/net/lwm2m_client/boards/qemu_x86.conf +++ b/samples/net/lwm2m_client/boards/qemu_x86.conf @@ -1 +1,5 @@ CONFIG_FPU=y +CONFIG_NET_L2_ETHERNET=y +CONFIG_NET_QEMU_ETHERNET=y + +CONFIG_PCIE=y diff --git a/samples/net/lwm2m_client/docker-test.sh b/samples/net/lwm2m_client/docker-test.sh new file mode 100644 index 000000000000000..a7200b21b4b3e76 --- /dev/null +++ b/samples/net/lwm2m_client/docker-test.sh @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if [ -z "$RUNNING_FROM_MAIN_SCRIPT" ]; then + echo "Do not run this script directly!" + echo "Run $ZEPHYR_BASE/scripts/net/run-sample-tests.sh instead." + exit 1 +fi + +IP="--ip=192.0.2.2 --ip6=2001:db8::2" +FWD="-p 8080:8080 -p 8081:8081 -p 5683:5683/udp" + +start_configuration "$IP $FWD" || return $? +start_docker "/net-tools/start-leshan.sh" || return $? + +start_zephyr + +sleep 5 +curl -s -X GET 'http://localhost:8080/api/clients/native_posix/3/0/0' | grep Zephyr 2>&1 >/dev/null +result=$? + +stop_zephyr +stop_docker + +if [ $result -eq 0 ]; then + return 0 +else + return 1 +fi diff --git a/samples/net/lwm2m_client/overlay-bootstrap.conf b/samples/net/lwm2m_client/overlay-bootstrap.conf index 68308bbd22bc222..5993329cb1ba84f 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-dtls.conf b/samples/net/lwm2m_client/overlay-dtls.conf index d9cf838ddc51939..930230d8ba4b2be 100644 --- a/samples/net/lwm2m_client/overlay-dtls.conf +++ b/samples/net/lwm2m_client/overlay-dtls.conf @@ -1,9 +1,12 @@ +# Enable DTLS with Connection Identifier CONFIG_LWM2M_DTLS_SUPPORT=y +CONFIG_LWM2M_DTLS_CID=y CONFIG_LWM2M_PEER_PORT=5684 # Select Zephyr mbedtls CONFIG_MBEDTLS=y CONFIG_MBEDTLS_TLS_VERSION_1_2=y +CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID=y # Special MbedTLS changes CONFIG_MBEDTLS_ENABLE_HEAP=y diff --git a/samples/net/lwm2m_client/overlay-ot.conf b/samples/net/lwm2m_client/overlay-ot.conf index 38960970f5840fd..0e73d874597c6a6 100644 --- a/samples/net/lwm2m_client/overlay-ot.conf +++ b/samples/net/lwm2m_client/overlay-ot.conf @@ -1,7 +1,7 @@ # Main CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y # Disable TCP and IPv4 (TCP disabled to avoid heavy traffic) CONFIG_NET_TCP=n diff --git a/samples/net/lwm2m_client/overlay-queue.conf b/samples/net/lwm2m_client/overlay-queue.conf index 060767dcb896685..2f2ee2aceaaf89c 100644 --- a/samples/net/lwm2m_client/overlay-queue.conf +++ b/samples/net/lwm2m_client/overlay-queue.conf @@ -1,2 +1,15 @@ CONFIG_LWM2M_QUEUE_MODE_ENABLED=y -CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME=180 + +# 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 +CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME=86400 +# Send update once an hour +CONFIG_LWM2M_UPDATE_PERIOD=3600 diff --git a/samples/net/lwm2m_client/sample.yaml b/samples/net/lwm2m_client/sample.yaml index 8faf0e613e5f17b..9c0cada2c1fa09f 100644 --- a/samples/net/lwm2m_client/sample.yaml +++ b/samples/net/lwm2m_client/sample.yaml @@ -10,6 +10,7 @@ tests: - frdm_k64f - pinnacle_100_dvk - mg100 + - native_sim integration_platforms: - qemu_x86 tags: @@ -18,7 +19,9 @@ tests: sample.net.lwm2m_client.all_objects: harness: net depends_on: netif - platform_allow: qemu_x86 + platform_allow: + - qemu_x86 + - native_sim integration_platforms: - qemu_x86 tags: @@ -43,6 +46,7 @@ tests: - frdm_k64f - pinnacle_100_dvk - mg100 + - native_sim integration_platforms: - qemu_x86 tags: @@ -63,7 +67,9 @@ tests: harness: net depends_on: netif extra_args: OVERLAY_CONFIG=overlay-queue.conf - platform_allow: qemu_x86 + platform_allow: + - qemu_x86 + - native_sim integration_platforms: - qemu_x86 tags: diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index 748f654d9eed78d..2e9792e51eaed54 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -16,6 +16,8 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include +#include +#include #include "modules.h" #define APP_BANNER "Run LWM2M client" @@ -29,6 +31,10 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define CLIENT_FIRMWARE_VER "1.0" #define CLIENT_HW_VER "1.0.1" +/* Macros used to subscribe to specific Zephyr NET management events. */ +#define L4_EVENT_MASK (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED) +#define CONN_LAYER_EVENT_MASK (NET_EVENT_CONN_IF_FATAL_ERROR) + static uint8_t bat_idx = LWM2M_DEVICE_PWR_SRC_TYPE_BAT_INT; static int bat_mv = 3800; static int bat_ma = 125; @@ -52,6 +58,12 @@ BUILD_ASSERT(sizeof(endpoint) <= CONFIG_LWM2M_SECURITY_KEY_SIZE, static struct k_sem quit_lock; +/* Zephyr NET management event callback structures. */ +static struct net_mgmt_event_callback l4_cb; +static struct net_mgmt_event_callback conn_cb; + +static K_SEM_DEFINE(network_connected_sem, 0, 1); + static int device_reboot_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len) { @@ -179,6 +191,10 @@ static void rd_client_event(struct lwm2m_ctx *client, /* do nothing */ break; + case LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED: + LOG_DBG("LwM2M server disabled"); + break; + case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE: LOG_DBG("Bootstrap registration failure!"); break; @@ -237,6 +253,25 @@ static void rd_client_event(struct lwm2m_ctx *client, } } +static void socket_state(int fd, enum lwm2m_socket_states state) +{ + (void) fd; + switch (state) { + case LWM2M_SOCKET_STATE_ONGOING: + LOG_DBG("LWM2M_SOCKET_STATE_ONGOING"); + break; + case LWM2M_SOCKET_STATE_ONE_RESPONSE: + LOG_DBG("LWM2M_SOCKET_STATE_ONE_RESPONSE"); + break; + case LWM2M_SOCKET_STATE_LAST: + LOG_DBG("LWM2M_SOCKET_STATE_LAST"); + break; + case LWM2M_SOCKET_STATE_NO_DATA: + LOG_DBG("LWM2M_SOCKET_STATE_NO_DATA"); + break; + } +} + static void observe_cb(enum lwm2m_observe_event event, struct lwm2m_obj_path *path, void *user_data) { @@ -265,6 +300,47 @@ static void observe_cb(enum lwm2m_observe_event event, } } +static void on_net_event_l4_disconnected(void) +{ + LOG_INF("Disconnected from network"); + lwm2m_engine_pause(); +} + +static void on_net_event_l4_connected(void) +{ + LOG_INF("Connected to network"); + k_sem_give(&network_connected_sem); + lwm2m_engine_resume(); +} + +static void l4_event_handler(struct net_mgmt_event_callback *cb, + uint32_t event, + struct net_if *iface) +{ + switch (event) { + case NET_EVENT_L4_CONNECTED: + LOG_INF("IP Up"); + on_net_event_l4_connected(); + break; + case NET_EVENT_L4_DISCONNECTED: + LOG_INF("IP down"); + on_net_event_l4_disconnected(); + break; + default: + break; + } +} + +static void connectivity_event_handler(struct net_mgmt_event_callback *cb, + uint32_t event, + struct net_if *iface) +{ + if (event == NET_EVENT_CONN_IF_FATAL_ERROR) { + LOG_ERR("Fatal error received from the connectivity layer"); + return; + } +} + int main(void) { uint32_t flags = IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) ? @@ -275,6 +351,31 @@ int main(void) k_sem_init(&quit_lock, 0, K_SEM_MAX_LIMIT); + if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) { + /* Setup handler for Zephyr NET Connection Manager events. */ + net_mgmt_init_event_callback(&l4_cb, l4_event_handler, L4_EVENT_MASK); + net_mgmt_add_event_callback(&l4_cb); + + /* Setup handler for Zephyr NET Connection Manager Connectivity layer. */ + net_mgmt_init_event_callback(&conn_cb, connectivity_event_handler, + CONN_LAYER_EVENT_MASK); + net_mgmt_add_event_callback(&conn_cb); + + ret = net_if_up(net_if_get_default()); + + if (ret < 0 && ret != -EALREADY) { + LOG_ERR("net_if_up, error: %d", ret); + return ret; + } + + ret = conn_mgr_if_connect(net_if_get_default()); + /* Ignore errors from interfaces not requiring connectivity */ + if (ret == 0) { + LOG_INF("Connecting to network"); + k_sem_take(&network_connected_sem, K_FOREVER); + } + } + ret = lwm2m_setup(); if (ret < 0) { LOG_ERR("Cannot setup LWM2M fields (%d)", ret); @@ -285,6 +386,7 @@ int main(void) #if defined(CONFIG_LWM2M_DTLS_SUPPORT) client_ctx.tls_tag = CONFIG_LWM2M_APP_TLS_TAG; #endif + client_ctx.set_socket_state = socket_state; /* client_ctx.sec_obj_inst is 0 as a starting point */ lwm2m_rd_client_start(&client_ctx, endpoint, flags, rd_client_event, observe_cb); diff --git a/samples/net/mdns_responder/CMakeLists.txt b/samples/net/mdns_responder/CMakeLists.txt index 21efc955050f04b..5c4e88178a9227e 100644 --- a/samples/net/mdns_responder/CMakeLists.txt +++ b/samples/net/mdns_responder/CMakeLists.txt @@ -4,7 +4,8 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(mdns_responder) -FILE(GLOB app_sources src/*.c) -target_sources(app PRIVATE ${app_sources}) +target_sources(app PRIVATE src/main.c) +target_sources(app PRIVATE src/service.c) +target_sources_ifdef(CONFIG_NET_VLAN app PRIVATE src/vlan.c) include(${ZEPHYR_BASE}/samples/net/common/common.cmake) diff --git a/samples/net/mdns_responder/Kconfig b/samples/net/mdns_responder/Kconfig new file mode 100644 index 000000000000000..53cc3d2153d4894 --- /dev/null +++ b/samples/net/mdns_responder/Kconfig @@ -0,0 +1,56 @@ +# Private config options for mDNS responder sample app + +# Copyright (c) 2023 NordicNordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "Networking mDNS responder sample application" + +config NET_SAMPLE_IFACE2_MY_IPV6_ADDR + string "My IPv6 address for second interface" + help + The value depends on your network setup. + +config NET_SAMPLE_IFACE2_MY_IPV4_ADDR + string "My IPv4 address for second interface" + help + The value depends on your network setup. + +config NET_SAMPLE_IFACE2_MY_IPV4_NETMASK + string "My IPv4 netmask for second interface" + help + The value depends on your network setup. + +config NET_SAMPLE_IFACE2_VLAN_TAG + int "VLAN tag for second interface" + default 100 + range 0 4094 + depends on NET_VLAN + help + Set VLAN (virtual LAN) tag (id) that is used in the sample + application. + +config NET_SAMPLE_IFACE3_MY_IPV6_ADDR + string "My IPv6 address for third interface" + help + The value depends on your network setup. + +config NET_SAMPLE_IFACE3_MY_IPV4_ADDR + string "My IPv4 address for third interface" + help + The value depends on your network setup. + +config NET_SAMPLE_IFACE3_MY_IPV4_NETMASK + string "My IPv4 netmask for third interface" + help + The value depends on your network setup. + +config NET_SAMPLE_IFACE3_VLAN_TAG + int "VLAN tag for third interface" + default 200 + range 0 4094 + depends on NET_VLAN + help + Set VLAN (virtual LAN) tag (id) that is used in the sample + application. + +source "Kconfig.zephyr" diff --git a/samples/net/mdns_responder/overlay-e1000.conf b/samples/net/mdns_responder/overlay-e1000.conf new file mode 100644 index 000000000000000..d2880bd3587a31e --- /dev/null +++ b/samples/net/mdns_responder/overlay-e1000.conf @@ -0,0 +1,6 @@ +CONFIG_NET_L2_ETHERNET=y +CONFIG_NET_QEMU_ETHERNET=y + +CONFIG_PCIE=y + +#CONFIG_ETHERNET_LOG_LEVEL_DBG=y diff --git a/samples/net/mdns_responder/overlay-vlan.conf b/samples/net/mdns_responder/overlay-vlan.conf new file mode 100644 index 000000000000000..5dfe0f9b8f72a98 --- /dev/null +++ b/samples/net/mdns_responder/overlay-vlan.conf @@ -0,0 +1,34 @@ +CONFIG_NET_VLAN=y + +# We have one non-vlan interface and two VLAN interfaces +CONFIG_NET_VLAN_COUNT=3 + +# There will be three network interfaces. + +# First ethernet interface will use these settings +CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" +CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" + +# Second ethernet interface will have these settings +CONFIG_NET_SAMPLE_IFACE2_MY_IPV6_ADDR="2001:db8:100::1" +# TEST-NET-2 from RFC 5737 +CONFIG_NET_SAMPLE_IFACE2_MY_IPV4_ADDR="198.51.100.1" +CONFIG_NET_SAMPLE_IFACE2_MY_IPV4_NETMASK="255.255.255.0" +# VLAN tag for the second interface +CONFIG_NET_SAMPLE_IFACE2_VLAN_TAG=100 + +# Settings for the third network interface +CONFIG_NET_SAMPLE_IFACE3_MY_IPV6_ADDR="2001:db8:200::1" +# TEST-NET-3 from RFC 5737 +CONFIG_NET_SAMPLE_IFACE3_MY_IPV4_ADDR="203.0.113.1" +CONFIG_NET_SAMPLE_IFACE3_MY_IPV4_NETMASK="255.255.255.0" +# VLAN tag for the second interface +CONFIG_NET_SAMPLE_IFACE3_VLAN_TAG=200 + +# Each interface needs at least 2 context. So if we have three +# interfaces we need minimum 6 context but allocate more so that +# we do not run out of them. +CONFIG_NET_MAX_CONTEXTS=10 +CONFIG_NET_MAX_CONN=10 diff --git a/samples/net/mdns_responder/src/main.c b/samples/net/mdns_responder/src/main.c index 6a4ec48a4ab8869..112f9e93931676d 100644 --- a/samples/net/mdns_responder/src/main.c +++ b/samples/net/mdns_responder/src/main.c @@ -14,6 +14,15 @@ LOG_MODULE_REGISTER(net_mdns_responder_sample, LOG_LEVEL_DBG); extern void service(void); +#if defined(CONFIG_NET_VLAN) +int init_vlan(void); +#else +static inline int init_vlan(void) +{ + return 0; +} +#endif /* CONFIG_NET_VLAN */ + /* * Note that mDNS support requires no application interaction with zephyr, * beyond optional runtime hostname configuration calls and setting @@ -26,6 +35,7 @@ extern void service(void); int main(void) { LOG_INF("Waiting mDNS queries..."); + init_vlan(); service(); return 0; } diff --git a/samples/net/mdns_responder/src/vlan.c b/samples/net/mdns_responder/src/vlan.c new file mode 100644 index 000000000000000..534662c3c6497ac --- /dev/null +++ b/samples/net/mdns_responder/src/vlan.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_mdns_responder_sample, LOG_LEVEL_DBG); + +#include + +#include + +/* User data for the interface callback */ +struct ud { + struct net_if *first; + struct net_if *second; + struct net_if *third; +}; + +static void iface_cb(struct net_if *iface, void *user_data_param) +{ + struct ud *user_data = user_data_param; + + if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) { + return; + } + + if (!user_data->first) { + user_data->first = iface; + return; + } + + if (!user_data->second) { + user_data->second = iface; + return; + } + + if (!user_data->third) { + user_data->third = iface; + return; + } +} + +static int setup_iface(struct net_if *iface, const char *ipv6_addr, + const char *ipv4_addr, const char *netmask, + uint16_t vlan_tag) +{ + struct net_if_addr *ifaddr; + struct in_addr addr4; + struct in6_addr addr6; + int ret; + + ret = net_eth_vlan_enable(iface, vlan_tag); + if (ret < 0) { + LOG_ERR("Cannot enable VLAN for tag %d (%d)", vlan_tag, ret); + } + + if (IS_ENABLED(CONFIG_NET_IPV6)) { + if (net_addr_pton(AF_INET6, ipv6_addr, &addr6)) { + LOG_ERR("Invalid address: %s", ipv6_addr); + return -EINVAL; + } + + ifaddr = net_if_ipv6_addr_add(iface, &addr6, + NET_ADDR_MANUAL, 0); + if (!ifaddr) { + LOG_ERR("Cannot add %s to interface %p", + ipv6_addr, iface); + return -EINVAL; + } + } + + if (IS_ENABLED(CONFIG_NET_IPV4)) { + if (net_addr_pton(AF_INET, ipv4_addr, &addr4)) { + LOG_ERR("Invalid address: %s", ipv4_addr); + return -EINVAL; + } + + ifaddr = net_if_ipv4_addr_add(iface, &addr4, + NET_ADDR_MANUAL, 0); + if (!ifaddr) { + LOG_ERR("Cannot add %s to interface %p", + ipv4_addr, iface); + return -EINVAL; + } + + if (netmask && netmask[0]) { + if (net_addr_pton(AF_INET, netmask, &addr4)) { + LOG_ERR("Invalid netmask: %s", ipv4_addr); + return -EINVAL; + } + + net_if_ipv4_set_netmask(iface, &addr4); + } + } + + LOG_DBG("Interface %p VLAN tag %d setup done.", iface, vlan_tag); + + return 0; +} + +int init_vlan(void) +{ + struct ud user_data; + int ret; + + memset(&user_data, 0, sizeof(user_data)); + + net_if_foreach(iface_cb, &user_data); + + /* This sample has two VLANs. For the second one we need to manually + * create IP address for this test. But first the VLAN needs to be + * added to the interface so that IPv6 DAD can work properly. + */ + ret = setup_iface(user_data.second, + CONFIG_NET_SAMPLE_IFACE2_MY_IPV6_ADDR, + CONFIG_NET_SAMPLE_IFACE2_MY_IPV4_ADDR, + CONFIG_NET_SAMPLE_IFACE2_MY_IPV4_NETMASK, + CONFIG_NET_SAMPLE_IFACE2_VLAN_TAG); + if (ret < 0) { + return ret; + } + + ret = setup_iface(user_data.third, + CONFIG_NET_SAMPLE_IFACE3_MY_IPV6_ADDR, + CONFIG_NET_SAMPLE_IFACE3_MY_IPV4_ADDR, + CONFIG_NET_SAMPLE_IFACE3_MY_IPV4_NETMASK, + CONFIG_NET_SAMPLE_IFACE3_VLAN_TAG); + if (ret < 0) { + return ret; + } + + return 0; +} diff --git a/samples/net/mqtt_sn_publisher/README.rst b/samples/net/mqtt_sn_publisher/README.rst index e78314876501629..48b8dab5dec307c 100644 --- a/samples/net/mqtt_sn_publisher/README.rst +++ b/samples/net/mqtt_sn_publisher/README.rst @@ -67,8 +67,8 @@ Then, locate your zephyr directory and type: .. zephyr-app-commands:: :zephyr-app: samples/net/mqtt_sn_publisher - :board: native_posix_64 - :goals: build -t run + :board: native_sim_64 + :goals: run :compact: Optionally, use any MQTT explorer to connect to your broker. diff --git a/samples/net/mqtt_sn_publisher/boards/native_sim.conf b/samples/net/mqtt_sn_publisher/boards/native_sim.conf new file mode 100644 index 000000000000000..0843e94acbdbdea --- /dev/null +++ b/samples/net/mqtt_sn_publisher/boards/native_sim.conf @@ -0,0 +1 @@ +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/net/mqtt_sn_publisher/boards/native_sim_64.conf b/samples/net/mqtt_sn_publisher/boards/native_sim_64.conf new file mode 100644 index 000000000000000..0843e94acbdbdea --- /dev/null +++ b/samples/net/mqtt_sn_publisher/boards/native_sim_64.conf @@ -0,0 +1 @@ +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/net/mqtt_sn_publisher/sample.yaml b/samples/net/mqtt_sn_publisher/sample.yaml index 5d37a430ba120f6..ca11e3e96f30f94 100644 --- a/samples/net/mqtt_sn_publisher/sample.yaml +++ b/samples/net/mqtt_sn_publisher/sample.yaml @@ -13,5 +13,6 @@ tests: - qemu_x86 - pinnacle_100_dvk - mg100 + - native_sim_64 integration_platforms: - qemu_x86 diff --git a/samples/net/mqtt_sn_publisher/src/common.h b/samples/net/mqtt_sn_publisher/src/common.h index 4b0fef326989a8d..1cfbbc1045079f9 100644 --- a/samples/net/mqtt_sn_publisher/src/common.h +++ b/samples/net/mqtt_sn_publisher/src/common.h @@ -23,4 +23,4 @@ extern struct k_mem_domain app_domain; #define THREAD_PRIORITY K_PRIO_PREEMPT(8) #endif -int start_thread(void); +void start_thread(void); diff --git a/samples/net/mqtt_sn_publisher/src/main.c b/samples/net/mqtt_sn_publisher/src/main.c index 665919ef50a34a6..65436daea4d5354 100644 --- a/samples/net/mqtt_sn_publisher/src/main.c +++ b/samples/net/mqtt_sn_publisher/src/main.c @@ -83,12 +83,16 @@ static void init_app(void) } } -static int start_client(void) +static void start_client(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + /* Wait for connection */ k_sem_take(&run_app, K_FOREVER); - return start_thread(); + start_thread(); } int main(void) @@ -107,9 +111,9 @@ int main(void) k_thread_access_grant(k_current_get(), &run_app); k_mem_domain_add_thread(&app_domain, k_current_get()); - k_thread_user_mode_enter((k_thread_entry_t)start_client, NULL, NULL, NULL); + k_thread_user_mode_enter(start_client, NULL, NULL, NULL); #else - exit(start_client()); + start_client(NULL, NULL, NULL); #endif return 0; } diff --git a/samples/net/mqtt_sn_publisher/src/udp.c b/samples/net/mqtt_sn_publisher/src/udp.c index 32a64fbccbd7f5b..70a09bdb89da49c 100644 --- a/samples/net/mqtt_sn_publisher/src/udp.c +++ b/samples/net/mqtt_sn_publisher/src/udp.c @@ -141,23 +141,28 @@ static void process_thread(void) LOG_ERR("Exiting thread: %d", err); } -int start_thread(void) +void start_thread(void) { int rc; #if defined(CONFIG_USERSPACE) rc = k_mem_domain_add_thread(&app_domain, udp_thread_id); if (rc < 0) { - return rc; + LOG_ERR("Failed: k_mem_domain_add_thread() %d", rc); + return; } #endif rc = k_thread_name_set(udp_thread_id, "udp"); if (rc < 0 && rc != -ENOSYS) { LOG_ERR("Failed: k_thread_name_set() %d", rc); - return rc; + return; } k_thread_start(udp_thread_id); - return k_thread_join(udp_thread_id, K_FOREVER); + rc = k_thread_join(udp_thread_id, K_FOREVER); + + if (rc != 0) { + LOG_ERR("Failed: k_thread_join() %d", rc); + } } diff --git a/samples/net/sockets/big_http_download/Makefile.posix b/samples/net/sockets/big_http_download/Makefile.host similarity index 100% rename from samples/net/sockets/big_http_download/Makefile.posix rename to samples/net/sockets/big_http_download/Makefile.host diff --git a/samples/net/sockets/big_http_download/README.rst b/samples/net/sockets/big_http_download/README.rst index d0b4551648bc02b..b3bf8e7f2e37f18 100644 --- a/samples/net/sockets/big_http_download/README.rst +++ b/samples/net/sockets/big_http_download/README.rst @@ -96,11 +96,11 @@ Running application on POSIX Host The same application source code can be built for a POSIX system, e.g. Linux. -To build for a host POSIX OS: +To build: .. code-block:: console - $ make -f Makefile.posix + $ make -f Makefile.host To run: diff --git a/samples/net/sockets/big_http_download/prj.conf b/samples/net/sockets/big_http_download/prj.conf index 02b7e11d39e9b6a..324eb765af20458 100644 --- a/samples/net/sockets/big_http_download/prj.conf +++ b/samples/net/sockets/big_http_download/prj.conf @@ -1,5 +1,5 @@ # General config -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y CONFIG_MBEDTLS=y CONFIG_MBEDTLS_ENABLE_HEAP=y CONFIG_MAIN_STACK_SIZE=2536 diff --git a/samples/net/sockets/big_http_download/sample.yaml b/samples/net/sockets/big_http_download/sample.yaml index 019f390d2984be5..313d0a135c7f5ad 100644 --- a/samples/net/sockets/big_http_download/sample.yaml +++ b/samples/net/sockets/big_http_download/sample.yaml @@ -2,7 +2,7 @@ sample: description: BSD Sockets big HTTP download example name: big_http_download common: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC harness: net min_ram: 32 min_flash: 128 diff --git a/samples/net/sockets/can/src/main.c b/samples/net/sockets/can/src/main.c index 2f86b63eaf1696e..8bd51984a6427ec 100644 --- a/samples/net/sockets/can/src/main.c +++ b/samples/net/sockets/can/src/main.c @@ -32,15 +32,19 @@ 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 }; static struct socketcan_filter sock_filter; -static void tx(int *can_fd) +static void tx(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + int *can_fd = p1; int fd = POINTER_TO_INT(can_fd); struct can_frame zframe = {0}; struct socketcan_frame sframe = {0}; @@ -95,9 +99,11 @@ static int create_socket(const struct socketcan_filter *sfilter) return fd; } -static void rx(int *can_fd, int *do_close_period, - const struct socketcan_filter *sfilter) +static void rx(void *p1, void *p2, void *p3) { + int *can_fd = p1; + int *do_close_period = p2; + const struct socketcan_filter *sfilter = p3; int close_period = POINTER_TO_INT(do_close_period); int fd = POINTER_TO_INT(can_fd); struct sockaddr_can can_addr; @@ -205,7 +211,7 @@ static int setup_socket(void) /* Delay TX startup so that RX is ready to receive */ tx_tid = k_thread_create(&tx_data, tx_stack, K_THREAD_STACK_SIZEOF(tx_stack), - (k_thread_entry_t)tx, INT_TO_POINTER(fd), + tx, INT_TO_POINTER(fd), NULL, NULL, PRIORITY, 0, K_SECONDS(1)); if (!tx_tid) { ret = -ENOENT; @@ -225,7 +231,7 @@ static int setup_socket(void) if (fd >= 0) { rx_tid = k_thread_create(&rx_data, rx_stack, K_THREAD_STACK_SIZEOF(rx_stack), - (k_thread_entry_t)rx, + rx, INT_TO_POINTER(fd), INT_TO_POINTER(CLOSE_PERIOD), &sock_filter, PRIORITY, 0, K_NO_WAIT); diff --git a/samples/net/sockets/coap_client/README.rst b/samples/net/sockets/coap_client/README.rst index a26d632772bfed1..ffcd81978cc317b 100644 --- a/samples/net/sockets/coap_client/README.rst +++ b/samples/net/sockets/coap_client/README.rst @@ -29,7 +29,7 @@ be obtained by using a tool such as tcpdump or wireshark. See the `net-tools`_ project for more details. -This sample can be built and executed on QEMU or native_posix board as described +This sample can be built and executed on QEMU or native_sim board as described in :ref:`networking_with_host`. Sample output diff --git a/samples/net/sockets/coap_client/prj.conf b/samples/net/sockets/coap_client/prj.conf index 8a513d82a45b678..b0df3759b221330 100644 --- a/samples/net/sockets/coap_client/prj.conf +++ b/samples/net/sockets/coap_client/prj.conf @@ -1,6 +1,6 @@ # Generic networking options CONFIG_NETWORKING=y -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y CONFIG_NET_IPV6=y CONFIG_NET_UDP=y diff --git a/samples/net/sockets/coap_client/sample.yaml b/samples/net/sockets/coap_client/sample.yaml index a1fc20ff391927c..8c822c7604eeb46 100644 --- a/samples/net/sockets/coap_client/sample.yaml +++ b/samples/net/sockets/coap_client/sample.yaml @@ -1,5 +1,5 @@ common: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC sample: description: TBD name: TBD diff --git a/samples/net/sockets/coap_server/CMakeLists.txt b/samples/net/sockets/coap_server/CMakeLists.txt index 97f67d0a3587501..17d207098254be6 100644 --- a/samples/net/sockets/coap_server/CMakeLists.txt +++ b/samples/net/sockets/coap_server/CMakeLists.txt @@ -7,3 +7,5 @@ project(coap_server) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/net/ip) + +zephyr_linker_sources(DATA_SECTIONS sections-ram.ld) diff --git a/samples/net/sockets/coap_server/README.rst b/samples/net/sockets/coap_server/README.rst index 57e4a81880909da..a2962b941bedbaa 100644 --- a/samples/net/sockets/coap_server/README.rst +++ b/samples/net/sockets/coap_server/README.rst @@ -1,13 +1,18 @@ .. zephyr:code-sample:: coap-server - :name: CoAP server - :relevant-api: coap udp + :name: CoAP service + :relevant-api: coap coap_service udp - Use the CoAP library to implement a server that exposes CoAP resources. + Use the CoAP server subsystem to register CoAP resources. Overview ******** -This sample is a simple CoAP server showing how to expose a simple resource. +This sample shows how to register CoAP resources to a main CoAP service. +The CoAP server implementation expects all services and resources to be +available at compile time, as they are put into dedicated sections. + +The resource is placed into the correct linker section based on the owning +service's name. A linker file is required, see ``sections-ram.ld`` for an example. This demo assumes that the platform of choice has networking support, some adjustments to the configuration may be needed. @@ -39,7 +44,7 @@ or wireshark. See the `net-tools`_ project for more details -This sample can be built and executed on QEMU or native_posix board as +This sample can be built and executed on QEMU or native_sim board as described in :ref:`networking_with_host`. Use this command on the host to run the `libcoap`_ implementation of diff --git a/samples/net/sockets/coap_server/boards/native_posix.conf b/samples/net/sockets/coap_server/boards/native_posix.conf new file mode 100644 index 000000000000000..b8f2d57be74311f --- /dev/null +++ b/samples/net/sockets/coap_server/boards/native_posix.conf @@ -0,0 +1,3 @@ +CONFIG_NET_L2_ETHERNET=y +CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME=y +CONFIG_NATIVE_UART_0_ON_STDINOUT=y diff --git a/samples/net/sockets/coap_server/boards/native_posix_64.conf b/samples/net/sockets/coap_server/boards/native_posix_64.conf new file mode 100644 index 000000000000000..b8f2d57be74311f --- /dev/null +++ b/samples/net/sockets/coap_server/boards/native_posix_64.conf @@ -0,0 +1,3 @@ +CONFIG_NET_L2_ETHERNET=y +CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME=y +CONFIG_NATIVE_UART_0_ON_STDINOUT=y diff --git a/samples/net/sockets/coap_server/boards/native_sim.conf b/samples/net/sockets/coap_server/boards/native_sim.conf new file mode 100644 index 000000000000000..ac091ebe5db39e9 --- /dev/null +++ b/samples/net/sockets/coap_server/boards/native_sim.conf @@ -0,0 +1,4 @@ +CONFIG_NET_L2_ETHERNET=y +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y +CONFIG_NATIVE_UART_0_ON_STDINOUT=y +CONFIG_PICOLIBC=y diff --git a/samples/net/sockets/coap_server/boards/native_sim_64.conf b/samples/net/sockets/coap_server/boards/native_sim_64.conf new file mode 100644 index 000000000000000..ac091ebe5db39e9 --- /dev/null +++ b/samples/net/sockets/coap_server/boards/native_sim_64.conf @@ -0,0 +1,4 @@ +CONFIG_NET_L2_ETHERNET=y +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y +CONFIG_NATIVE_UART_0_ON_STDINOUT=y +CONFIG_PICOLIBC=y diff --git a/samples/net/sockets/coap_server/boards/qemu_cortex_m3.conf b/samples/net/sockets/coap_server/boards/qemu_cortex_m3.conf new file mode 100644 index 000000000000000..dc256b47832a2f9 --- /dev/null +++ b/samples/net/sockets/coap_server/boards/qemu_cortex_m3.conf @@ -0,0 +1,4 @@ +CONFIG_NET_L2_ETHERNET=y +CONFIG_ETH_DRIVER=y +CONFIG_ETH_STELLARIS=y +CONFIG_NET_QEMU_ETHERNET=y diff --git a/samples/net/sockets/coap_server/prj.conf b/samples/net/sockets/coap_server/prj.conf index cbe61178b2a65e2..59d444db456663f 100644 --- a/samples/net/sockets/coap_server/prj.conf +++ b/samples/net/sockets/coap_server/prj.conf @@ -1,6 +1,6 @@ # Generic networking options CONFIG_NETWORKING=y -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y CONFIG_NET_UDP=y # Socket @@ -10,6 +10,8 @@ CONFIG_NET_SOCKETS_POLL_MAX=4 # CoAP CONFIG_COAP=y +CONFIG_COAP_SERVER=y +CONFIG_COAP_SERVER_WELL_KNOWN_CORE=y CONFIG_COAP_WELL_KNOWN_BLOCK_WISE=n # Kernel options @@ -22,13 +24,16 @@ CONFIG_NET_LOG=y # Network Shell CONFIG_NET_SHELL=y - -CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_COAP_SERVER_SHELL=y # Configuration CONFIG_NET_CONFIG_SETTINGS=y +# Events +CONFIG_NET_MGMT=y +CONFIG_NET_MGMT_EVENT=y +CONFIG_NET_MGMT_EVENT_INFO=y + # Enable only one protocol, if you enable both sources # won't compile. # IPv6 Support diff --git a/samples/net/sockets/coap_server/sample.yaml b/samples/net/sockets/coap_server/sample.yaml index dacc6e02ab02f28..2fcf9b6328714cb 100644 --- a/samples/net/sockets/coap_server/sample.yaml +++ b/samples/net/sockets/coap_server/sample.yaml @@ -1,12 +1,14 @@ common: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC sample: - description: TBD - name: TBD + description: BSD Sockets API CoAP server example + name: socket_coap_server tests: sample.net.sockets.coap_server: harness: net tags: - net - socket - platform_allow: qemu_x86 + platform_allow: + - native_sim + - qemu_x86 diff --git a/samples/net/sockets/coap_server/sections-ram.ld b/samples/net/sockets/coap_server/sections-ram.ld new file mode 100644 index 000000000000000..04534264195305d --- /dev/null +++ b/samples/net/sockets/coap_server/sections-ram.ld @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include + +ITERABLE_SECTION_RAM(coap_resource_coap_server, 4) diff --git a/samples/net/sockets/coap_server/src/coap-server.c b/samples/net/sockets/coap_server/src/coap-server.c deleted file mode 100644 index ce47e31a2455e8b..000000000000000 --- a/samples/net/sockets/coap_server/src/coap-server.c +++ /dev/null @@ -1,1466 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_REGISTER(net_coap_server_sample, LOG_LEVEL_DBG); - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "net_private.h" -#if defined(CONFIG_NET_IPV6) -#include "ipv6.h" -#endif - -#define MAX_RETRANSMIT_COUNT 2 - -#define MAX_COAP_MSG_LEN 256 - -#define MY_COAP_PORT 5683 - -#define BLOCK_WISE_TRANSFER_SIZE_GET 2048 - -#if defined(CONFIG_NET_IPV6) -#define ALL_NODES_LOCAL_COAP_MCAST \ - { { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfd } } } - -#define MY_IP6ADDR \ - { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } } -#endif - -#define ADDRLEN(sock) \ - (((struct sockaddr *)sock)->sa_family == AF_INET ? \ - sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) - -#define NUM_OBSERVERS 3 - -#define NUM_PENDINGS 10 - -/* CoAP socket fd */ -static int sock; - -static struct coap_observer observers[NUM_OBSERVERS]; - -static struct coap_pending pendings[NUM_PENDINGS]; - -static struct k_work_delayable observer_work; - -static int obs_counter; - -static struct coap_resource *resource_to_notify; - -static struct k_work_delayable retransmit_work; - -#if defined(CONFIG_NET_IPV6) -static bool join_coap_multicast_group(void) -{ - static struct in6_addr my_addr = MY_IP6ADDR; - static struct sockaddr_in6 mcast_addr = { - .sin6_family = AF_INET6, - .sin6_addr = ALL_NODES_LOCAL_COAP_MCAST, - .sin6_port = htons(MY_COAP_PORT) }; - struct net_if_addr *ifaddr; - struct net_if *iface; - int ret; - - iface = net_if_get_default(); - if (!iface) { - LOG_ERR("Could not get te default interface\n"); - return false; - } - -#if defined(CONFIG_NET_CONFIG_SETTINGS) - if (net_addr_pton(AF_INET6, - CONFIG_NET_CONFIG_MY_IPV6_ADDR, - &my_addr) < 0) { - LOG_ERR("Invalid IPv6 address %s", - CONFIG_NET_CONFIG_MY_IPV6_ADDR); - } -#endif - - ifaddr = net_if_ipv6_addr_add(iface, &my_addr, NET_ADDR_MANUAL, 0); - if (!ifaddr) { - LOG_ERR("Could not add unicast address to interface"); - return false; - } - - ifaddr->addr_state = NET_ADDR_PREFERRED; - - ret = net_ipv6_mld_join(iface, &mcast_addr.sin6_addr); - if (ret < 0) { - LOG_ERR("Cannot join %s IPv6 multicast group (%d)", - net_sprint_ipv6_addr(&mcast_addr.sin6_addr), ret); - return false; - } - - return true; -} -#endif - -#if defined(CONFIG_NET_IPV6) -static int start_coap_server(void) -{ - struct sockaddr_in6 addr6; - int r; - - memset(&addr6, 0, sizeof(addr6)); - addr6.sin6_family = AF_INET6; - addr6.sin6_port = htons(MY_COAP_PORT); - - sock = socket(addr6.sin6_family, SOCK_DGRAM, IPPROTO_UDP); - if (sock < 0) { - LOG_ERR("Failed to create UDP socket %d", errno); - return -errno; - } - - r = bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)); - if (r < 0) { - LOG_ERR("Failed to bind UDP socket %d", errno); - return -errno; - } - - return 0; -} -#endif - -#if defined(CONFIG_NET_IPV4) -static int start_coap_server(void) -{ - struct sockaddr_in addr; - int r; - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(MY_COAP_PORT); - - sock = socket(addr.sin_family, SOCK_DGRAM, IPPROTO_UDP); - if (sock < 0) { - LOG_ERR("Failed to create UDP socket %d", errno); - return -errno; - } - - r = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); - if (r < 0) { - LOG_ERR("Failed to bind UDP socket %d", errno); - return -errno; - } - - return 0; -} -#endif - -static int send_coap_reply(struct coap_packet *cpkt, - const struct sockaddr *addr, - socklen_t addr_len) -{ - int r; - - net_hexdump("Response", cpkt->data, cpkt->offset); - - r = sendto(sock, cpkt->data, cpkt->offset, 0, addr, addr_len); - if (r < 0) { - LOG_ERR("Failed to send %d", errno); - r = -errno; - } - - return r; -} - -static int well_known_core_get(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - struct coap_packet response; - uint8_t *data; - int r; - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_well_known_core_get(resource, request, &response, - data, MAX_COAP_MSG_LEN); - if (r < 0) { - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int piggyback_get(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - struct coap_packet response; - uint8_t payload[40]; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint16_t id; - uint8_t code; - uint8_t type; - uint8_t tkl; - int r; - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - if (type == COAP_TYPE_CON) { - type = COAP_TYPE_ACK; - } else { - type = COAP_TYPE_NON_CON; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_CONTENT, id); - if (r < 0) { - goto end; - } - - r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, - COAP_CONTENT_FORMAT_TEXT_PLAIN); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload_marker(&response); - if (r < 0) { - goto end; - } - - /* The response that coap-client expects */ - r = snprintk((char *) payload, sizeof(payload), - "Type: %u\nCode: %u\nMID: %u\n", type, code, id); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload(&response, (uint8_t *)payload, - strlen(payload)); - if (r < 0) { - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int test_del(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - struct coap_packet response; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint8_t tkl; - uint8_t code; - uint8_t type; - uint16_t id; - int r; - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - if (type == COAP_TYPE_CON) { - type = COAP_TYPE_ACK; - } else { - type = COAP_TYPE_NON_CON; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_DELETED, id); - if (r < 0) { - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int test_put(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - struct coap_packet response; - uint8_t token[COAP_TOKEN_MAX_LEN]; - const uint8_t *payload; - uint8_t *data; - uint16_t payload_len; - uint8_t code; - uint8_t type; - uint8_t tkl; - uint16_t id; - int r; - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - payload = coap_packet_get_payload(request, &payload_len); - if (payload) { - net_hexdump("PUT Payload", payload, payload_len); - } - - if (type == COAP_TYPE_CON) { - type = COAP_TYPE_ACK; - } else { - type = COAP_TYPE_NON_CON; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_CHANGED, id); - if (r < 0) { - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int test_post(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - static const char * const location_path[] = { "location1", - "location2", - "location3", - NULL }; - const char * const *p; - struct coap_packet response; - uint8_t token[COAP_TOKEN_MAX_LEN]; - const uint8_t *payload; - uint8_t *data; - uint16_t payload_len; - uint8_t code; - uint8_t type; - uint8_t tkl; - uint16_t id; - int r; - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - payload = coap_packet_get_payload(request, &payload_len); - if (payload) { - net_hexdump("POST Payload", payload, payload_len); - } - - if (type == COAP_TYPE_CON) { - type = COAP_TYPE_ACK; - } else { - type = COAP_TYPE_NON_CON; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_CREATED, id); - if (r < 0) { - goto end; - } - - for (p = location_path; *p; p++) { - r = coap_packet_append_option(&response, - COAP_OPTION_LOCATION_PATH, - *p, strlen(*p)); - if (r < 0) { - goto end; - } - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int query_get(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - struct coap_option options[4]; - struct coap_packet response; - uint8_t payload[40]; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint16_t id; - uint8_t code; - uint8_t type; - uint8_t tkl; - int i, r; - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - r = coap_find_options(request, COAP_OPTION_URI_QUERY, options, 4); - if (r < 0) { - return -EINVAL; - } - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("num queries: %d", r); - - for (i = 0; i < r; i++) { - char str[16]; - - if (options[i].len + 1 > sizeof(str)) { - LOG_INF("Unexpected length of query: " - "%d (expected %zu)", - options[i].len, sizeof(str)); - break; - } - - memcpy(str, options[i].value, options[i].len); - str[options[i].len] = '\0'; - - LOG_INF("query[%d]: %s", i + 1, str); - } - - LOG_INF("*******"); - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, - COAP_RESPONSE_CODE_CONTENT, id); - if (r < 0) { - goto end; - } - - r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, - COAP_CONTENT_FORMAT_TEXT_PLAIN); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload_marker(&response); - if (r < 0) { - goto end; - } - - /* The response that coap-client expects */ - r = snprintk((char *) payload, sizeof(payload), - "Type: %u\nCode: %u\nMID: %u\n", type, code, id); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload(&response, (uint8_t *)payload, - strlen(payload)); - if (r < 0) { - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int location_query_post(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - static const char *const location_query[] = { "first=1", - "second=2", - NULL }; - const char * const *p; - struct coap_packet response; - uint8_t *data; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint16_t id; - uint8_t code; - uint8_t type; - uint8_t tkl; - int r; - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - if (type == COAP_TYPE_CON) { - type = COAP_TYPE_ACK; - } else { - type = COAP_TYPE_NON_CON; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_CREATED, id); - if (r < 0) { - goto end; - } - - for (p = location_query; *p; p++) { - r = coap_packet_append_option(&response, - COAP_OPTION_LOCATION_QUERY, - *p, strlen(*p)); - if (r < 0) { - goto end; - } - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int separate_get(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - struct coap_packet response; - uint8_t payload[40]; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint16_t id; - uint8_t code; - uint8_t type; - uint8_t tkl; - int r; - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - if (type == COAP_TYPE_ACK) { - return 0; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, 0, id); - if (r < 0) { - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - if (r < 0) { - goto end; - } - - if (type == COAP_TYPE_CON) { - type = COAP_TYPE_CON; - } else { - type = COAP_TYPE_NON_CON; - } - - /* Do not free and allocate "data" again, re-use the buffer */ - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_CONTENT, id); - if (r < 0) { - goto end; - } - - r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, - COAP_CONTENT_FORMAT_TEXT_PLAIN); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload_marker(&response); - if (r < 0) { - goto end; - } - - /* The response that coap-client expects */ - r = snprintk((char *) payload, sizeof(payload), - "Type: %u\nCode: %u\nMID: %u\n", type, code, id); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload(&response, (uint8_t *)payload, - strlen(payload)); - if (r < 0) { - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int large_get(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) - -{ - static struct coap_block_context ctx; - struct coap_packet response; - uint8_t payload[64]; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint16_t size; - uint16_t id; - uint8_t code; - uint8_t type; - uint8_t tkl; - int r; - - if (ctx.total_size == 0) { - coap_block_transfer_init(&ctx, COAP_BLOCK_64, - BLOCK_WISE_TRANSFER_SIZE_GET); - } - - r = coap_update_from_block(request, &ctx); - if (r < 0) { - return -EINVAL; - } - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, - COAP_RESPONSE_CODE_CONTENT, id); - if (r < 0) { - return -EINVAL; - } - - r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, - COAP_CONTENT_FORMAT_TEXT_PLAIN); - if (r < 0) { - goto end; - } - - r = coap_append_block2_option(&response, &ctx); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload_marker(&response); - if (r < 0) { - goto end; - } - - size = MIN(coap_block_size_to_bytes(ctx.block_size), - ctx.total_size - ctx.current); - - memset(payload, 'A', MIN(size, sizeof(payload))); - - r = coap_packet_append_payload(&response, (uint8_t *)payload, size); - if (r < 0) { - goto end; - } - - r = coap_next_block(&response, &ctx); - if (!r) { - /* Will return 0 when it's the last block. */ - memset(&ctx, 0, sizeof(ctx)); - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int large_update_put(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - static struct coap_block_context ctx; - struct coap_packet response; - const uint8_t *payload; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint16_t id; - uint16_t len; - uint8_t code; - uint8_t type; - uint8_t tkl; - int r; - bool last_block; - - r = coap_get_option_int(request, COAP_OPTION_BLOCK1); - if (r < 0) { - return -EINVAL; - } - - last_block = !GET_MORE(r); - - /* initialize block context upon the arrival of first block */ - if (!GET_BLOCK_NUM(r)) { - coap_block_transfer_init(&ctx, COAP_BLOCK_64, 0); - } - - r = coap_update_from_block(request, &ctx); - if (r < 0) { - LOG_ERR("Invalid block size option from request"); - return -EINVAL; - } - - payload = coap_packet_get_payload(request, &len); - if (!last_block && payload == NULL) { - LOG_ERR("Packet without payload"); - return -EINVAL; - } - - LOG_INF("**************"); - LOG_INF("[ctx] current %zu block_size %u total_size %zu", - ctx.current, coap_block_size_to_bytes(ctx.block_size), - ctx.total_size); - LOG_INF("**************"); - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - /* Do something with the payload */ - - if (!last_block) { - code = COAP_RESPONSE_CODE_CONTINUE; - } else { - code = COAP_RESPONSE_CODE_CHANGED; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, - code, id); - if (r < 0) { - goto end; - } - - r = coap_append_block1_option(&response, &ctx); - if (r < 0) { - LOG_ERR("Could not add Block1 option to response"); - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static int large_create_post(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - static struct coap_block_context ctx; - struct coap_packet response; - const uint8_t *payload; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint16_t len; - uint16_t id; - uint8_t code; - uint8_t type; - uint8_t tkl; - int r; - bool last_block; - - r = coap_get_option_int(request, COAP_OPTION_BLOCK1); - if (r < 0) { - return -EINVAL; - } - - last_block = !GET_MORE(r); - - /* initialize block context upon the arrival of first block */ - if (!GET_BLOCK_NUM(r)) { - coap_block_transfer_init(&ctx, COAP_BLOCK_32, 0); - } - - r = coap_update_from_block(request, &ctx); - if (r < 0) { - LOG_ERR("Invalid block size option from request"); - return -EINVAL; - } - - payload = coap_packet_get_payload(request, &len); - if (!last_block && payload) { - LOG_ERR("Packet without payload"); - return -EINVAL; - } - - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - if (!last_block) { - code = COAP_RESPONSE_CODE_CONTINUE; - } else { - code = COAP_RESPONSE_CODE_CREATED; - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, - code, id); - if (r < 0) { - goto end; - } - - r = coap_append_block1_option(&response, &ctx); - if (r < 0) { - LOG_ERR("Could not add Block1 option to response"); - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static void schedule_next_retransmission(void) -{ - struct coap_pending *pending; - int64_t remaining; - int64_t now = k_uptime_get(); - - /* Get the first pending retransmission to expire after cycling. */ - pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS); - if (!pending) { - return; - } - - remaining = pending->t0 + pending->timeout - now; - if (remaining < 0) { - remaining = 0; - } - - k_work_reschedule(&retransmit_work, K_MSEC(remaining)); -} - -static void remove_observer(struct sockaddr *addr); - -static void retransmit_request(struct k_work *work) -{ - struct coap_pending *pending; - int r; - - pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS); - if (!pending) { - return; - } - - if (!coap_pending_cycle(pending)) { - remove_observer(&pending->addr); - k_free(pending->data); - coap_pending_clear(pending); - } else { - net_hexdump("Retransmit", pending->data, pending->len); - - r = sendto(sock, pending->data, pending->len, 0, - &pending->addr, ADDRLEN(&pending->addr)); - if (r < 0) { - LOG_ERR("Failed to send %d", errno); - } - } - - schedule_next_retransmission(); -} - -static void update_counter(struct k_work *work) -{ - obs_counter++; - - if (resource_to_notify) { - coap_resource_notify(resource_to_notify); - } - - k_work_reschedule(&observer_work, K_SECONDS(5)); -} - -static int create_pending_request(struct coap_packet *response, - const struct sockaddr *addr) -{ - struct coap_pending *pending; - int r; - - pending = coap_pending_next_unused(pendings, NUM_PENDINGS); - if (!pending) { - return -ENOMEM; - } - - r = coap_pending_init(pending, response, addr, MAX_RETRANSMIT_COUNT); - if (r < 0) { - return -EINVAL; - } - - coap_pending_cycle(pending); - - schedule_next_retransmission(); - - return 0; -} - -static int send_notification_packet(const struct sockaddr *addr, - socklen_t addr_len, - uint16_t age, uint16_t id, - const uint8_t *token, uint8_t tkl, - bool is_response) -{ - struct coap_packet response; - char payload[14]; - uint8_t *data; - uint8_t type; - int r; - - if (is_response) { - type = COAP_TYPE_ACK; - } else { - type = COAP_TYPE_CON; - } - - if (!is_response) { - id = coap_next_id(); - } - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_CONTENT, id); - if (r < 0) { - goto end; - } - - if (age >= 2U) { - r = coap_append_option_int(&response, COAP_OPTION_OBSERVE, age); - if (r < 0) { - goto end; - } - } - - r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, - COAP_CONTENT_FORMAT_TEXT_PLAIN); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload_marker(&response); - if (r < 0) { - goto end; - } - - /* The response that coap-client expects */ - r = snprintk((char *) payload, sizeof(payload), - "Counter: %d\n", obs_counter); - if (r < 0) { - goto end; - } - - r = coap_packet_append_payload(&response, (uint8_t *)payload, - strlen(payload)); - if (r < 0) { - goto end; - } - - if (type == COAP_TYPE_CON) { - r = create_pending_request(&response, addr); - if (r < 0) { - goto end; - } - } - - k_work_reschedule(&observer_work, K_SECONDS(5)); - - r = send_coap_reply(&response, addr, addr_len); - - /* On successful creation of pending request, do not free memory */ - if (type == COAP_TYPE_CON) { - return r; - } - -end: - k_free(data); - - return r; -} - -static int obs_get(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - struct coap_observer *observer; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint16_t id; - uint8_t code; - uint8_t type; - uint8_t tkl; - bool observe = true; - - if (!coap_request_is_observe(request)) { - if (coap_get_option_int(request, COAP_OPTION_OBSERVE) == 1) { - remove_observer(addr); - } - observe = false; - goto done; - } - - observer = coap_observer_next_unused(observers, NUM_OBSERVERS); - if (!observer) { - LOG_ERR("Not enough observer slots."); - return -ENOMEM; - } - - coap_observer_init(observer, request, addr); - - coap_register_observer(resource, observer); - - resource_to_notify = resource; - -done: - code = coap_header_get_code(request); - type = coap_header_get_type(request); - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - LOG_INF("*******"); - LOG_INF("type: %u code %u id %u", type, code, id); - LOG_INF("*******"); - - return send_notification_packet(addr, addr_len, - observe ? resource->age : 0, - id, token, tkl, true); -} - -static void obs_notify(struct coap_resource *resource, - struct coap_observer *observer) -{ - send_notification_packet(&observer->addr, - sizeof(observer->addr), - resource->age, 0, - observer->token, observer->tkl, false); -} - -static int core_get(struct coap_resource *resource, - struct coap_packet *request, - struct sockaddr *addr, socklen_t addr_len) -{ - static const char dummy_str[] = "Just a test\n"; - struct coap_packet response; - uint8_t token[COAP_TOKEN_MAX_LEN]; - uint8_t *data; - uint16_t id; - uint8_t tkl; - int r; - - id = coap_header_get_id(request); - tkl = coap_header_get_token(request, token); - - data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); - if (!data) { - return -ENOMEM; - } - - r = coap_packet_init(&response, data, MAX_COAP_MSG_LEN, - COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, - COAP_RESPONSE_CODE_CONTENT, id); - if (r < 0) { - r = -EINVAL; - goto end; - } - - r = coap_packet_append_payload_marker(&response); - if (r < 0) { - r = -EINVAL; - goto end; - } - - r = coap_packet_append_payload(&response, (uint8_t *)dummy_str, - sizeof(dummy_str)); - if (r < 0) { - r = -EINVAL; - goto end; - } - - r = send_coap_reply(&response, addr, addr_len); - -end: - k_free(data); - - return r; -} - -static const char * const test_path[] = { "test", NULL }; - -static const char * const segments_path[] = { "seg1", "seg2", "seg3", NULL }; - -#if defined(CONFIG_COAP_URI_WILDCARD) -static const char * const wildcard1_path[] = { "wild1", "+", "wild3", NULL }; - -static const char * const wildcard2_path[] = { "wild2", "#", NULL }; -#endif /* CONFIG_COAP_URI_WILDCARD */ - -static const char * const query_path[] = { "query", NULL }; - -static const char * const separate_path[] = { "separate", NULL }; - -static const char * const location_query_path[] = { "location-query", NULL }; - -static const char * const large_path[] = { "large", NULL }; - -static const char * const large_update_path[] = { "large-update", NULL }; - -static const char * const large_create_path[] = { "large-create", NULL }; - -static const char * const obs_path[] = { "obs", NULL }; - -static const char * const core_1_path[] = { "core1", NULL }; -static const char * const core_1_attributes[] = { - "title=\"Core 1\"", - "rt=core1", - NULL }; - -static const char * const core_2_path[] = { "core2", NULL }; -static const char * const core_2_attributes[] = { - "title=\"Core 1\"", - "rt=core1", - NULL }; - -static struct coap_resource coap_resources[] = { - { .get = well_known_core_get, - .path = COAP_WELL_KNOWN_CORE_PATH, - }, - { .get = piggyback_get, - .post = test_post, - .del = test_del, - .put = test_put, - .path = test_path - }, - { .get = piggyback_get, - .path = segments_path, - }, -#if defined(CONFIG_COAP_URI_WILDCARD) - { .get = piggyback_get, - .path = wildcard1_path, - }, - { .get = piggyback_get, - .path = wildcard2_path, - }, -#endif /* CONFIG_COAP_URI_WILDCARD */ - { .get = query_get, - .path = query_path, - }, - { .get = separate_get, - .path = separate_path, - }, - { .path = location_query_path, - .post = location_query_post, - }, - { .path = large_path, - .get = large_get, - }, - { .path = large_update_path, - .put = large_update_put, - }, - { .path = large_create_path, - .post = large_create_post, - }, - { .path = obs_path, - .get = obs_get, - .notify = obs_notify, - }, - { .get = core_get, - .path = core_1_path, - .user_data = &((struct coap_core_metadata) { - .attributes = core_1_attributes, - }), - }, - { .get = core_get, - .path = core_2_path, - .user_data = &((struct coap_core_metadata) { - .attributes = core_2_attributes, - }), - }, - { }, -}; - -static struct coap_resource *find_resource_by_observer( - struct coap_resource *resources, struct coap_observer *o) -{ - struct coap_resource *r; - - for (r = resources; r && r->path; r++) { - sys_snode_t *node; - - SYS_SLIST_FOR_EACH_NODE(&r->observers, node) { - if (&o->list == node) { - return r; - } - } - } - - return NULL; -} - -static void remove_observer(struct sockaddr *addr) -{ - struct coap_resource *r; - struct coap_observer *o; - - o = coap_find_observer_by_addr(observers, NUM_OBSERVERS, addr); - if (!o) { - return; - } - - r = find_resource_by_observer(coap_resources, o); - if (!r) { - LOG_ERR("Observer found but Resource not found\n"); - return; - } - - LOG_INF("Removing observer %p", o); - - coap_remove_observer(r, o); - memset(o, 0, sizeof(struct coap_observer)); -} - -static void process_coap_request(uint8_t *data, uint16_t data_len, - struct sockaddr *client_addr, - socklen_t client_addr_len) -{ - struct coap_packet request; - struct coap_pending *pending; - struct coap_option options[16] = { 0 }; - uint8_t opt_num = 16U; - uint8_t type; - int r; - - r = coap_packet_parse(&request, data, data_len, options, opt_num); - if (r < 0) { - LOG_ERR("Invalid data received (%d)\n", r); - return; - } - - type = coap_header_get_type(&request); - - pending = coap_pending_received(&request, pendings, NUM_PENDINGS); - if (!pending) { - goto not_found; - } - - /* Clear CoAP pending request */ - if (type == COAP_TYPE_ACK || type == COAP_TYPE_RESET) { - k_free(pending->data); - coap_pending_clear(pending); - - if (type == COAP_TYPE_RESET) { - remove_observer(client_addr); - } - } - - return; - -not_found: - r = coap_handle_request(&request, coap_resources, options, opt_num, - client_addr, client_addr_len); - if (r < 0) { - LOG_WRN("No handler for such request (%d)\n", r); - } -} - -static int process_client_request(void) -{ - int received; - struct sockaddr client_addr; - socklen_t client_addr_len; - uint8_t request[MAX_COAP_MSG_LEN]; - - do { - client_addr_len = sizeof(client_addr); - received = recvfrom(sock, request, sizeof(request), 0, - &client_addr, &client_addr_len); - if (received < 0) { - LOG_ERR("Connection error %d", errno); - return -errno; - } - - process_coap_request(request, received, &client_addr, - client_addr_len); - } while (true); - - return 0; -} - -int main(void) -{ - int r; - - LOG_DBG("Start CoAP-server sample"); - -#if defined(CONFIG_NET_IPV6) - bool res; - - res = join_coap_multicast_group(); - if (!res) { - goto quit; - } -#endif - - r = start_coap_server(); - if (r < 0) { - goto quit; - } - - k_work_init_delayable(&retransmit_work, retransmit_request); - k_work_init_delayable(&observer_work, update_counter); - - while (1) { - r = process_client_request(); - if (r < 0) { - goto quit; - } - } - - LOG_DBG("Done"); - return 0; - -quit: - LOG_ERR("Quit"); - return 0; -} diff --git a/samples/net/sockets/coap_server/src/core.c b/samples/net/sockets/coap_server/src/core.c new file mode 100644 index 000000000000000..00f4adb4d34908c --- /dev/null +++ b/samples/net/sockets/coap_server/src/core.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include +#include + +static int core_get(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + static const char dummy_str[] = "Just a test\n"; + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint8_t tkl; + int r; + + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload(&response, (uint8_t *)dummy_str, + sizeof(dummy_str)); + if (r < 0) { + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len, NULL); + + return r; +} + +static const char * const core_1_path[] = { "core1", NULL }; +static const char * const core_1_attributes[] = { + "title=\"Core 1\"", + "rt=core1", + NULL, +}; +COAP_RESOURCE_DEFINE(core_1, coap_server, +{ + .get = core_get, + .path = core_1_path, + .user_data = &((struct coap_core_metadata) { + .attributes = core_1_attributes, + }), +}); + +static const char * const core_2_path[] = { "core2", NULL }; +static const char * const core_2_attributes[] = { + "title=\"Core 2\"", + "rt=core2", + NULL, +}; +COAP_RESOURCE_DEFINE(core_2, coap_server, +{ + .get = core_get, + .path = core_2_path, + .user_data = &((struct coap_core_metadata) { + .attributes = core_2_attributes, + }), +}); diff --git a/samples/net/sockets/coap_server/src/events.c b/samples/net/sockets/coap_server/src/events.c new file mode 100644 index 000000000000000..3f843fba0171d96 --- /dev/null +++ b/samples/net/sockets/coap_server/src/events.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#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) +{ + ARG_UNUSED(iface); + ARG_UNUSED(user_data); + + switch (mgmt_event) { + case NET_EVENT_COAP_OBSERVER_ADDED: + LOG_INF("CoAP observer added"); + break; + case NET_EVENT_COAP_OBSERVER_REMOVED: + LOG_INF("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; + + LOG_INF("CoAP service %s started", net_event->service->name); + } else { + LOG_INF("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; + + LOG_INF("CoAP service %s stopped", net_event->service->name); + } else { + LOG_INF("CoAP service stopped"); + } + break; + } +} + +NET_MGMT_REGISTER_EVENT_HANDLER(coap_events, COAP_EVENTS_SET, coap_event_handler, NULL); diff --git a/samples/net/sockets/coap_server/src/large.c b/samples/net/sockets/coap_server/src/large.c new file mode 100644 index 000000000000000..8656a5b53b1448d --- /dev/null +++ b/samples/net/sockets/coap_server/src/large.c @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include + +#define BLOCK_WISE_TRANSFER_SIZE_GET 2048 + +static int large_get(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) + +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + static struct coap_block_context ctx; + struct coap_packet response; + uint8_t payload[64]; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t size; + uint16_t id; + uint8_t code; + uint8_t type; + uint8_t tkl; + int r; + + if (ctx.total_size == 0) { + coap_block_transfer_init(&ctx, COAP_BLOCK_64, BLOCK_WISE_TRANSFER_SIZE_GET); + } + + r = coap_update_from_block(request, &ctx); + if (r < 0) { + return -EINVAL; + } + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return -EINVAL; + } + + r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, + COAP_CONTENT_FORMAT_TEXT_PLAIN); + if (r < 0) { + return r; + } + + r = coap_append_block2_option(&response, &ctx); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + return r; + } + + size = MIN(coap_block_size_to_bytes(ctx.block_size), + ctx.total_size - ctx.current); + + memset(payload, 'A', MIN(size, sizeof(payload))); + + r = coap_packet_append_payload(&response, (uint8_t *)payload, size); + if (r < 0) { + return r; + } + + r = coap_next_block(&response, &ctx); + if (!r) { + /* Will return 0 when it's the last block. */ + memset(&ctx, 0, sizeof(ctx)); + } + + r = coap_resource_send(resource, &response, addr, addr_len, NULL); + + return r; +} + +static int large_update_put(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + static struct coap_block_context ctx; + struct coap_packet response; + const uint8_t *payload; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint16_t len; + uint8_t code; + uint8_t type; + uint8_t tkl; + int r; + bool last_block; + + r = coap_get_option_int(request, COAP_OPTION_BLOCK1); + if (r < 0) { + return -EINVAL; + } + + last_block = !GET_MORE(r); + + /* initialize block context upon the arrival of first block */ + if (!GET_BLOCK_NUM(r)) { + coap_block_transfer_init(&ctx, COAP_BLOCK_64, 0); + } + + r = coap_update_from_block(request, &ctx); + if (r < 0) { + LOG_ERR("Invalid block size option from request"); + return -EINVAL; + } + + payload = coap_packet_get_payload(request, &len); + if (!last_block && payload == NULL) { + LOG_ERR("Packet without payload"); + return -EINVAL; + } + + LOG_INF("**************"); + LOG_INF("[ctx] current %zu block_size %u total_size %zu", + ctx.current, coap_block_size_to_bytes(ctx.block_size), + ctx.total_size); + LOG_INF("**************"); + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + /* Do something with the payload */ + + if (!last_block) { + code = COAP_RESPONSE_CODE_CONTINUE; + } else { + code = COAP_RESPONSE_CODE_CHANGED; + } + + r = coap_ack_init(&response, request, data, sizeof(data), code); + if (r < 0) { + return r; + } + + r = coap_append_block1_option(&response, &ctx); + if (r < 0) { + LOG_ERR("Could not add Block1 option to response"); + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len, NULL); + + return r; +} + +static int large_create_post(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + static struct coap_block_context ctx; + struct coap_packet response; + const uint8_t *payload; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t len; + uint16_t id; + uint8_t code; + uint8_t type; + uint8_t tkl; + int r; + bool last_block; + + r = coap_get_option_int(request, COAP_OPTION_BLOCK1); + if (r < 0) { + return -EINVAL; + } + + last_block = !GET_MORE(r); + + /* initialize block context upon the arrival of first block */ + if (!GET_BLOCK_NUM(r)) { + coap_block_transfer_init(&ctx, COAP_BLOCK_32, 0); + } + + r = coap_update_from_block(request, &ctx); + if (r < 0) { + LOG_ERR("Invalid block size option from request"); + return -EINVAL; + } + + payload = coap_packet_get_payload(request, &len); + if (!last_block && payload) { + LOG_ERR("Packet without payload"); + return -EINVAL; + } + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + if (!last_block) { + code = COAP_RESPONSE_CODE_CONTINUE; + } else { + code = COAP_RESPONSE_CODE_CREATED; + } + + r = coap_ack_init(&response, request, data, sizeof(data), code); + if (r < 0) { + return r; + } + + r = coap_append_block1_option(&response, &ctx); + if (r < 0) { + LOG_ERR("Could not add Block1 option to response"); + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len, NULL); + + return r; +} + +static const char * const large_path[] = { "large", NULL }; +COAP_RESOURCE_DEFINE(large, coap_server, +{ + .get = large_get, + .path = large_path, +}); + +static const char * const large_update_path[] = { "large-update", NULL }; +COAP_RESOURCE_DEFINE(large_update, coap_server, +{ + .put = large_update_put, + .path = large_update_path, +}); + +static const char * const large_create_path[] = { "large-create", NULL }; +COAP_RESOURCE_DEFINE(large_create, coap_server, +{ + .post = large_create_post, + .path = large_create_path, +}); diff --git a/samples/net/sockets/coap_server/src/location_query.c b/samples/net/sockets/coap_server/src/location_query.c new file mode 100644 index 000000000000000..bce4eb67b862b48 --- /dev/null +++ b/samples/net/sockets/coap_server/src/location_query.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include + +static int location_query_post(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + static const char *const location_query[] = { "first=1", + "second=2", + NULL }; + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + const char * const *p; + struct coap_packet response; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint8_t code; + uint8_t type; + uint8_t tkl; + int r; + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CREATED, id); + if (r < 0) { + return r; + } + + for (p = location_query; *p; p++) { + r = coap_packet_append_option(&response, + COAP_OPTION_LOCATION_QUERY, + *p, strlen(*p)); + if (r < 0) { + return r; + } + } + + r = coap_resource_send(resource, &response, addr, addr_len, NULL); + + return r; +} + +static const char * const location_query_path[] = { "location-query", NULL }; +COAP_RESOURCE_DEFINE(location_query, coap_server, +{ + .post = location_query_post, + .path = location_query_path, +}); diff --git a/samples/net/sockets/coap_server/src/main.c b/samples/net/sockets/coap_server/src/main.c new file mode 100644 index 000000000000000..4f476511b2cfc38 --- /dev/null +++ b/samples/net/sockets/coap_server/src/main.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(net_coap_service_sample, LOG_LEVEL_DBG); + +#include + +#ifdef CONFIG_NET_IPV6 +#include "net_private.h" +#include "ipv6.h" +#endif + +static const uint16_t coap_port = 5683; + +#ifdef CONFIG_NET_IPV6 + +#define ALL_NODES_LOCAL_COAP_MCAST \ + { { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfd } } } + +#define MY_IP6ADDR \ + { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } } + +static int join_coap_multicast_group(void) +{ + static struct in6_addr my_addr = MY_IP6ADDR; + static struct sockaddr_in6 mcast_addr = { + .sin6_family = AF_INET6, + .sin6_addr = ALL_NODES_LOCAL_COAP_MCAST, + .sin6_port = htons(coap_port) }; + struct net_if_addr *ifaddr; + struct net_if *iface; + int ret; + + iface = net_if_get_default(); + if (!iface) { + LOG_ERR("Could not get the default interface"); + return -ENOENT; + } + +#if defined(CONFIG_NET_CONFIG_SETTINGS) + if (net_addr_pton(AF_INET6, + CONFIG_NET_CONFIG_MY_IPV6_ADDR, + &my_addr) < 0) { + LOG_ERR("Invalid IPv6 address %s", + CONFIG_NET_CONFIG_MY_IPV6_ADDR); + } +#endif + + ifaddr = net_if_ipv6_addr_add(iface, &my_addr, NET_ADDR_MANUAL, 0); + if (!ifaddr) { + LOG_ERR("Could not add unicast address to interface"); + return -EINVAL; + } + + ifaddr->addr_state = NET_ADDR_PREFERRED; + + ret = net_ipv6_mld_join(iface, &mcast_addr.sin6_addr); + if (ret < 0) { + LOG_ERR("Cannot join %s IPv6 multicast group (%d)", + net_sprint_ipv6_addr(&mcast_addr.sin6_addr), ret); + return ret; + } + + return 0; +} + +int main(void) +{ + return join_coap_multicast_group(); +} + +#else /* CONFIG_NET_IPV6 */ + +int main(void) +{ + return 0; +} + +#endif /* CONFIG_NET_IPV6 */ + +COAP_SERVICE_DEFINE(coap_server, NULL, &coap_port, COAP_SERVICE_AUTOSTART); diff --git a/samples/net/sockets/coap_server/src/observer.c b/samples/net/sockets/coap_server/src/observer.c new file mode 100644 index 000000000000000..8a14d316c61b0e4 --- /dev/null +++ b/samples/net/sockets/coap_server/src/observer.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include +#include + +static int obs_counter; + +static void update_counter(struct k_work *work); +K_WORK_DELAYABLE_DEFINE(obs_work, update_counter); + +static int send_notification_packet(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, + bool is_response) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + char payload[14]; + uint8_t type; + int r; + + if (is_response) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_CON; + } + + if (!is_response) { + id = coap_next_id(); + } + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return r; + } + + if (age >= 2U) { + r = coap_append_option_int(&response, COAP_OPTION_OBSERVE, age); + if (r < 0) { + return r; + } + } + + r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, + COAP_CONTENT_FORMAT_TEXT_PLAIN); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + return r; + } + + /* The response that coap-client expects */ + r = snprintk((char *) payload, sizeof(payload), + "Counter: %d\n", obs_counter); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload(&response, (uint8_t *)payload, + strlen(payload)); + if (r < 0) { + return r; + } + + k_work_reschedule(&obs_work, K_SECONDS(5)); + + r = coap_resource_send(resource, &response, addr, addr_len, NULL); + + return r; +} + +static int obs_get(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint8_t code; + uint8_t type; + uint8_t tkl; + int r; + + r = coap_resource_parse_observe(resource, request, addr); + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + return send_notification_packet(resource, addr, addr_len, + r == 0 ? resource->age : 0, + id, token, tkl, true); +} + +static void obs_notify(struct coap_resource *resource, + struct coap_observer *observer) +{ + send_notification_packet(resource, + &observer->addr, + sizeof(observer->addr), + resource->age, 0, + observer->token, observer->tkl, false); +} + +static const char * const obs_path[] = { "obs", NULL }; +COAP_RESOURCE_DEFINE(obs, coap_server, +{ + .get = obs_get, + .path = obs_path, + .notify = obs_notify, +}); + +static void update_counter(struct k_work *work) +{ + obs_counter++; + + coap_resource_notify(&obs); + + k_work_reschedule(&obs_work, K_SECONDS(5)); +} diff --git a/samples/net/sockets/coap_server/src/query.c b/samples/net/sockets/coap_server/src/query.c new file mode 100644 index 000000000000000..95272189d9cac91 --- /dev/null +++ b/samples/net/sockets/coap_server/src/query.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include + +static int query_get(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_option options[4]; + struct coap_packet response; + uint8_t payload[40]; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint8_t code; + uint8_t type; + uint8_t tkl; + int i, r; + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + r = coap_find_options(request, COAP_OPTION_URI_QUERY, options, 4); + if (r < 0) { + return -EINVAL; + } + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("num queries: %d", r); + + for (i = 0; i < r; i++) { + char str[16]; + + if (options[i].len + 1 > sizeof(str)) { + LOG_INF("Unexpected length of query: " + "%d (expected %zu)", + options[i].len, sizeof(str)); + break; + } + + memcpy(str, options[i].value, options[i].len); + str[options[i].len] = '\0'; + + LOG_INF("query[%d]: %s", i + 1, str); + } + + LOG_INF("*******"); + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, COAP_TYPE_ACK, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return r; + } + + r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, + COAP_CONTENT_FORMAT_TEXT_PLAIN); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + return r; + } + + /* The response that coap-client expects */ + r = snprintk((char *) payload, sizeof(payload), + "Type: %u\nCode: %u\nMID: %u\n", type, code, id); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload(&response, (uint8_t *)payload, + strlen(payload)); + if (r < 0) { + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len, NULL); + + return r; +} + +static const char * const query_path[] = { "query", NULL }; +COAP_RESOURCE_DEFINE(query, coap_server, +{ + .get = query_get, + .path = query_path, +}); diff --git a/samples/net/sockets/coap_server/src/separate.c b/samples/net/sockets/coap_server/src/separate.c new file mode 100644 index 000000000000000..68bba0bb473c32c --- /dev/null +++ b/samples/net/sockets/coap_server/src/separate.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include + +static int separate_get(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + uint8_t payload[40]; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint8_t code; + uint8_t type; + uint8_t tkl; + int r; + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + if (type == COAP_TYPE_ACK) { + return 0; + } + + r = coap_ack_init(&response, request, data, sizeof(data), 0); + if (r < 0) { + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len, NULL); + if (r < 0) { + return r; + } + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_CON; + } else { + type = COAP_TYPE_NON_CON; + } + + /* Re-use the buffer */ + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return r; + } + + r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, + COAP_CONTENT_FORMAT_TEXT_PLAIN); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + return r; + } + + /* The response that coap-client expects */ + r = snprintk((char *) payload, sizeof(payload), + "Type: %u\nCode: %u\nMID: %u\n", type, code, id); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload(&response, (uint8_t *)payload, + strlen(payload)); + if (r < 0) { + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len, NULL); + + return r; +} + +static const char * const separate_path[] = { "separate", NULL }; +COAP_RESOURCE_DEFINE(separate, coap_server, +{ + .get = separate_get, + .path = separate_path, +}); diff --git a/samples/net/sockets/coap_server/src/test.c b/samples/net/sockets/coap_server/src/test.c new file mode 100644 index 000000000000000..52885b31a5ddfff --- /dev/null +++ b/samples/net/sockets/coap_server/src/test.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_coap_service_sample); + +#include +#include + +#include "net_private.h" + +static int piggyback_get(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + uint8_t payload[40]; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint16_t id; + uint8_t code; + uint8_t type; + uint8_t tkl; + int r; + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CONTENT, id); + if (r < 0) { + return r; + } + + r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT, + COAP_CONTENT_FORMAT_TEXT_PLAIN); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload_marker(&response); + if (r < 0) { + return r; + } + + /* The response that coap-client expects */ + r = snprintk((char *) payload, sizeof(payload), + "Type: %u\nCode: %u\nMID: %u\n", type, code, id); + if (r < 0) { + return r; + } + + r = coap_packet_append_payload(&response, (uint8_t *)payload, + strlen(payload)); + if (r < 0) { + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len, NULL); + + return r; +} + +static int test_del(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint8_t tkl; + uint8_t code; + uint8_t type; + uint16_t id; + int r; + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_DELETED, id); + if (r < 0) { + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len, NULL); + + return r; +} + +static int test_put(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + struct coap_packet response; + uint8_t token[COAP_TOKEN_MAX_LEN]; + const uint8_t *payload; + uint16_t payload_len; + uint8_t code; + uint8_t type; + uint8_t tkl; + uint16_t id; + int r; + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + payload = coap_packet_get_payload(request, &payload_len); + if (payload) { + net_hexdump("PUT Payload", payload, payload_len); + } + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CHANGED, id); + if (r < 0) { + return r; + } + + r = coap_resource_send(resource, &response, addr, addr_len, NULL); + + return r; +} + +static int test_post(struct coap_resource *resource, + struct coap_packet *request, + struct sockaddr *addr, socklen_t addr_len) +{ + static const char * const location_path[] = { "location1", + "location2", + "location3", + NULL }; + uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE]; + const char * const *p; + struct coap_packet response; + uint8_t token[COAP_TOKEN_MAX_LEN]; + const uint8_t *payload; + uint16_t payload_len; + uint8_t code; + uint8_t type; + uint8_t tkl; + uint16_t id; + int r; + + code = coap_header_get_code(request); + type = coap_header_get_type(request); + id = coap_header_get_id(request); + tkl = coap_header_get_token(request, token); + + LOG_INF("*******"); + LOG_INF("type: %u code %u id %u", type, code, id); + LOG_INF("*******"); + + payload = coap_packet_get_payload(request, &payload_len); + if (payload) { + net_hexdump("POST Payload", payload, payload_len); + } + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + r = coap_packet_init(&response, data, sizeof(data), + COAP_VERSION_1, type, tkl, token, + COAP_RESPONSE_CODE_CREATED, id); + if (r < 0) { + return r; + } + + for (p = location_path; *p; p++) { + r = coap_packet_append_option(&response, + COAP_OPTION_LOCATION_PATH, + *p, strlen(*p)); + if (r < 0) { + return r; + } + } + + r = coap_resource_send(resource, &response, addr, addr_len, NULL); + + return r; +} + +static const char * const test_path[] = { "test", NULL }; +COAP_RESOURCE_DEFINE(test, coap_server, +{ + .get = piggyback_get, + .post = test_post, + .del = test_del, + .put = test_put, + .path = test_path, +}); + +static const char * const segments_path[] = { "seg1", "seg2", "seg3", NULL }; +COAP_RESOURCE_DEFINE(segments, coap_server, +{ + .get = piggyback_get, + .path = segments_path, +}); + +#if defined(CONFIG_COAP_URI_WILDCARD) + +static const char * const wildcard1_path[] = { "wild1", "+", "wild3", NULL }; +COAP_RESOURCE_DEFINE(wildcard1, coap_server, +{ + .get = piggyback_get, + .path = wildcard1_path, +}); + +static const char * const wildcard2_path[] = { "wild2", "#", NULL }; +COAP_RESOURCE_DEFINE(wildcard2, coap_server, +{ + .get = piggyback_get, + .path = wildcard2_path, +}); + +#endif diff --git a/samples/net/sockets/dumb_http_server/Makefile.posix b/samples/net/sockets/dumb_http_server/Makefile.host similarity index 100% rename from samples/net/sockets/dumb_http_server/Makefile.posix rename to samples/net/sockets/dumb_http_server/Makefile.host diff --git a/samples/net/sockets/dumb_http_server/README.rst b/samples/net/sockets/dumb_http_server/README.rst index 56e6ac281e46581..659f94c82cdefb7 100644 --- a/samples/net/sockets/dumb_http_server/README.rst +++ b/samples/net/sockets/dumb_http_server/README.rst @@ -64,11 +64,11 @@ The same application source code can be built for a POSIX system, e.g. Linux. (Note: if you look at the source, you will see that the code is the same except the header files are different for Zephyr vs POSIX.) -To build for a host POSIX OS: +To build: .. code-block:: console - $ make -f Makefile.posix + $ make -f Makefile.host To run: diff --git a/samples/net/sockets/dumb_http_server/prj.conf b/samples/net/sockets/dumb_http_server/prj.conf index 62dcbde44b89476..1c826c38f9db366 100644 --- a/samples/net/sockets/dumb_http_server/prj.conf +++ b/samples/net/sockets/dumb_http_server/prj.conf @@ -1,5 +1,5 @@ # General config -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y # Networking config CONFIG_NETWORKING=y diff --git a/samples/net/sockets/dumb_http_server/sample.yaml b/samples/net/sockets/dumb_http_server/sample.yaml index d586551bdb7c467..13fd552b8aa0e64 100644 --- a/samples/net/sockets/dumb_http_server/sample.yaml +++ b/samples/net/sockets/dumb_http_server/sample.yaml @@ -2,7 +2,7 @@ sample: description: BSD Sockets API dumb HTTP server example name: socket_dumb_http_server common: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC harness: net min_ram: 32 min_flash: 96 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 76b94934df89d47..d9194ca0dd20413 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 714bbc5a67b3663..06f9f0c6e716912 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); @@ -287,7 +294,7 @@ static int process_tcp(int *sock, int *accepted) &tcp6_handler_thread[slot], tcp6_handler_stack[slot], K_THREAD_STACK_SIZEOF(tcp6_handler_stack[slot]), - (k_thread_entry_t)client_conn_handler, + client_conn_handler, INT_TO_POINTER(slot), &accepted[slot], &tcp6_handler_tid[slot], @@ -302,7 +309,7 @@ static int process_tcp(int *sock, int *accepted) &tcp4_handler_thread[slot], tcp4_handler_stack[slot], K_THREAD_STACK_SIZEOF(tcp4_handler_stack[slot]), - (k_thread_entry_t)client_conn_handler, + client_conn_handler, INT_TO_POINTER(slot), &accepted[slot], &tcp4_handler_tid[slot], diff --git a/samples/net/sockets/echo/Makefile.posix b/samples/net/sockets/echo/Makefile.host similarity index 100% rename from samples/net/sockets/echo/Makefile.posix rename to samples/net/sockets/echo/Makefile.host diff --git a/samples/net/sockets/echo/README.rst b/samples/net/sockets/echo/README.rst index 005036ca5382e0a..ca49115fd5d8843 100644 --- a/samples/net/sockets/echo/README.rst +++ b/samples/net/sockets/echo/README.rst @@ -2,15 +2,16 @@ :name: Echo server (simple) :relevant-api: bsd_sockets - Implements a simple IPv4 TCP echo server using BSD sockets. + Implements a simple IPv4/IPv6 TCP echo server using BSD sockets. Overview ******** -The sockets/echo sample application for Zephyr implements an IPv4 TCP echo -server using a BSD Sockets compatible API. The purpose of this sample is to -show how it's possible to develop a sockets application portable to both -POSIX and Zephyr. As such, it is kept minimal and supports only IPv4 and TCP. +The sockets/echo 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 it's possible to develop a sockets +application portable to both POSIX and Zephyr. As such, it is kept minimal +and supports only IPv4, IPv6 and TCP. The source code for this sample application can be found at: :zephyr_file:`samples/net/sockets/echo`. @@ -51,11 +52,11 @@ The same application source code can be built for a POSIX system, e.g. Linux. (Note: if you look at the source, you will see that the code is the same except the header files are different for Zephyr vs POSIX.) -To build for a host POSIX OS: +To build: .. code-block:: console - $ make -f Makefile.posix + $ make -f Makefile.host To run: diff --git a/samples/net/sockets/echo/prj.conf b/samples/net/sockets/echo/prj.conf index 6526148e0a13103..3d25caa29248796 100644 --- a/samples/net/sockets/echo/prj.conf +++ b/samples/net/sockets/echo/prj.conf @@ -1,14 +1,14 @@ # General config -CONFIG_NEWLIB_LIBC=y CONFIG_MAIN_STACK_SIZE=1200 # Networking config CONFIG_NETWORKING=y CONFIG_NET_IPV4=y -CONFIG_NET_IPV6=n +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 # Network driver config CONFIG_TEST_RANDOM_GENERATOR=y @@ -16,5 +16,8 @@ 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" diff --git a/samples/net/sockets/echo/sample.yaml b/samples/net/sockets/echo/sample.yaml index 300c13a4a6f5854..00a8e4e56bd4b76 100644 --- a/samples/net/sockets/echo/sample.yaml +++ b/samples/net/sockets/echo/sample.yaml @@ -4,7 +4,7 @@ sample: common: harness: net depends_on: netif - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC tests: sample.net.sockets.echo: tags: diff --git a/samples/net/sockets/echo/src/socket_echo.c b/samples/net/sockets/echo/src/socket_echo.c index cf4d05f5780b9e0..5ebf954ff491cc4 100644 --- a/samples/net/sockets/echo/src/socket_echo.c +++ b/samples/net/sockets/echo/src/socket_echo.c @@ -26,20 +26,36 @@ int main(void) { - int serv; - struct sockaddr_in bind_addr; + int opt, optlen = sizeof(int); + int serv, ret; + struct sockaddr_in6 bind_addr = { + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_ANY_INIT, + .sin6_port = htons(BIND_PORT), + }; static int counter; - serv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - + serv = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); if (serv < 0) { printf("error: socket: %d\n", errno); exit(1); } - bind_addr.sin_family = AF_INET; - bind_addr.sin_addr.s_addr = htonl(INADDR_ANY); - bind_addr.sin_port = htons(BIND_PORT); + ret = getsockopt(serv, IPPROTO_IPV6, IPV6_V6ONLY, &opt, &optlen); + if (ret == 0) { + if (opt) { + printf("IPV6_V6ONLY option is on, turning it off.\n"); + + opt = 0; + ret = setsockopt(serv, IPPROTO_IPV6, IPV6_V6ONLY, + &opt, optlen); + if (ret < 0) { + printf("Cannot turn off IPV6_V6ONLY option\n"); + } else { + printf("Sharing same socket between IPv6 and IPv4\n"); + } + } + } if (bind(serv, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) < 0) { printf("error: bind: %d\n", errno); @@ -55,7 +71,7 @@ int main(void) "port %d...\n", BIND_PORT); while (1) { - struct sockaddr_in client_addr; + struct sockaddr_in6 client_addr; socklen_t client_addr_len = sizeof(client_addr); char addr_str[32]; int client = accept(serv, (struct sockaddr *)&client_addr, @@ -66,7 +82,7 @@ int main(void) continue; } - inet_ntop(client_addr.sin_family, &client_addr.sin_addr, + inet_ntop(client_addr.sin6_family, &client_addr.sin6_addr, addr_str, sizeof(addr_str)); printf("Connection #%d from %s\n", counter++, addr_str); diff --git a/samples/net/sockets/echo_async/Makefile.posix b/samples/net/sockets/echo_async/Makefile.host similarity index 100% rename from samples/net/sockets/echo_async/Makefile.posix rename to samples/net/sockets/echo_async/Makefile.host diff --git a/samples/net/sockets/echo_async/README.rst b/samples/net/sockets/echo_async/README.rst index 0499973fc2e1e51..826b3ffbda5a41d 100644 --- a/samples/net/sockets/echo_async/README.rst +++ b/samples/net/sockets/echo_async/README.rst @@ -57,11 +57,11 @@ Linux. (Note: if you look at the source, you will see that the code is the same except the header files are different for Zephyr vs POSIX, and there's an additional option to set for Linux to make a socket IPv6-only). -To build for a host POSIX OS: +To build: .. code-block:: console - $ make -f Makefile.posix + $ make -f Makefile.host To run: diff --git a/samples/net/sockets/echo_async/prj.conf b/samples/net/sockets/echo_async/prj.conf index 3cfb5a6d4fcf48d..212910095570e0b 100644 --- a/samples/net/sockets/echo_async/prj.conf +++ b/samples/net/sockets/echo_async/prj.conf @@ -1,5 +1,5 @@ # General config -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y CONFIG_MAIN_STACK_SIZE=1200 # Networking config diff --git a/samples/net/sockets/echo_async/sample.yaml b/samples/net/sockets/echo_async/sample.yaml index d3097a30775a56a..9c88a2d5ea5aae2 100644 --- a/samples/net/sockets/echo_async/sample.yaml +++ b/samples/net/sockets/echo_async/sample.yaml @@ -2,7 +2,7 @@ sample: description: BSD Sockets API TCP echo server sample using non-blocking sockets name: socket_echo_async common: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC harness: net platform_allow: qemu_x86 tags: diff --git a/samples/net/sockets/echo_async_select/Makefile.posix b/samples/net/sockets/echo_async_select/Makefile.host similarity index 100% rename from samples/net/sockets/echo_async_select/Makefile.posix rename to samples/net/sockets/echo_async_select/Makefile.host diff --git a/samples/net/sockets/echo_async_select/README.rst b/samples/net/sockets/echo_async_select/README.rst index cc2b48735d853a5..963b10059281942 100644 --- a/samples/net/sockets/echo_async_select/README.rst +++ b/samples/net/sockets/echo_async_select/README.rst @@ -55,11 +55,11 @@ Linux. (Note: if you look at the source, you will see that the code is the same except the header files are different for Zephyr vs POSIX, and there's an additional option to set for Linux to make a socket IPv6-only). -To build for a host POSIX OS: +To build: .. code-block:: console - $ make -f Makefile.posix + $ make -f Makefile.host To run: diff --git a/samples/net/sockets/echo_async_select/prj.conf b/samples/net/sockets/echo_async_select/prj.conf index 0a6e0c049b61ed9..377b2eef8af69dd 100644 --- a/samples/net/sockets/echo_async_select/prj.conf +++ b/samples/net/sockets/echo_async_select/prj.conf @@ -1,5 +1,5 @@ # General config -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y CONFIG_MAIN_STACK_SIZE=1200 CONFIG_POSIX_API=y diff --git a/samples/net/sockets/echo_async_select/sample.yaml b/samples/net/sockets/echo_async_select/sample.yaml index b052c0d1c9db45d..3353773ec0b56e8 100644 --- a/samples/net/sockets/echo_async_select/sample.yaml +++ b/samples/net/sockets/echo_async_select/sample.yaml @@ -7,7 +7,7 @@ common: tags: - net - socket - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC tests: sample.net.sockets.echo_async_select: extra_configs: diff --git a/samples/net/sockets/echo_client/overlay-ot.conf b/samples/net/sockets/echo_client/overlay-ot.conf index 58c70682478a91e..0eb39c24d43541e 100644 --- a/samples/net/sockets/echo_client/overlay-ot.conf +++ b/samples/net/sockets/echo_client/overlay-ot.conf @@ -1,4 +1,4 @@ -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y # Disable TCP and IPv4 (TCP disabled to avoid heavy traffic) CONFIG_NET_TCP=n diff --git a/samples/net/sockets/echo_client/sample.yaml b/samples/net/sockets/echo_client/sample.yaml index bbc7d3c10e17416..7c37257e420ef92 100644 --- a/samples/net/sockets/echo_client/sample.yaml +++ b/samples/net/sockets/echo_client/sample.yaml @@ -81,7 +81,7 @@ tests: - net - openthread platform_allow: nrf52840dk_nrf52840 - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC sample.net.sockets.echo_client.b91_802154: extra_args: OVERLAY_CONFIG="overlay-802154.conf" platform_allow: tlsr9518adk80d @@ -92,7 +92,7 @@ tests: - net - openthread platform_allow: tlsr9518adk80d - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC sample.net.sockets.echo_client.kw41z_openthread: extra_args: OVERLAY_CONFIG="overlay-ot.conf" slow: true @@ -100,7 +100,7 @@ tests: - net - openthread platform_allow: frdm_kw41z - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC sample.net.sockets.echo_client.userspace: extra_args: - CONFIG_USERSPACE=y diff --git a/samples/net/sockets/echo_client/src/echo-client.c b/samples/net/sockets/echo_client/src/echo-client.c index 3738c758b15a439..3e4aff0f2d0bdd5 100644 --- a/samples/net/sockets/echo_client/src/echo-client.c +++ b/samples/net/sockets/echo_client/src/echo-client.c @@ -279,8 +279,12 @@ static void init_app(void) init_udp(); } -static int start_client(void) +static void start_client(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + int iterations = CONFIG_NET_SAMPLE_SEND_ITERATIONS; int i = 0; int ret; @@ -305,8 +309,6 @@ static int start_client(void) stop_udp_and_tcp(); } - - return ret; } int main(void) @@ -318,6 +320,7 @@ int main(void) * app only after we have a connection, then we can start * it right away. */ + connected = true; k_sem_give(&run_app); } @@ -327,10 +330,9 @@ int main(void) k_thread_access_grant(k_current_get(), &run_app); k_mem_domain_add_thread(&app_domain, k_current_get()); - k_thread_user_mode_enter((k_thread_entry_t)start_client, NULL, NULL, - NULL); + k_thread_user_mode_enter(start_client, NULL, NULL, NULL); #else - exit(start_client()); + start_client(NULL, NULL, NULL); #endif return 0; } diff --git a/samples/net/sockets/echo_client/src/udp.c b/samples/net/sockets/echo_client/src/udp.c index 1889fdb591df766..e5b7ea1dae067a0 100644 --- a/samples/net/sockets/echo_client/src/udp.c +++ b/samples/net/sockets/echo_client/src/udp.c @@ -40,8 +40,12 @@ static int send_udp_data(struct data *data); static void wait_reply(struct k_timer *timer); static void wait_transmit(struct k_timer *timer); -static void process_udp_tx(void) +static void process_udp_tx(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + struct k_poll_event events[] = { K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, @@ -317,7 +321,7 @@ int start_udp(void) k_thread_create(&udp_tx_thread, udp_tx_thread_stack, K_THREAD_STACK_SIZEOF(udp_tx_thread_stack), - (k_thread_entry_t)process_udp_tx, + process_udp_tx, NULL, NULL, NULL, THREAD_PRIORITY, IS_ENABLED(CONFIG_USERSPACE) ? K_USER | K_INHERIT_PERMS : 0, diff --git a/samples/net/sockets/echo_server/overlay-ot.conf b/samples/net/sockets/echo_server/overlay-ot.conf index 2158020d621288b..5d4563fdfa11803 100644 --- a/samples/net/sockets/echo_server/overlay-ot.conf +++ b/samples/net/sockets/echo_server/overlay-ot.conf @@ -1,4 +1,4 @@ -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y # Disable TCP and IPv4 (TCP disabled to avoid heavy traffic) CONFIG_NET_TCP=n diff --git a/samples/net/sockets/echo_server/sample.yaml b/samples/net/sockets/echo_server/sample.yaml index 102559054020cae..1174797d04a3966 100644 --- a/samples/net/sockets/echo_server/sample.yaml +++ b/samples/net/sockets/echo_server/sample.yaml @@ -92,7 +92,7 @@ tests: - net - openthread platform_allow: nrf52840dk_nrf52840 - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC sample.net.sockets.echo_server.b91_openthread: extra_args: OVERLAY_CONFIG="overlay-ot.conf" slow: true @@ -100,7 +100,7 @@ tests: - net - openthread platform_allow: tlsr9518adk80d - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC sample.net.sockets.echo_server.kw41z_openthread: extra_args: OVERLAY_CONFIG="overlay-ot.conf" slow: true @@ -108,7 +108,7 @@ tests: - net - openthread platform_allow: frdm_kw41z - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC sample.net.sockets.echo_server.e1000: extra_args: OVERLAY_CONFIG="overlay-e1000.conf" tags: net diff --git a/samples/net/sockets/echo_server/src/tcp.c b/samples/net/sockets/echo_server/src/tcp.c index ffc6d69bc36f374..1a6555d43c30c49 100644 --- a/samples/net/sockets/echo_server/src/tcp.c +++ b/samples/net/sockets/echo_server/src/tcp.c @@ -243,7 +243,7 @@ static int process_tcp(struct data *data) &tcp6_handler_thread[slot], tcp6_handler_stack[slot], K_THREAD_STACK_SIZEOF(tcp6_handler_stack[slot]), - (k_thread_entry_t)handle_data, + handle_data, INT_TO_POINTER(slot), data, &tcp6_handler_in_use[slot], THREAD_PRIORITY, IS_ENABLED(CONFIG_USERSPACE) ? K_USER | @@ -267,7 +267,7 @@ static int process_tcp(struct data *data) &tcp4_handler_thread[slot], tcp4_handler_stack[slot], K_THREAD_STACK_SIZEOF(tcp4_handler_stack[slot]), - (k_thread_entry_t)handle_data, + handle_data, INT_TO_POINTER(slot), data, &tcp4_handler_in_use[slot], THREAD_PRIORITY, IS_ENABLED(CONFIG_USERSPACE) ? K_USER | diff --git a/samples/net/sockets/echo_service/CMakeLists.txt b/samples/net/sockets/echo_service/CMakeLists.txt new file mode 100644 index 000000000000000..fda31959a7db0d2 --- /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 000000000000000..3e1d7625d7015a8 --- /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 000000000000000..adcf29f904d7282 --- /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 000000000000000..c39159ea7e4883f --- /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 000000000000000..aee10686c0f0a5b --- /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 000000000000000..dbdde28cf3027da --- /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/http_get/Makefile.posix b/samples/net/sockets/http_get/Makefile.host similarity index 100% rename from samples/net/sockets/http_get/Makefile.posix rename to samples/net/sockets/http_get/Makefile.host diff --git a/samples/net/sockets/http_get/README.rst b/samples/net/sockets/http_get/README.rst index 790b9756f318293..09bfb2050d164f6 100644 --- a/samples/net/sockets/http_get/README.rst +++ b/samples/net/sockets/http_get/README.rst @@ -76,11 +76,11 @@ The same application source code can be built for a POSIX system, e.g. Linux. (Note: if you look at the source, you will see that the code is the same except the header files are different for Zephyr vs POSIX.) -To build for a host POSIX OS: +To build: .. code-block:: console - $ make -f Makefile.posix + $ make -f Makefile.host To run: diff --git a/samples/net/sockets/http_get/prj.conf b/samples/net/sockets/http_get/prj.conf index 64bb4bc52f8c01f..57d4d4c55c03792 100644 --- a/samples/net/sockets/http_get/prj.conf +++ b/samples/net/sockets/http_get/prj.conf @@ -1,6 +1,6 @@ # General config CONFIG_MAIN_STACK_SIZE=1536 -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y # Networking config CONFIG_NETWORKING=y diff --git a/samples/net/sockets/http_get/sample.yaml b/samples/net/sockets/http_get/sample.yaml index f8fb27104c3cce6..999c7ba97d6c0f9 100644 --- a/samples/net/sockets/http_get/sample.yaml +++ b/samples/net/sockets/http_get/sample.yaml @@ -2,7 +2,7 @@ sample: description: BSD Sockets API HTTP GET example name: socket_http_get common: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC harness: net min_ram: 32 min_flash: 80 diff --git a/samples/net/sockets/net_mgmt/README.rst b/samples/net/sockets/net_mgmt/README.rst index 92d6d8524c79277..c59b8170e31749c 100644 --- a/samples/net/sockets/net_mgmt/README.rst +++ b/samples/net/sockets/net_mgmt/README.rst @@ -34,12 +34,12 @@ Build net-mgmt socket sample application like this: :goals: build :compact: -Example building for the native_posix board: +Example building for the native_sim board: .. zephyr-app-commands:: :zephyr-app: samples/net/sockets/net_mgmt :host-os: unix - :board: native_posix + :board: native_sim :conf: prj.conf :goals: run :compact: diff --git a/samples/net/sockets/net_mgmt/sample.yaml b/samples/net/sockets/net_mgmt/sample.yaml index 7199cb2614a87e5..337e8d08a756ea2 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/sockets/net_mgmt/src/main.c b/samples/net/sockets/net_mgmt/src/main.c index 2e6813b54cdd0fe..877e5e41d5c7dce 100644 --- a/samples/net/sockets/net_mgmt/src/main.c +++ b/samples/net/sockets/net_mgmt/src/main.c @@ -82,8 +82,12 @@ static char *get_ip_addr(char *ipaddr, size_t len, sa_family_t family, return buf; } -static void listener(void) +static void listener(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + struct sockaddr_nm sockaddr; struct sockaddr_nm event_addr; socklen_t event_addr_len; @@ -163,10 +167,10 @@ int main(void) k_thread_start(trigger_events_thread_id); if (IS_ENABLED(CONFIG_USERSPACE)) { - k_thread_user_mode_enter((k_thread_entry_t)listener, + k_thread_user_mode_enter(listener, NULL, NULL, NULL); } else { - listener(); + listener(NULL, NULL, NULL); } return 0; } diff --git a/samples/net/sockets/packet/README.rst b/samples/net/sockets/packet/README.rst index ea096be0a23f9ca..b9429215061588e 100644 --- a/samples/net/sockets/packet/README.rst +++ b/samples/net/sockets/packet/README.rst @@ -23,7 +23,7 @@ sent and received packets. See the `net-tools`_ project for more details. -This sample can be built and executed on QEMU or native_posix board as +This sample can be built and executed on QEMU or native_sim board as described in :ref:`networking_with_host`. .. _`net-tools`: https://github.com/zephyrproject-rtos/net-tools diff --git a/samples/net/sockets/packet/sample.yaml b/samples/net/sockets/packet/sample.yaml index 66deae9f335374e..d02c03c7d681c7c 100644 --- a/samples/net/sockets/packet/sample.yaml +++ b/samples/net/sockets/packet/sample.yaml @@ -7,8 +7,10 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 integration_platforms: - - native_posix + - native_sim tags: - net - sockets diff --git a/samples/net/sockets/sntp_client/README.rst b/samples/net/sockets/sntp_client/README.rst index 1e061c36a707a9b..f9a1aacd4b8ffc0 100644 --- a/samples/net/sockets/sntp_client/README.rst +++ b/samples/net/sockets/sntp_client/README.rst @@ -24,7 +24,7 @@ printed. See the `net-tools`_ project for more details. -This sample can be built and executed on QEMU or native_posix board as +This sample can be built and executed on QEMU or native_sim board as described in :ref:`networking_with_qemu`. .. _`net-tools`: https://github.com/zephyrproject-rtos/net-tools diff --git a/samples/net/sockets/sntp_client/prj.conf b/samples/net/sockets/sntp_client/prj.conf index d641240c25e10f5..bfcd3092ac6f5c1 100644 --- a/samples/net/sockets/sntp_client/prj.conf +++ b/samples/net/sockets/sntp_client/prj.conf @@ -1,5 +1,5 @@ # General config -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y # Networking config CONFIG_NETWORKING=y diff --git a/samples/net/sockets/sntp_client/sample.yaml b/samples/net/sockets/sntp_client/sample.yaml index 3a87d5995e24933..65d4f2f3b2cc629 100644 --- a/samples/net/sockets/sntp_client/sample.yaml +++ b/samples/net/sockets/sntp_client/sample.yaml @@ -6,13 +6,19 @@ common: tags: net tests: sample.net.sockets.sntp_client: - platform_allow: qemu_x86 + platform_allow: + - qemu_x86 + - native_sim sample.net.sockets.sntp_client.posix_names: - platform_allow: qemu_x86 + platform_allow: + - qemu_x86 + - native_sim extra_configs: - CONFIG_NET_SOCKETS_POSIX_NAMES=y sample.net.sockets.sntp_client.posix: - platform_allow: qemu_x86 + platform_allow: + - qemu_x86 + - native_sim extra_configs: - CONFIG_NET_SOCKETS_POSIX_NAMES=n - CONFIG_POSIX_API=y diff --git a/samples/net/sockets/socketpair/Makefile.posix b/samples/net/sockets/socketpair/Makefile.host similarity index 100% rename from samples/net/sockets/socketpair/Makefile.posix rename to samples/net/sockets/socketpair/Makefile.host diff --git a/samples/net/sockets/socketpair/README.rst b/samples/net/sockets/socketpair/README.rst index 3dce3caea7e8763..948a2b2d8bfe194 100644 --- a/samples/net/sockets/socketpair/README.rst +++ b/samples/net/sockets/socketpair/README.rst @@ -62,11 +62,11 @@ Running application on POSIX Host The same application source code can be built for a POSIX system, e.g. Linux. -To build for a host POSIX OS: +To build: .. code-block:: console - $ make -f Makefile.posix + $ make -f Makefile.host To run: diff --git a/samples/net/sockets/tcp/prj.conf b/samples/net/sockets/tcp/prj.conf index be1af897fe2523e..a442918f3376863 100644 --- a/samples/net/sockets/tcp/prj.conf +++ b/samples/net/sockets/tcp/prj.conf @@ -1,4 +1,4 @@ -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y CONFIG_NETWORKING=y diff --git a/samples/net/sockets/tcp/sample.yaml b/samples/net/sockets/tcp/sample.yaml index b636044bca3961e..895e519a36047ad 100644 --- a/samples/net/sockets/tcp/sample.yaml +++ b/samples/net/sockets/tcp/sample.yaml @@ -3,7 +3,7 @@ sample: name: tcp tests: sample.net.socket.tcp: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC harness: net platform_allow: qemu_x86 tags: diff --git a/samples/net/sockets/txtime/sample.yaml b/samples/net/sockets/txtime/sample.yaml index 98488b70e942687..189f6901bfc76ef 100644 --- a/samples/net/sockets/txtime/sample.yaml +++ b/samples/net/sockets/txtime/sample.yaml @@ -5,10 +5,12 @@ common: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 - qemu_x86 - qemu_x86_64 integration_platforms: - - native_posix + - native_sim sample: description: Socket SO_TXTIME sample name: txtime-socket diff --git a/samples/net/sockets/txtime/src/main.c b/samples/net/sockets/txtime/src/main.c index a4a637323981a74..481312d1afe03d8 100644 --- a/samples/net/sockets/txtime/src/main.c +++ b/samples/net/sockets/txtime/src/main.c @@ -127,8 +127,12 @@ static void event_handler(struct net_mgmt_event_callback *cb, } } -static void rx(struct app_data *data) +static void rx(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct app_data *data = p1; static uint8_t recv_buf[sizeof(txtime_str)]; struct sockaddr src; socklen_t addr_len = data->peer_addr_len; @@ -143,8 +147,12 @@ static void rx(struct app_data *data) } } -static void tx(struct app_data *data) +static void tx(void *p1, void *p2, void *p3) { + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct app_data *data = p1; struct net_ptp_time time; struct msghdr msg; struct cmsghdr *cmsg; @@ -620,7 +628,7 @@ int main(void) tx_tid = k_thread_create(&tx_thread, tx_stack, K_THREAD_STACK_SIZEOF(tx_stack), - (k_thread_entry_t)tx, &peer_data, + tx, &peer_data, NULL, NULL, THREAD_PRIORITY, 0, K_FOREVER); if (!tx_tid) { @@ -632,7 +640,7 @@ int main(void) rx_tid = k_thread_create(&rx_thread, rx_stack, K_THREAD_STACK_SIZEOF(rx_stack), - (k_thread_entry_t)rx, &peer_data, + rx, &peer_data, NULL, NULL, THREAD_PRIORITY, 0, K_FOREVER); if (!rx_tid) { diff --git a/samples/net/stats/README.rst b/samples/net/stats/README.rst index 84204d46131e63e..b8a2016c83f3b50 100644 --- a/samples/net/stats/README.rst +++ b/samples/net/stats/README.rst @@ -21,7 +21,7 @@ Requirements Building and Running ******************** -A good way to run this sample application is with QEMU or native_posix board +A good way to run this sample application is with QEMU or native_sim board as described in :ref:`networking_with_host`. Follow these steps to build the network statistics sample application: diff --git a/samples/net/syslog_net/prj.conf b/samples/net/syslog_net/prj.conf index d4fb024b448ebd1..b0ae6043cefb02a 100644 --- a/samples/net/syslog_net/prj.conf +++ b/samples/net/syslog_net/prj.conf @@ -37,4 +37,4 @@ 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 -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y diff --git a/samples/net/syslog_net/sample.yaml b/samples/net/syslog_net/sample.yaml index 6a84d7d51cd33bf..4fe99e593ff111a 100644 --- a/samples/net/syslog_net/sample.yaml +++ b/samples/net/syslog_net/sample.yaml @@ -9,11 +9,11 @@ sample: name: syslog_net tests: sample.net.syslog.with_timefuncs: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED extra_configs: - - CONFIG_NEWLIB_LIBC=y + - CONFIG_REQUIRES_FULL_LIBC=y sample.net.syslog.ipv4_only: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED extra_configs: - CONFIG_NET_IPV6=n - CONFIG_NET_CONFIG_NEED_IPV6=n @@ -21,18 +21,18 @@ tests: - CONFIG_NET_CONFIG_PEER_IPV6_ADDR="" - CONFIG_LOG_BACKEND_NET_SERVER="192.0.2.1:514" sample.net.syslog.ipv6_only: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED extra_configs: - CONFIG_NET_IPV4=n - CONFIG_NET_CONFIG_NEED_IPV4=n - CONFIG_NET_CONFIG_MY_IPV4_ADDR="" - CONFIG_NET_CONFIG_PEER_IPV4_ADDR="" sample.net.syslog.no_autostart: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED extra_configs: - CONFIG_LOG_BACKEND_NET_AUTOSTART=n sample.net.syslog.runtime_srv_addr: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED extra_configs: - CONFIG_LOG_BACKEND_NET_AUTOSTART=n - CONFIG_LOG_BACKEND_NET_SERVER="" diff --git a/samples/net/tftp_client/README.rst b/samples/net/tftp_client/README.rst index 40da21adcf6f939..a6c684da5b0a5d5 100644 --- a/samples/net/tftp_client/README.rst +++ b/samples/net/tftp_client/README.rst @@ -19,7 +19,7 @@ The source code for this sample application can be found at: Requirements ************ -- :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` or :ref:`networking_with_native_posix` +- :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` or :ref:`networking_with_native_sim` - Linux machine Building and Running @@ -41,15 +41,15 @@ Build the tftp-client sample application like this: :compact: The easiest way to setup this sample application is to build and run it -as native POSIX application or as a QEMU target using the default configuration :file:`prj.conf`. -This requires a small amount of setup described in :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` and :ref:`networking_with_native_posix`. +as a native_sim application or as a QEMU target using the default configuration :file:`prj.conf`. +This requires a small amount of setup described in :ref:`networking_with_eth_qemu`, :ref:`networking_with_qemu` and :ref:`networking_with_native_sim`. -Build the tftp-client sample application for native_posix like this: +Build the tftp-client sample application for :ref:`native_sim ` like this: .. zephyr-app-commands:: :zephyr-app: samples/net/tftp_client :host-os: unix - :board: native_posix + :board: native_sim :goals: run :compact: @@ -70,7 +70,7 @@ configurations in ``prj.conf``:: Sample output ================================== -Sample run on native_posix platform with TFTP server on host machine +Sample run on native_sim platform with TFTP server on host machine Launch net-setup.sh in net-tools .. code-block:: console diff --git a/samples/net/tftp_client/boards/native_sim.conf b/samples/net/tftp_client/boards/native_sim.conf new file mode 100644 index 000000000000000..1e9e27b074ea10a --- /dev/null +++ b/samples/net/tftp_client/boards/native_sim.conf @@ -0,0 +1,3 @@ +CONFIG_DNS_RESOLVER=y +CONFIG_DNS_SERVER_IP_ADDRESSES=y +CONFIG_DNS_SERVER1="192.0.2.2" diff --git a/samples/net/tftp_client/sample.yaml b/samples/net/tftp_client/sample.yaml index baabc4790b4cb4f..3ccedecafe997eb 100644 --- a/samples/net/tftp_client/sample.yaml +++ b/samples/net/tftp_client/sample.yaml @@ -7,8 +7,9 @@ tests: depends_on: netif platform_allow: - native_posix + - native_sim integration_platforms: - - native_posix + - native_sim tags: - net - tftp diff --git a/samples/net/wifi/boards/cy8cproto_062_4343w.conf b/samples/net/wifi/boards/cy8cproto_062_4343w.conf new file mode 100644 index 000000000000000..943db317fadc422 --- /dev/null +++ b/samples/net/wifi/boards/cy8cproto_062_4343w.conf @@ -0,0 +1,3 @@ +CONFIG_NET_IF_MAX_IPV4_COUNT=2 +CONFIG_NET_MGMT_EVENT_QUEUE_TIMEOUT=20 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 diff --git a/samples/net/wifi/boards/esp32_devkitc_wroom.conf b/samples/net/wifi/boards/esp32_devkitc_wroom.conf index 5c37cfc402d35fc..a72fdf39efa2454 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 5c37cfc402d35fc..a72fdf39efa2454 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 5c37cfc402d35fc..a72fdf39efa2454 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 5c37cfc402d35fc..a72fdf39efa2454 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 5c37cfc402d35fc..a72fdf39efa2454 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 000000000000000..a72fdf39efa2454 --- /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 000000000000000..4d69fe294930529 --- /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 5c37cfc402d35fc..a72fdf39efa2454 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/wpan_serial/src/main.c b/samples/net/wpan_serial/src/main.c index 1e702dc959094a0..04b98a449bbadc8 100644 --- a/samples/net/wpan_serial/src/main.c +++ b/samples/net/wpan_serial/src/main.c @@ -299,8 +299,12 @@ static void process_config(struct net_pkt *pkt) } } -static void rx_thread(void) +static void rx_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + LOG_DBG("RX thread started"); while (true) { @@ -386,8 +390,12 @@ static int try_write(uint8_t *data, uint16_t len) /** * TX - transmit to SLIP interface */ -static void tx_thread(void) +static void tx_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + LOG_DBG("TX thread started"); while (true) { @@ -421,7 +429,7 @@ static void init_rx_queue(void) k_thread_create(&rx_thread_data, rx_stack, K_THREAD_STACK_SIZEOF(rx_stack), - (k_thread_entry_t)rx_thread, + rx_thread, NULL, NULL, NULL, THREAD_PRIORITY, 0, K_NO_WAIT); } @@ -431,7 +439,7 @@ static void init_tx_queue(void) k_thread_create(&tx_thread_data, tx_stack, K_THREAD_STACK_SIZEOF(tx_stack), - (k_thread_entry_t)tx_thread, + tx_thread, NULL, NULL, NULL, THREAD_PRIORITY, 0, K_NO_WAIT); } diff --git a/samples/net/wpanusb/src/wpanusb.c b/samples/net/wpanusb/src/wpanusb.c index a4e1f88403f3095..7cee37340c323d1 100644 --- a/samples/net/wpanusb/src/wpanusb.c +++ b/samples/net/wpanusb/src/wpanusb.c @@ -295,8 +295,12 @@ static int tx(struct net_pkt *pkt) return ret; } -static void tx_thread(void) +static void tx_thread(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + LOG_DBG("Tx thread started"); while (1) { @@ -353,7 +357,7 @@ static void init_tx_queue(void) k_thread_create(&tx_thread_data, tx_stack, K_THREAD_STACK_SIZEOF(tx_stack), - (k_thread_entry_t)tx_thread, + tx_thread, NULL, NULL, NULL, THREAD_PRIORITY, 0, K_NO_WAIT); } diff --git a/samples/net/zperf/CMakeLists.txt b/samples/net/zperf/CMakeLists.txt index ae9b46dadc0fdb0..c4552f97141768b 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 000000000000000..a56cd6b941605ed --- /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 8f90b5bd833fa1e..287d55db122c281 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 4340caf2abc9bcc..000000000000000 --- 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 8f90b5bd833fa1e..287d55db122c281 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 4340caf2abc9bcc..000000000000000 --- 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 000000000000000..287d55db122c281 --- /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 000000000000000..287d55db122c281 --- /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 39f1217d62dfa3c..230e0462333081c 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 201940c23a9961f..99b8f50d31acb79 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/sample.yaml b/samples/philosophers/sample.yaml index d072f2c68878fb9..2db2c1563f43930 100644 --- a/samples/philosophers/sample.yaml +++ b/samples/philosophers/sample.yaml @@ -8,7 +8,7 @@ common: harness: console min_ram: 16 integration_platforms: - - native_posix + - native_sim harness_config: type: multi_line ordered: false diff --git a/samples/posix/eventfd/Makefile.host b/samples/posix/eventfd/Makefile.host new file mode 100644 index 000000000000000..b5080991747c00b --- /dev/null +++ b/samples/posix/eventfd/Makefile.host @@ -0,0 +1,5 @@ +# This makefile builds the sample for a POSIX system, like Linux + +eventfd: src/main.c + mkdir -p build + $(CC) $^ -o build/$@ diff --git a/samples/posix/eventfd/Makefile.posix b/samples/posix/eventfd/Makefile.posix deleted file mode 100644 index 8cb1f7d7da65acd..000000000000000 --- a/samples/posix/eventfd/Makefile.posix +++ /dev/null @@ -1,4 +0,0 @@ -# This makefile builds the sample for a POSIX system, like Linux - -eventfd: src/main.c - $(CC) $^ -o $@ diff --git a/samples/posix/eventfd/README.rst b/samples/posix/eventfd/README.rst new file mode 100644 index 000000000000000..c6947d6e57cdf76 --- /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/eventfd/prj.conf b/samples/posix/eventfd/prj.conf index 7ff74543b2f7c7c..4fb4280b874204d 100644 --- a/samples/posix/eventfd/prj.conf +++ b/samples/posix/eventfd/prj.conf @@ -1,5 +1,5 @@ # General config -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y CONFIG_POSIX_API=y CONFIG_EVENTFD=y diff --git a/samples/posix/eventfd/sample.yaml b/samples/posix/eventfd/sample.yaml index d1384095ae8f2ec..8e1e16b4eb7554b 100644 --- a/samples/posix/eventfd/sample.yaml +++ b/samples/posix/eventfd/sample.yaml @@ -2,7 +2,7 @@ sample: description: Extended POSIX (Linux) API eventfd() example name: eventfd common: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC tags: posix platform_exclude: m2gl025_miv integration_platforms: diff --git a/samples/posix/gettimeofday/Makefile.host b/samples/posix/gettimeofday/Makefile.host new file mode 100644 index 000000000000000..76023d7f21eaf78 --- /dev/null +++ b/samples/posix/gettimeofday/Makefile.host @@ -0,0 +1,5 @@ +# This makefile builds the sample for a POSIX system, like Linux + +gettimeofday: src/main.c + mkdir -p build + $(CC) $^ -o build/$@ diff --git a/samples/posix/gettimeofday/Makefile.posix b/samples/posix/gettimeofday/Makefile.posix deleted file mode 100644 index eb0529e1864ddee..000000000000000 --- a/samples/posix/gettimeofday/Makefile.posix +++ /dev/null @@ -1,4 +0,0 @@ -# This makefile builds the sample for a POSIX system, like Linux - -gettimeofday: src/main.c - $(CC) $^ -o $@ diff --git a/samples/posix/gettimeofday/README.rst b/samples/posix/gettimeofday/README.rst index c2c5def96d8eccf..a9cd477181858b8 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 @@ -34,9 +32,13 @@ on QEMU as follows: :goals: run :compact: -For comparison, a version for native POSIX operating systems (e.g. Linux) -can be built using: +For comparison, to build directly for your host OS if it is POSIX compliant (for ex. Linux): .. code-block:: console - make -f Makefile.posix + 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/gettimeofday/prj.conf b/samples/posix/gettimeofday/prj.conf index 033db203f16dc53..ee748221ce5e15a 100644 --- a/samples/posix/gettimeofday/prj.conf +++ b/samples/posix/gettimeofday/prj.conf @@ -1,6 +1,6 @@ # General config CONFIG_MAIN_STACK_SIZE=1088 -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y CONFIG_POSIX_API=y CONFIG_SNTP=y CONFIG_NET_CONFIG_CLOCK_SNTP_INIT=y diff --git a/samples/posix/gettimeofday/sample.yaml b/samples/posix/gettimeofday/sample.yaml index 2e21ce214573899..a71d29f09c50ad1 100644 --- a/samples/posix/gettimeofday/sample.yaml +++ b/samples/posix/gettimeofday/sample.yaml @@ -2,7 +2,8 @@ sample: description: POSIX API gettimeofday() example (with SNTP) name: gettimeofday common: - filter: ( TOOLCHAIN_HAS_NEWLIB == 1 and not CONFIG_SOC_FAMILY_INTEL_ADSP ) + filter: ( CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC + and not CONFIG_SOC_FAMILY_INTEL_ADSP ) harness: net min_ram: 32 min_flash: 96 diff --git a/samples/posix/philosophers/CMakeLists.txt b/samples/posix/philosophers/CMakeLists.txt new file mode 100644 index 000000000000000..e8a6a207987c117 --- /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) diff --git a/samples/posix/philosophers/Kconfig b/samples/posix/philosophers/Kconfig new file mode 100644 index 000000000000000..5105138ca83acc4 --- /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 000000000000000..e7e1b958e5c08e7 --- /dev/null +++ b/samples/posix/philosophers/README.rst @@ -0,0 +1,57 @@ +.. _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 000000000000000..ccee021cdf75a92 --- /dev/null +++ b/samples/posix/philosophers/prj.conf @@ -0,0 +1,25 @@ +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 + +CONFIG_LOG=y +CONFIG_LOG_MODE_MINIMAL=y + +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=7 + +#Enable thread awareness for debugging tools supporting it +CONFIG_DEBUG_THREAD_INFO=y + +# CONFIG_SAMPLE_ERROR_CHECKING=y +# CONFIG_PTHREAD_MUTEX_LOG_LEVEL_DBG=y +# CONFIG_PTHREAD_LOG_LEVEL_DBG=y diff --git a/samples/posix/philosophers/sample.yaml b/samples/posix/philosophers/sample.yaml new file mode 100644 index 000000000000000..1e3a6a2cb365f50 --- /dev/null +++ b/samples/posix/philosophers/sample.yaml @@ -0,0 +1,21 @@ +sample: + name: POSIX Philosophers +common: + tags: + - inroduction + - 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 000000000000000..bf1db7d707f052f --- /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 - 1); +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 c7b2e1d83a35d7e..f7d026eb2cd1256 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 000000000000000..d5077cf0ec68f9a --- /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 000000000000000..a7d6c69946b3e83 --- /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 7b1dfc80964584c..1f171e76a4bfdbb 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/sample.yaml b/samples/posix/uname/sample.yaml index cfe990eb127d359..f4b8b82abacfd1d 100644 --- a/samples/posix/uname/sample.yaml +++ b/samples/posix/uname/sample.yaml @@ -3,9 +3,11 @@ sample: name: posix uname common: tags: posix - filter: not CONFIG_ARCH_POSIX - integration_platforms: + platform_exclude: + - native_posix - native_posix_64 + integration_platforms: + - native_sim - qemu_riscv64 harness: console harness_config: diff --git a/samples/posix/uname/src/main.c b/samples/posix/uname/src/main.c index 93af0af529db1f6..c6a480fe6ddfebb 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/sample_definition_and_criteria.rst b/samples/sample_definition_and_criteria.rst index 5a75496aff60507..8e69fe4a63ae1a3 100644 --- a/samples/sample_definition_and_criteria.rst +++ b/samples/sample_definition_and_criteria.rst @@ -19,7 +19,7 @@ Sample Criteria * The primary purpose of a sample is to provide a reference to the user. * Samples must not use Zephyr's testing framework. - * Must not use :kconfig:option:`CONFIG_ZTEST` or :kconfig:option:`CONFIG_ZTEST_NEW_API`. + * Must not use :kconfig:option:`CONFIG_ZTEST` * Must not use zasserts in samples. * If a sample can provide output that can be verified, then output should be evaluated against @@ -38,7 +38,7 @@ Sample Criteria tests: sample.kernel.cond_var: integration_platforms: - - native_posix + - native_sim tags: kernel condition_variables harness: console harness_config: diff --git a/samples/sensor/bme280/boards/intel_adl_crb.overlay b/samples/sensor/bme280/boards/intel_adl_crb.overlay index 6b24f92e9af13d8..957dd83180a537a 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 000000000000000..5868d248950fabf --- /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 473cfae2a0bfc95..a555e93213ccf96 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/co2_polling/CMakeLists.txt b/samples/sensor/co2_polling/CMakeLists.txt new file mode 100644 index 000000000000000..ae467b6d2aa9d98 --- /dev/null +++ b/samples/sensor/co2_polling/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(co2_polling) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/sensor/co2_polling/README.rst b/samples/sensor/co2_polling/README.rst new file mode 100644 index 000000000000000..c0436b363acccaf --- /dev/null +++ b/samples/sensor/co2_polling/README.rst @@ -0,0 +1,30 @@ +.. co2: + +Generic CO2 polling sample +########################## + +Overview +******** + +A sensor sample that demonstrates how to poll a CO2 sensor. + +Building and Running +******************** + +This sample reads the CO2 sensor and print the values continuously. + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/co2_polling + :board: + :goals: build flash + :compact: + +Sample Output +============= + +.. code-block:: console + + CO2 940 ppm + CO2 950 ppm + + diff --git a/samples/sensor/co2_polling/boards/nucleo_h563zi.conf b/samples/sensor/co2_polling/boards/nucleo_h563zi.conf new file mode 100644 index 000000000000000..86df0aff3e6242a --- /dev/null +++ b/samples/sensor/co2_polling/boards/nucleo_h563zi.conf @@ -0,0 +1 @@ +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/samples/sensor/co2_polling/boards/nucleo_h563zi.overlay b/samples/sensor/co2_polling/boards/nucleo_h563zi.overlay new file mode 100644 index 000000000000000..549e34926995da6 --- /dev/null +++ b/samples/sensor/co2_polling/boards/nucleo_h563zi.overlay @@ -0,0 +1,15 @@ +/ { + aliases { + co2 = &explorir_m; + }; +}; + +&lpuart1 { + status = "okay"; + current-speed = <9600>; + + explorir_m: explorir_m { + compatible = "gss,explorir-m"; + status = "okay"; + }; +}; diff --git a/samples/sensor/co2_polling/prj.conf b/samples/sensor/co2_polling/prj.conf new file mode 100644 index 000000000000000..fe480d2b794be33 --- /dev/null +++ b/samples/sensor/co2_polling/prj.conf @@ -0,0 +1,7 @@ +CONFIG_STDOUT_CONSOLE=y +CONFIG_LOG=y +CONFIG_SHELL=y +CONFIG_SENSOR_SHELL=y +CONFIG_SERIAL=y +CONFIG_SENSOR=y +CONFIG_SENSOR_LOG_LEVEL_DBG=y diff --git a/samples/sensor/co2_polling/sample.yaml b/samples/sensor/co2_polling/sample.yaml new file mode 100644 index 000000000000000..13b4ffa6dfb4839 --- /dev/null +++ b/samples/sensor/co2_polling/sample.yaml @@ -0,0 +1,8 @@ +sample: + name: CO2 sensor sample +tests: + sample.sensor.co2: + harness: sensor + tags: sensors + filter: dt_alias_exists("co2") + depends_on: serial uart_interrupt_driven diff --git a/samples/sensor/co2_polling/src/main.c b/samples/sensor/co2_polling/src/main.c new file mode 100644 index 000000000000000..4f1845274539b96 --- /dev/null +++ b/samples/sensor/co2_polling/src/main.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023, Vitrolife A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +LOG_MODULE_REGISTER(MAIN); + +int main(void) +{ + struct sensor_value value; + const struct device *const dev = DEVICE_DT_GET(DT_ALIAS(co2)); + + if (!device_is_ready(dev)) { + LOG_ERR("%s is not ready", dev->name); + return 0; + } + + while (1) { + if (sensor_sample_fetch(dev) == 0 && + sensor_channel_get(dev, SENSOR_CHAN_CO2, &value) == 0) { + LOG_INF("CO2 %d ppm", value.val1); + } + + k_msleep(1000); + } + + return 0; +} diff --git a/samples/sensor/dht/boards/longan_nano.overlay b/samples/sensor/dht/boards/longan_nano.overlay new file mode 100644 index 000000000000000..a50cd9b94049dbc --- /dev/null +++ b/samples/sensor/dht/boards/longan_nano.overlay @@ -0,0 +1,11 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + dht22 { + compatible = "aosong,dht"; + status = "okay"; + dio-gpios = <&gpiob 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; +}; diff --git a/samples/sensor/dht/prj.conf b/samples/sensor/dht/prj.conf index 9555c35279317e7..33811ecb1719b52 100644 --- a/samples/sensor/dht/prj.conf +++ b/samples/sensor/dht/prj.conf @@ -8,6 +8,6 @@ CONFIG_SENSOR=y CONFIG_GPIO=y # Need float format support -CONFIG_NEWLIB_LIBC=y -CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y +CONFIG_REQUIRES_FULL_LIBC=y +CONFIG_REQUIRES_FLOAT_PRINTF=y CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/samples/sensor/dht/sample.yaml b/samples/sensor/dht/sample.yaml index 74f346bd31ddaff..ad74cb83d9cc758 100644 --- a/samples/sensor/dht/sample.yaml +++ b/samples/sensor/dht/sample.yaml @@ -5,7 +5,7 @@ # common: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED sample: name: DHT Sensor Sample tests: diff --git a/samples/sensor/dht_polling/CMakeLists.txt b/samples/sensor/dht_polling/CMakeLists.txt new file mode 100644 index 000000000000000..31b4352da9d70f1 --- /dev/null +++ b/samples/sensor/dht_polling/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Ian Morris +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(dht_polling) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/sensor/dht_polling/README.rst b/samples/sensor/dht_polling/README.rst new file mode 100644 index 000000000000000..09550b255d00b47 --- /dev/null +++ b/samples/sensor/dht_polling/README.rst @@ -0,0 +1,49 @@ +.. _dht_polling: + +Generic Digital Humidity Temperature sensor polling sample +########################################################## + +Overview +******** + +This sample application demonstrates how to use digital humidity temperature +sensors. + +Building and Running +******************** + +This sample supports up to 10 humidity/temperature sensors. Each sensor needs to +be aliased as ``dhtN`` where ``N`` goes from ``0`` to ``9``. For example: + +.. code-block:: devicetree + + / { + aliases { + dht0 = &hs300x; + }; + }; + +Make sure the aliases are in devicetree, then build and run with: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/dht_polling + :board: + :goals: build flash + :compact: + +Sample Output +============= + +.. code-block:: console + + hs300x@44: temp is 25.31 °C humidity is 30.39 %RH + hs300x@44: temp is 25.51 °C humidity is 30.44 %RH + hs300x@44: temp is 25.51 °C humidity is 30.37 %RH + hs300x@44: temp is 25.51 °C humidity is 30.39 %RH + hs300x@44: temp is 25.31 °C humidity is 30.37 %RH + hs300x@44: temp is 25.31 °C humidity is 30.35 %RH + hs300x@44: temp is 25.51 °C humidity is 30.37 %RH + hs300x@44: temp is 25.51 °C humidity is 30.37 %RH + hs300x@44: temp is 25.51 °C humidity is 30.39 %RH + hs300x@44: temp is 25.51 °C humidity is 30.44 %RH + hs300x@44: temp is 25.51 °C humidity is 30.53 %RH diff --git a/samples/sensor/dht_polling/boards/nucleo_f401re.overlay b/samples/sensor/dht_polling/boards/nucleo_f401re.overlay new file mode 100644 index 000000000000000..cb381b5ba3a0f0c --- /dev/null +++ b/samples/sensor/dht_polling/boards/nucleo_f401re.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Ian Morris + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + dht0 = &hs300x; + }; +}; + + &i2c1 { + status = "okay"; + + hs300x: hs300x@44 { + compatible = "renesas,hs300x"; + reg = <0x44>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; diff --git a/samples/sensor/dht_polling/prj.conf b/samples/sensor/dht_polling/prj.conf new file mode 100644 index 000000000000000..7d668be1f0b1957 --- /dev/null +++ b/samples/sensor/dht_polling/prj.conf @@ -0,0 +1,2 @@ +CONFIG_STDOUT_CONSOLE=y +CONFIG_SENSOR=y diff --git a/samples/sensor/dht_polling/sample.yaml b/samples/sensor/dht_polling/sample.yaml new file mode 100644 index 000000000000000..8177e636d21670f --- /dev/null +++ b/samples/sensor/dht_polling/sample.yaml @@ -0,0 +1,20 @@ +# +# Copyright (c) 2023 Ian Morris +# +# SPDX-License-Identifier: Apache-2.0 +# + +sample: + description: Digital Humidity Temperature polling sample + name: DHT polling sample +tests: + sample.sensor.dht_polling: + tags: sensors + filter: dt_alias_exists("dht0") + integration_platforms: + - nucleo_f401re + harness: console + harness_config: + type: one_line + regex: + - "[0-9A-Za-z_,+-.]*@[0-9A-Fa-f]*: temp is (.*) °C humidity is (.*) %RH" diff --git a/samples/sensor/dht_polling/src/main.c b/samples/sensor/dht_polling/src/main.c new file mode 100644 index 000000000000000..8ff26b5ab9b0acf --- /dev/null +++ b/samples/sensor/dht_polling/src/main.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 Ian Morris + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include + +#define DHT_ALIAS(i) DT_ALIAS(_CONCAT(dht, i)) +#define DHT_DEVICE(i, _) \ + IF_ENABLED(DT_NODE_EXISTS(DHT_ALIAS(i)), (DEVICE_DT_GET(DHT_ALIAS(i)),)) + +/* Support up to 10 temperature/humidity sensors */ +static const struct device *const sensors[] = {LISTIFY(10, DHT_DEVICE, ())}; + +int main(void) +{ + int rc; + + for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) { + if (!device_is_ready(sensors[i])) { + printk("sensor: device %s not ready.\n", sensors[i]->name); + return 0; + } + } + + while (1) { + for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) { + struct device *dev = (struct device *)sensors[i]; + + rc = sensor_sample_fetch(dev); + if (rc < 0) { + printk("%s: sensor_sample_fetch() failed: %d\n", dev->name, rc); + return rc; + } + + struct sensor_value temp; + struct sensor_value hum; + + rc = sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp); + if (rc == 0) { + rc = sensor_channel_get(dev, SENSOR_CHAN_HUMIDITY, &hum); + } + if (rc != 0) { + printf("get failed: %d\n", rc); + break; + } + + printk("%16s: temp is %d.%02d °C humidity is %d.%02d %%RH\n", + dev->name, temp.val1, temp.val2 / 10000, + hum.val1, hum.val2 / 10000); + } + k_msleep(1000); + } + return 0; +} diff --git a/samples/sensor/die_temp_polling/boards/esp32c3_devkitm.conf b/samples/sensor/die_temp_polling/boards/esp32c3_devkitm.conf index 13ed95d4291da27..5ab7306afeb3922 100644 --- a/samples/sensor/die_temp_polling/boards/esp32c3_devkitm.conf +++ b/samples/sensor/die_temp_polling/boards/esp32c3_devkitm.conf @@ -1 +1 @@ -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y diff --git a/samples/sensor/die_temp_polling/boards/esp32c3_luatos_core.conf b/samples/sensor/die_temp_polling/boards/esp32c3_luatos_core.conf index 13ed95d4291da27..5ab7306afeb3922 100644 --- a/samples/sensor/die_temp_polling/boards/esp32c3_luatos_core.conf +++ b/samples/sensor/die_temp_polling/boards/esp32c3_luatos_core.conf @@ -1 +1 @@ -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y diff --git a/samples/sensor/die_temp_polling/boards/esp32c3_luatos_core_usb.conf b/samples/sensor/die_temp_polling/boards/esp32c3_luatos_core_usb.conf index 13ed95d4291da27..5ab7306afeb3922 100644 --- a/samples/sensor/die_temp_polling/boards/esp32c3_luatos_core_usb.conf +++ b/samples/sensor/die_temp_polling/boards/esp32c3_luatos_core_usb.conf @@ -1 +1 @@ -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y diff --git a/samples/sensor/die_temp_polling/boards/esp32s2_saola.conf b/samples/sensor/die_temp_polling/boards/esp32s2_saola.conf index 13ed95d4291da27..5ab7306afeb3922 100644 --- a/samples/sensor/die_temp_polling/boards/esp32s2_saola.conf +++ b/samples/sensor/die_temp_polling/boards/esp32s2_saola.conf @@ -1 +1 @@ -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y 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 000000000000000..aeb8043f62114cf --- /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/die_temp_polling/boards/mimxrt1050_evk.conf b/samples/sensor/die_temp_polling/boards/mimxrt1050_evk.conf index 13ed95d4291da27..5ab7306afeb3922 100644 --- a/samples/sensor/die_temp_polling/boards/mimxrt1050_evk.conf +++ b/samples/sensor/die_temp_polling/boards/mimxrt1050_evk.conf @@ -1 +1 @@ -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y diff --git a/samples/sensor/fdc2x1x/prj.conf b/samples/sensor/fdc2x1x/prj.conf index f0275d2e97e205c..2b9602b1fc824dc 100644 --- a/samples/sensor/fdc2x1x/prj.conf +++ b/samples/sensor/fdc2x1x/prj.conf @@ -2,7 +2,7 @@ CONFIG_LOG=y CONFIG_I2C=y CONFIG_SENSOR=y CONFIG_PM_DEVICE=n -CONFIG_NEWLIB_LIBC=y -CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y +CONFIG_REQUIRES_FULL_LIBC=y +CONFIG_REQUIRES_FLOAT_PRINTF=y CONFIG_FDC2X1X_TRIGGER_GLOBAL_THREAD=n diff --git a/samples/sensor/grove_light/prj.conf b/samples/sensor/grove_light/prj.conf index 7aafd3830843964..dc1d0ec21393487 100644 --- a/samples/sensor/grove_light/prj.conf +++ b/samples/sensor/grove_light/prj.conf @@ -1,5 +1,5 @@ CONFIG_ADC=y CONFIG_SENSOR=y -CONFIG_NEWLIB_LIBC=y -CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y +CONFIG_REQUIRES_FULL_LIBC=y +CONFIG_REQUIRES_FLOAT_PRINTF=y CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/samples/sensor/grove_light/sample.yaml b/samples/sensor/grove_light/sample.yaml index df34be19f7a7146..3eb1083a883f46c 100644 --- a/samples/sensor/grove_light/sample.yaml +++ b/samples/sensor/grove_light/sample.yaml @@ -1,5 +1,5 @@ common: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED sample: name: Grove Light Sensor tests: diff --git a/samples/sensor/grove_temperature/prj.conf b/samples/sensor/grove_temperature/prj.conf index 7aafd3830843964..dc1d0ec21393487 100644 --- a/samples/sensor/grove_temperature/prj.conf +++ b/samples/sensor/grove_temperature/prj.conf @@ -1,5 +1,5 @@ CONFIG_ADC=y CONFIG_SENSOR=y -CONFIG_NEWLIB_LIBC=y -CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y +CONFIG_REQUIRES_FULL_LIBC=y +CONFIG_REQUIRES_FLOAT_PRINTF=y CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/samples/sensor/grove_temperature/sample.yaml b/samples/sensor/grove_temperature/sample.yaml index 0076845543e9c44..83035b9b9fb613e 100644 --- a/samples/sensor/grove_temperature/sample.yaml +++ b/samples/sensor/grove_temperature/sample.yaml @@ -1,5 +1,5 @@ common: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED sample: name: Grove Temperature Sensor tests: diff --git a/samples/sensor/grove_temperature/src/main.c b/samples/sensor/grove_temperature/src/main.c index 643ae4707e2223f..c49137f6018432f 100644 --- a/samples/sensor/grove_temperature/src/main.c +++ b/samples/sensor/grove_temperature/src/main.c @@ -63,7 +63,7 @@ int main(void) /* display temperature on LCD */ glcd_cursor_pos_set(glcd, 0, 0); -#ifdef CONFIG_NEWLIB_LIBC_FLOAT_PRINTF +#ifdef CONFIG_REQUIRES_FLOAT_PRINTF sprintf(row, "T:%.2f%cC", sensor_value_to_double(&temp), 223 /* degree symbol */); @@ -75,7 +75,7 @@ int main(void) #endif -#ifdef CONFIG_NEWLIB_LIBC_FLOAT_PRINTF +#ifdef CONFIG_REQUIRES_FLOAT_PRINTF printf("Temperature: %.2f C\n", sensor_value_to_double(&temp)); #else printk("Temperature: %d\n", temp.val1); diff --git a/samples/sensor/hts221/sample.yaml b/samples/sensor/hts221/sample.yaml index beffa273cfd4a58..472986177a109f5 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 f469f05b6db73f4..4ff98457e50ced5 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 d347ea8534597e5..4562dd868bbc60e 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 d347ea8534597e5..4562dd868bbc60e 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 d347ea8534597e5..4562dd868bbc60e 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 000000000000000..3d872a2071bf885 --- /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/sensor/sensor_shell/boards/tdk_robokit1.conf b/samples/sensor/sensor_shell/boards/tdk_robokit1.conf new file mode 100644 index 000000000000000..aee20b8b10049ce --- /dev/null +++ b/samples/sensor/sensor_shell/boards/tdk_robokit1.conf @@ -0,0 +1,3 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 +CONFIG_SPI_RTIO=y diff --git a/samples/sensor/sensor_shell/sample.yaml b/samples/sensor/sensor_shell/sample.yaml index 7b194f4d6227819..d89dfebc21aae23 100644 --- a/samples/sensor/sensor_shell/sample.yaml +++ b/samples/sensor/sensor_shell/sample.yaml @@ -4,6 +4,8 @@ tests: sample.sensor.shell: integration_platforms: - frdm_k64f + # TODO Remove once #63414 is resolved + platform_exclude: gd32l233r_eval filter: ( CONFIG_UART_CONSOLE and CONFIG_SERIAL_SUPPORT_INTERRUPT ) tags: shell harness: keyboard diff --git a/samples/shields/lmp90100_evb/rtd/app.overlay b/samples/shields/lmp90100_evb/rtd/app.overlay index 7ea69d39c83f677..27044a27865182c 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 939f2c331ad51f7..040a1d23509b370 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 339ad015c0c73df..762a84311fb5ec6 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 7b134995827eea6..975d56d4e509d45 100644 --- a/samples/shields/npm1300_ek/prj.conf +++ b/samples/shields/npm1300_ek/prj.conf @@ -4,6 +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 62e1059cf09eff6..47ed6214677bed6 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/npm6001_ek/prj.conf b/samples/shields/npm6001_ek/prj.conf index bfacbe8b14bf8be..94da7cfdaef63f3 100644 --- a/samples/shields/npm6001_ek/prj.conf +++ b/samples/shields/npm6001_ek/prj.conf @@ -7,4 +7,5 @@ CONFIG_GETOPT=y CONFIG_GETOPT_LONG=y CONFIG_GPIO=y CONFIG_REGULATOR=y +CONFIG_REGULATOR_SHELL=y CONFIG_WATCHDOG=y 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 000000000000000..e901945a06239d8 --- /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 000000000000000..73296ce36ca4849 --- /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 000000000000000..f7af0f8fe0fc3d2 --- /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 000000000000000..bec5bda73ff2ed3 --- /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 000000000000000..0454a75dd90e408 --- /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 000000000000000..9ad8c2e6b0190e1 --- /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 000000000000000..9fc28a45b574518 --- /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 000000000000000..8637d6b6c1a5611 --- /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 000000000000000..1931d2aaa4a1cc9 --- /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 000000000000000..e4351acb360a6c1 --- /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 000000000000000..1e8a99f3f81ff69 --- /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 000000000000000..0dfc2651da7eeec --- /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 000000000000000..2e9e206de76a3c4 --- /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 000000000000000..54a66edb45ac715 --- /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 000000000000000..15ac7805452385f --- /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/bindesc/hello_bindesc/README.rst b/samples/subsys/bindesc/hello_bindesc/README.rst index f2cd9e2d16eb71a..0596639b518c96a 100644 --- a/samples/subsys/bindesc/hello_bindesc/README.rst +++ b/samples/subsys/bindesc/hello_bindesc/README.rst @@ -27,6 +27,6 @@ To dump all binary descriptors in the image, run: west bindesc dump build/zephyr/zephyr.bin (Note: you can also dump the contents of ``zephyr.elf``, if your build system -does not produce a ``*.bin`` file, e.g. compiling for ``native_posix``.) +does not produce a ``*.bin`` file, e.g. compiling for ``native_sim``.) For more details see :ref:`binary_descriptors` and :ref:`west-bindesc`. diff --git a/samples/subsys/bindesc/hello_bindesc/sample.yaml b/samples/subsys/bindesc/hello_bindesc/sample.yaml index e923744c3d842af..2725b9ab241bb77 100644 --- a/samples/subsys/bindesc/hello_bindesc/sample.yaml +++ b/samples/subsys/bindesc/hello_bindesc/sample.yaml @@ -3,7 +3,18 @@ sample: tests: sample.bindesc: tags: bindesc - filter: CONFIG_ARCH_SUPPORTS_ROM_START - build_only: true + filter: CONFIG_ARCH_SUPPORTS_ROM_START or CONFIG_ARCH_POSIX integration_platforms: - - native_posix + - native_sim + harness: console + harness_config: + type: multi_line + ordered: true + regex: + - "Zephyr version: " + - "App version: 1.0.0" + - "Build time: " + - "Compiler: " + - "my_string: Hello world!" + - "my_int: 5" + - "my_bytes: 01 02 03 04" diff --git a/samples/subsys/canbus/isotp/Kconfig b/samples/subsys/canbus/isotp/Kconfig index 2ee75804b704b3e..9fd282d2282d945 100644 --- a/samples/subsys/canbus/isotp/Kconfig +++ b/samples/subsys/canbus/isotp/Kconfig @@ -23,7 +23,7 @@ config SAMPLE_RX_THREAD_PRIORITY Priority used for the RX threads. config SAMPLE_CAN_FD_MODE - bool "Use CAN-FD" + bool "Use CAN FD" select CAN_FD_MODE config ISOTP_RX_BUF_COUNT diff --git a/samples/subsys/canbus/isotp/sample.yaml b/samples/subsys/canbus/isotp/sample.yaml index 9bb24251656cdac..0036552b67b10d9 100644 --- a/samples/subsys/canbus/isotp/sample.yaml +++ b/samples/subsys/canbus/isotp/sample.yaml @@ -25,6 +25,8 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 harness: console harness_config: type: one_line diff --git a/samples/subsys/console/echo/README.rst b/samples/subsys/console/echo/README.rst new file mode 100644 index 000000000000000..b5851f16265591a --- /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 9029cc44ae771a5..8c0c8bc347125e5 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/debug/gdbstub/CMakeLists.txt b/samples/subsys/debug/gdbstub/CMakeLists.txt deleted file mode 100644 index 9759ca6c7f0c365..000000000000000 --- a/samples/subsys/debug/gdbstub/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) - -if(BOARD MATCHES "qemu_x86") - list(APPEND QEMU_EXTRA_FLAGS -serial tcp:127.0.0.1:5678,server) -endif() - -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(debug) - -target_sources(app PRIVATE src/main.c) diff --git a/samples/subsys/debug/gdbstub/README.rst b/samples/subsys/debug/gdbstub/README.rst deleted file mode 100644 index dc8430cd339891c..000000000000000 --- a/samples/subsys/debug/gdbstub/README.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. zephyr:code-sample:: gdb-debug - :name: GDB debug - - Use GDB Remote Serial Protocol to debug a Zephyr application running on QEMU. - -Overview -******** - -A simple sample that can be used with QEMU to show debug using GDB -Remote Serial Protocol (RSP) capabilities. - -Building and Running -******************** - -This application can be built and executed on QEMU as follows: - -.. zephyr-app-commands:: - :zephyr-app: samples/subsys/debug/gdbstub - :host-os: unix - :board: qemu_x86 - :goals: run - :compact: - -Open a new terminal and use gdb to connect to the running qemu as follows: - -.. code-block:: bash - - gdb build/zephyr/zephyr.elf - (gdb) target remote :5678 - -Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. diff --git a/samples/subsys/debug/gdbstub/prj.conf b/samples/subsys/debug/gdbstub/prj.conf deleted file mode 100644 index da68f3823c4d5cf..000000000000000 --- a/samples/subsys/debug/gdbstub/prj.conf +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG_GDBSTUB=y -CONFIG_NO_OPTIMIZATIONS=y -CONFIG_USERSPACE=y -CONFIG_KOBJECT_TEXT_AREA=4096 diff --git a/samples/subsys/debug/gdbstub/pytest/test_gdbstub.py b/samples/subsys/debug/gdbstub/pytest/test_gdbstub.py deleted file mode 100755 index 41dca1cfcae9a86..000000000000000 --- a/samples/subsys/debug/gdbstub/pytest/test_gdbstub.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2023 Intel Corporation. -# -# SPDX-License-Identifier: Apache-2.0 - -import os -import subprocess -from twister_harness import DeviceAdapter -import sys -import logging -import shlex - -ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") -sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts", "pylib", "twister")) -from twisterlib.cmakecache import CMakeCache - -logger = logging.getLogger(__name__) - - -def test_gdbstub(dut: DeviceAdapter): - """ - Test gdbstub feature using a gdb script. We connect to the DUT and run some - basic gdb commands and evaluate return code to determine pass or failure. - """ - build_dir = dut.device_config.build_dir - cmake_cache = CMakeCache.from_file(build_dir / 'CMakeCache.txt') - gdb = cmake_cache.get('CMAKE_GDB', None) - assert gdb - source_dir = cmake_cache.get('APPLICATION_SOURCE_DIR', None) - assert source_dir - cmd = [gdb, '-x', f'{source_dir}/run.gdbinit', f'{build_dir}/zephyr/zephyr.elf'] - logger.info(f'Test command: {shlex.join(cmd)}') - result = subprocess.run(cmd, capture_output=True, text=True, timeout=20) - logger.debug('Output:\n%s' % result.stdout) - assert result.returncode == 0 diff --git a/samples/subsys/debug/gdbstub/run.gdbinit b/samples/subsys/debug/gdbstub/run.gdbinit deleted file mode 100644 index abce598f54af7a3..000000000000000 --- a/samples/subsys/debug/gdbstub/run.gdbinit +++ /dev/null @@ -1,17 +0,0 @@ -set pagination off -#symbol-file build/zephyr/zephyr.elf -target remote :5678 -b test -b main.c:33 -c - -s -set var a = 2 -c -if ret == 6 - printf "PASSED\n" - quit 0 -else - printf "FAILED\n" - quit 1 -end diff --git a/samples/subsys/debug/gdbstub/sample.yaml b/samples/subsys/debug/gdbstub/sample.yaml deleted file mode 100644 index 638c5ec16cc37b8..000000000000000 --- a/samples/subsys/debug/gdbstub/sample.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# -# Copyright (c) 2020 intel Corporation. -# -# SPDX-License-Identifier: Apache-2.0 -# - -sample: - name: gdbstub sample -tests: - sample.debug.gdbstub: - platform_allow: qemu_x86 - harness: pytest - tags: - - debug - - gdbstub diff --git a/samples/subsys/debug/gdbstub/src/main.c b/samples/subsys/debug/gdbstub/src/main.c deleted file mode 100644 index 51995db4ab7370a..000000000000000 --- a/samples/subsys/debug/gdbstub/src/main.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#define STACKSIZE 512 - -static int test(void) -{ - int a; - int b; - - a = 10; - b = a * 2; - - return a + b; -} - -static void thread_entry(void *p1, void *p2, void *p3) -{ - printk("Hello from user thread!\n"); -} - -int main(void) -{ - int ret; - - ret = test(); - printk("%d\n", ret); - return 0; -} - -K_THREAD_DEFINE(thread, STACKSIZE, thread_entry, NULL, NULL, NULL, - 7, K_USER, 0); diff --git a/samples/subsys/display/lvgl/README.rst b/samples/subsys/display/lvgl/README.rst index e7312a2791b7647..be5eecd9db1960a 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 ************ @@ -27,9 +46,9 @@ or a board with an integrated display: - :ref:`esp_wrover_kit` -or a simulated display environment in a native Posix application: +or a simulated display environment in a :ref:`native_sim ` application: -- :ref:`native_posix` +- :ref:`native_sim` - `SDL2`_ or @@ -53,15 +72,15 @@ Example building for :ref:`nrf52840dk_nrf52840`: :shield: adafruit_2_8_tft_touch_v2 :goals: build flash -Example building for :ref:`native_posix`: +Example building for :ref:`native_sim `: .. zephyr-app-commands:: :zephyr-app: samples/subsys/display/lvgl - :board: native_posix + :board: native_sim :goals: build run Alternatively, if building from a 64-bit host machine, the previous target -board argument may also be replaced by ``native_posix_64``. +board argument may also be replaced by ``native_sim_64``. References ********** diff --git a/samples/subsys/display/lvgl/boards/native_posix.overlay b/samples/subsys/display/lvgl/boards/native_posix.overlay index 43cc9818d5aa0f9..29c03cc09284ae7 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 000000000000000..de103d88fedb2f6 --- /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 000000000000000..2f9e228cd8218b3 --- /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 d53bc36aaa771fc..3c6e56cdfe124bc 100644 --- a/samples/subsys/display/lvgl/sample.yaml +++ b/samples/subsys/display/lvgl/sample.yaml @@ -19,7 +19,7 @@ tests: modules: - lvgl integration_platforms: - - native_posix_64 + - native_sim_64 sample.display.lvgl.rk055hdmipi4m: # This sample is intended to test the RT1170 and RT595, which require # a display shield to work with LVGL @@ -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 d58be5502781880..2fca16023adecb8 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/edac/README.rst b/samples/subsys/edac/README.rst index 2548284928a4626..fb556b1c07b5b6c 100644 --- a/samples/subsys/edac/README.rst +++ b/samples/subsys/edac/README.rst @@ -34,7 +34,9 @@ Getting help ============ After the application has started help can be read with the following -command:: +command: + +.. code-block:: console uart:~$ edac -h edac - EDAC information @@ -44,7 +46,9 @@ command:: inject :Inject ECC error commands edac inject -Help for subcommand info can be read with:: +Help for subcommand info can be read with: + +.. code-block:: console uart:~$ edac info -h info - Show EDAC information @@ -53,7 +57,9 @@ Help for subcommand info can be read with:: ecc_error :ECC Error Show / Clear commands parity_error :Parity Error Show / Clear commands -Injection help can be received with:: +Injection help can be received with: + +.. code-block:: console uart:~$ edac inject -h inject - Inject ECC error commands @@ -70,7 +76,9 @@ Injection help can be received with:: Testing Error Injection ======================= -Set Error Injection parameters with:: +Set Error Injection parameters with: + +.. code-block:: console uart:~$ edac inject addr 0x1000 Set injection address base to: 0x1000 @@ -81,13 +89,17 @@ Set Error Injection parameters with:: uart:~$ edac inject error_type correctable Set injection error type: correctable -Trigger injection with:: +Trigger injection with: + +.. code-block:: console uart:~$ edac inject trigger Triggering injection Now Read / Write to the injection address to trigger Error Injection with -following devmem commands:: +following devmem commands: + +.. code-block:: console uart:~$ devmem 0x1000 32 0xabcd Mapped 0x1000 to 0x2ffcf000 @@ -101,6 +113,8 @@ following devmem commands:: Using data width 32 Read value 0xabcd -We should get the following message on screen indicating an IBECC event:: +We should get the following message on screen indicating an IBECC event: + +.. code-block:: none Got notification about IBECC event diff --git a/samples/subsys/fs/format/sample.yaml b/samples/subsys/fs/format/sample.yaml index ca93e00f075c244..aafe86f79891328 100644 --- a/samples/subsys/fs/format/sample.yaml +++ b/samples/subsys/fs/format/sample.yaml @@ -4,12 +4,14 @@ tests: sample.filesystem.format.littlefs: platform_allow: - native_posix + - native_sim - nrf52dk_nrf52832 build_only: true tags: filesystem sample.filesystem.format.fat_fs: platform_allow: - native_posix + - native_sim - mimxrt1064_evk build_only: true extra_args: 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 000000000000000..22d18f5879cb46c --- /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/boards/stm32h747i_disco_m7.conf b/samples/subsys/fs/fs_sample/boards/stm32h747i_disco_m7.conf new file mode 100644 index 000000000000000..857d2e8ddfd888d --- /dev/null +++ b/samples/subsys/fs/fs_sample/boards/stm32h747i_disco_m7.conf @@ -0,0 +1 @@ +CONFIG_SDMMC_STM32_HWFC=y diff --git a/samples/subsys/fs/fs_sample/boards/stm32h747i_disco_m7.overlay b/samples/subsys/fs/fs_sample/boards/stm32h747i_disco_m7.overlay new file mode 100644 index 000000000000000..d80aa5114fc39fb --- /dev/null +++ b/samples/subsys/fs/fs_sample/boards/stm32h747i_disco_m7.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2023 S&C Electric Company + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&sdmmc1 { + sdmmc { + compatible = "zephyr,sdmmc-disk"; + }; +}; diff --git a/samples/subsys/fs/fs_sample/sample.yaml b/samples/subsys/fs/fs_sample/sample.yaml index e022ca1e4c164bf..58c0cf623619dd6 100644 --- a/samples/subsys/fs/fs_sample/sample.yaml +++ b/samples/subsys/fs/fs_sample/sample.yaml @@ -43,5 +43,12 @@ 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: + build_only: true + platform_allow: stm32h747i_disco_m7 + extra_args: + - OVERLAY_CONFIG=boards/stm32h747i_disco_m7.conf diff --git a/samples/subsys/fs/littlefs/boards/nucleo_h743zi_blk.conf b/samples/subsys/fs/littlefs/boards/nucleo_h743zi_blk.conf index eeabf1150b0eb15..a5663cf11a2a766 100644 --- a/samples/subsys/fs/littlefs/boards/nucleo_h743zi_blk.conf +++ b/samples/subsys/fs/littlefs/boards/nucleo_h743zi_blk.conf @@ -7,3 +7,4 @@ CONFIG_MAIN_STACK_SIZE=2048 CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=8192 CONFIG_FS_LITTLEFS_FC_HEAP_SIZE=8192 +CONFIG_SDMMC_STM32_HWFC=y diff --git a/samples/subsys/fs/littlefs/boards/stm32h747i_disco_m7.conf b/samples/subsys/fs/littlefs/boards/stm32h747i_disco_m7.conf new file mode 100644 index 000000000000000..a45f607811f049b --- /dev/null +++ b/samples/subsys/fs/littlefs/boards/stm32h747i_disco_m7.conf @@ -0,0 +1,3 @@ +CONFIG_SDMMC_STM32_HWFC=y +CONFIG_FS_LITTLEFS_FC_HEAP_SIZE=2048 +CONFIG_MAIN_STACK_SIZE=2048 diff --git a/samples/subsys/fs/littlefs/boards/stm32h747i_disco_m7.overlay b/samples/subsys/fs/littlefs/boards/stm32h747i_disco_m7.overlay new file mode 100644 index 000000000000000..cf1c30e2e87b8c7 --- /dev/null +++ b/samples/subsys/fs/littlefs/boards/stm32h747i_disco_m7.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2023 S&C Electric Company + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&sdmmc1 { + sdmmc { + compatible = "zephyr,sdmmc-disk"; + }; +}; diff --git a/samples/subsys/fs/littlefs/prj_blk.conf b/samples/subsys/fs/littlefs/prj_blk.conf index 7df323b59f34d14..011f919a5680847 100644 --- a/samples/subsys/fs/littlefs/prj_blk.conf +++ b/samples/subsys/fs/littlefs/prj_blk.conf @@ -19,4 +19,3 @@ CONFIG_FS_LITTLEFS_BLK_DEV=y CONFIG_APP_LITTLEFS_STORAGE_BLK_SDMMC=y CONFIG_NOCACHE_MEMORY=y -CONFIG_SDMMC_STM32_HWFC=y diff --git a/samples/subsys/fs/littlefs/sample.yaml b/samples/subsys/fs/littlefs/sample.yaml index d22cfbbd2358217..cee428271733cd0 100644 --- a/samples/subsys/fs/littlefs/sample.yaml +++ b/samples/subsys/fs/littlefs/sample.yaml @@ -16,6 +16,7 @@ tests: - mimxrt1064_evk - qemu_x86 - native_posix + - native_sim - mimxrt1160_evk_cm7 - lpcxpresso55s69_cpu0 - mr_canhubk3 @@ -33,3 +34,9 @@ tests: extra_args: - OVERLAY_CONFIG=boards/nrf52840dk_nrf52840_qspi.conf - DTC_OVERLAY_FILE=boards/nrf52840dk_nrf52840_qspi.overlay + sample.filesystem.littlefs.stm32h747i_disco_m7_sdmmc: + build_only: true + platform_allow: stm32h747i_disco_m7 + extra_args: + - OVERLAY_CONFIG=boards/stm32h747i_disco_m7.conf + - CONF_FILE=prj_blk.conf diff --git a/samples/subsys/input/input_dump/Kconfig b/samples/subsys/input/input_dump/Kconfig new file mode 100644 index 000000000000000..680cafae127e446 --- /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 000000000000000..3ed71e8b1375bc7 --- /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 000000000000000..3ed71e8b1375bc7 --- /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 000000000000000..3ed71e8b1375bc7 --- /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 000000000000000..3ed71e8b1375bc7 --- /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 04a867b8a0733ee..7015f6026aeeb5b 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_posix + sample.input.input_dump: {} + sample.input.input_dump_shell: + extra_configs: + - CONFIG_SHELL=y diff --git a/samples/subsys/ipc/ipc_service/icmsg/CMakeLists.txt b/samples/subsys/ipc/ipc_service/icmsg/CMakeLists.txt index 31bc4418c9dd475..2d9d62bdf23ac9f 100644 --- a/samples/subsys/ipc/ipc_service/icmsg/CMakeLists.txt +++ b/samples/subsys/ipc/ipc_service/icmsg/CMakeLists.txt @@ -6,15 +6,12 @@ cmake_minimum_required(VERSION 3.20.0) -set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/ipc_service_remote-prefix/src/ipc_service_remote-build/zephyr) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") - set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet") -else() +if(NOT ("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp")) message(FATAL_ERROR "${BOARD} is not supported for this sample") endif() -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(ipc_service_host) target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/common) @@ -22,13 +19,3 @@ target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/common) target_sources(app PRIVATE src/main.c) include(ExternalProject) - -ExternalProject_Add( - ipc_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 -) diff --git a/samples/subsys/ipc/ipc_service/icmsg/Kconfig.sysbuild b/samples/subsys/ipc/ipc_service/icmsg/Kconfig.sysbuild new file mode 100644 index 000000000000000..47884745130c147 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/icmsg/Kconfig.sysbuild @@ -0,0 +1,9 @@ +# 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" diff --git a/samples/subsys/ipc/ipc_service/icmsg/README.rst b/samples/subsys/ipc/ipc_service/icmsg/README.rst index 81426ee935328c1..c12c410707592f4 100644 --- a/samples/subsys/ipc/ipc_service/icmsg/README.rst +++ b/samples/subsys/ipc/ipc_service/icmsg/README.rst @@ -18,6 +18,7 @@ Building the application for nrf5340dk_nrf5340_cpuapp :zephyr-app: samples/subsys/ipc/ipc_service/icmsg :board: nrf5340dk_nrf5340_cpuapp :goals: debug + :west-args: --sysbuild Open a serial terminal (minicom, putty, etc.) and connect the board with the following settings: diff --git a/samples/subsys/ipc/ipc_service/icmsg/remote/sample.yaml b/samples/subsys/ipc/ipc_service/icmsg/remote/sample.yaml deleted file mode 100644 index 3b927c11f371bce..000000000000000 --- a/samples/subsys/ipc/ipc_service/icmsg/remote/sample.yaml +++ /dev/null @@ -1,9 +0,0 @@ -sample: - name: IPC Service example integration (icmsg backend) (remote) -tests: - sample.ipc.icmsg_remote: - platform_allow: nrf5340dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet - tags: ipc - harness: remote diff --git a/samples/subsys/ipc/ipc_service/icmsg/sample.yaml b/samples/subsys/ipc/ipc_service/icmsg/sample.yaml index 582f277ce7a6b13..b54fc7f89620375 100644 --- a/samples/subsys/ipc/ipc_service/icmsg/sample.yaml +++ b/samples/subsys/ipc/ipc_service/icmsg/sample.yaml @@ -6,4 +6,5 @@ tests: integration_platforms: - nrf5340dk_nrf5340_cpuapp tags: ipc + sysbuild: true harness: remote diff --git a/samples/subsys/ipc/ipc_service/icmsg/sysbuild.cmake b/samples/subsys/ipc/ipc_service/icmsg/sysbuild.cmake new file mode 100644 index 000000000000000..d0d79b8f2408402 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/icmsg/sysbuild.cmake @@ -0,0 +1,14 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "") + message(FATAL_ERROR + "Target ${BOARD} not supported for this sample. " + "There is no remote board selected in Kconfig.sysbuild") +endif() + +ExternalZephyrProject_Add( + APPLICATION remote + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_NET_CORE_BOARD} +) diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/CMakeLists.txt b/samples/subsys/ipc/ipc_service/icmsg_me/CMakeLists.txt deleted file mode 100644 index 5317f899424e467..000000000000000 --- a/samples/subsys/ipc/ipc_service/icmsg_me/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (c) 2022 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: Apache-2.0 -# - -cmake_minimum_required(VERSION 3.20.0) - -set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/ipc_service_remote-prefix/src/ipc_service_remote-build/zephyr) - -if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") - set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet") -else() - message(FATAL_ERROR "${BOARD} is not supported for this sample") -endif() - -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(ipc_service) - -target_sources(app PRIVATE src/main.c) - -include(ExternalProject) - -ExternalProject_Add( - ipc_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 -) diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/prj.conf b/samples/subsys/ipc/ipc_service/icmsg_me/prj.conf deleted file mode 100644 index 5feb10b31200f50..000000000000000 --- a/samples/subsys/ipc/ipc_service/icmsg_me/prj.conf +++ /dev/null @@ -1,8 +0,0 @@ -CONFIG_PRINTK=y - -CONFIG_IPC_SERVICE=y -CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX=y -CONFIG_MBOX=y - -CONFIG_LOG=y -CONFIG_IPC_SERVICE_LOG_LEVEL_INF=y diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/remote/prj.conf b/samples/subsys/ipc/ipc_service/icmsg_me/remote/prj.conf deleted file mode 100644 index 5feb10b31200f50..000000000000000 --- a/samples/subsys/ipc/ipc_service/icmsg_me/remote/prj.conf +++ /dev/null @@ -1,8 +0,0 @@ -CONFIG_PRINTK=y - -CONFIG_IPC_SERVICE=y -CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX=y -CONFIG_MBOX=y - -CONFIG_LOG=y -CONFIG_IPC_SERVICE_LOG_LEVEL_INF=y diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/remote/sample.yaml b/samples/subsys/ipc/ipc_service/icmsg_me/remote/sample.yaml deleted file mode 100644 index baf92ccc3da3d66..000000000000000 --- a/samples/subsys/ipc/ipc_service/icmsg_me/remote/sample.yaml +++ /dev/null @@ -1,9 +0,0 @@ -sample: - name: IPC Service example integration (icmsg multi endpoint follower backend) (remote) -tests: - sample.ipc.icmsg_me_follower: - platform_allow: nrf5340dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet - tags: ipc - harness: remote diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/remote/src/main.c b/samples/subsys/ipc/ipc_service/icmsg_me/remote/src/main.c deleted file mode 100644 index 387f962af95379f..000000000000000 --- a/samples/subsys/ipc/ipc_service/icmsg_me/remote/src/main.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#include - -#define STACKSIZE (1024) -#define PRIORITY K_PRIO_PREEMPT(2) - -K_THREAD_STACK_DEFINE(ipc0A_stack, STACKSIZE); -K_THREAD_STACK_DEFINE(ipc0B_stack, STACKSIZE); -K_THREAD_STACK_DEFINE(ipc1_stack, STACKSIZE); - -static volatile uint8_t ipc0A_received_data; -static volatile uint8_t ipc0B_received_data; -static const void *ipc1_received_data; - -static K_SEM_DEFINE(ipc0A_bound_sem, 0, 1); -static K_SEM_DEFINE(ipc0B_bound_sem, 0, 1); -static K_SEM_DEFINE(ipc1_bound_sem, 0, 1); - -static K_SEM_DEFINE(ipc0A_data_sem, 0, 1); -static K_SEM_DEFINE(ipc0B_data_sem, 0, 1); -static K_SEM_DEFINE(ipc1_data_sem, 0, 1); - -/* - * ==> THREAD 0A (IPC instance 0 - endpoint A) <== - */ - -static void ipc0A_ept_bound(void *priv) -{ - k_sem_give(&ipc0A_bound_sem); -} - -static void ipc0A_ept_recv(const void *data, size_t len, void *priv) -{ - ipc0A_received_data = *((uint8_t *) data); - - k_sem_give(&ipc0A_data_sem); -} - -static struct ipc_ept_cfg ipc0A_ept_cfg = { - .name = "ipc0A", - .cb = { - .bound = ipc0A_ept_bound, - .received = ipc0A_ept_recv, - }, -}; - -static void ipc0A_entry(void *dummy0, void *dummy1, void *dummy2) -{ - ARG_UNUSED(dummy0); - ARG_UNUSED(dummy1); - ARG_UNUSED(dummy2); - - const struct device *ipc0_instance; - unsigned char message = 0; - struct ipc_ept ipc0A_ept; - int ret; - - printk("IPC-service REMOTE [INST 0 - ENDP A] demo started\n"); - - ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); - - ret = ipc_service_open_instance(ipc0_instance); - if (ret < 0 && ret != -EALREADY) { - printk("ipc_service_open_instance() failure\n"); - return; - } - - ret = ipc_service_register_endpoint(ipc0_instance, &ipc0A_ept, &ipc0A_ept_cfg); - if (ret < 0) { - printf("ipc_service_register_endpoint() failure\n"); - return; - } - - k_sem_take(&ipc0A_bound_sem, K_FOREVER); - - while (message < 99) { - k_sem_take(&ipc0A_data_sem, K_FOREVER); - message = ipc0A_received_data; - - printk("REMOTE [0A]: %d\n", message); - - message++; - - ret = ipc_service_send(&ipc0A_ept, &message, sizeof(message)); - if (ret < 0) { - printk("send_message(%d) failed with ret %d\n", message, ret); - break; - } - } - - printk("IPC-service REMOTE [INST 0 - ENDP A] demo ended.\n"); -} -K_THREAD_DEFINE(ipc0A_thread_id, STACKSIZE, ipc0A_entry, NULL, NULL, NULL, PRIORITY, 0, 0); - -/* - * ==> THREAD 0B (IPC instance 0 - endpoint B) <== - */ - -static void ipc0B_ept_bound(void *priv) -{ - k_sem_give(&ipc0B_bound_sem); -} - -static void ipc0B_ept_recv(const void *data, size_t len, void *priv) -{ - ipc0B_received_data = *((uint8_t *) data); - - k_sem_give(&ipc0B_data_sem); -} - -static struct ipc_ept_cfg ipc0B_ept_cfg = { - .name = "ipc0B", - .cb = { - .bound = ipc0B_ept_bound, - .received = ipc0B_ept_recv, - }, -}; - -static void ipc0B_entry(void *dummy0, void *dummy1, void *dummy2) -{ - ARG_UNUSED(dummy0); - ARG_UNUSED(dummy1); - ARG_UNUSED(dummy2); - - const struct device *ipc0_instance; - unsigned char message = 0; - struct ipc_ept ipc0B_ept; - int ret; - - printk("IPC-service REMOTE [INST 0 - ENDP B] demo started\n"); - - ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); - - ret = ipc_service_open_instance(ipc0_instance); - if (ret < 0 && ret != -EALREADY) { - printk("ipc_service_open_instance() failure\n"); - return; - } - - /* - * Wait 1 sec to give the opportunity to the PRIMARY core to register - * the endpoint first - */ - - k_sleep(K_MSEC(1000)); - - ret = ipc_service_register_endpoint(ipc0_instance, &ipc0B_ept, &ipc0B_ept_cfg); - if (ret < 0) { - printf("ipc_service_register_endpoint() failure\n"); - return; - } - - k_sem_take(&ipc0B_bound_sem, K_FOREVER); - - while (message < 99) { - k_sem_take(&ipc0B_data_sem, K_FOREVER); - message = ipc0B_received_data; - - printk("REMOTE [0B]: %d\n", message); - - message++; - - ret = ipc_service_send(&ipc0B_ept, &message, sizeof(message)); - if (ret < 0) { - printk("send_message(%d) failed with ret %d\n", message, ret); - break; - } - } - - printk("IPC-service REMOTE [INST 0 - ENDP B] demo ended.\n"); -} -K_THREAD_DEFINE(ipc0B_thread_id, STACKSIZE, ipc0B_entry, NULL, NULL, NULL, PRIORITY, 0, 0); - -/* - * ==> THREAD 1 (IPC instance 1) <== - * - * NOTE: This instance is using the NOCOPY copability of the backend. - */ - -static struct ipc_ept ipc1_ept; - -static void ipc1_ept_bound(void *priv) -{ - k_sem_give(&ipc1_bound_sem); -} - -static void ipc1_ept_recv(const void *data, size_t len, void *priv) -{ - ipc_service_hold_rx_buffer(&ipc1_ept, (void *)data); - ipc1_received_data = data; - - k_sem_give(&ipc1_data_sem); -} - -static struct ipc_ept_cfg ipc1_ept_cfg = { - .name = "ipc1", - .cb = { - .bound = ipc1_ept_bound, - .received = ipc1_ept_recv, - }, -}; - -static void ipc1_entry(void *dummy0, void *dummy1, void *dummy2) -{ - ARG_UNUSED(dummy0); - ARG_UNUSED(dummy1); - ARG_UNUSED(dummy2); - - const struct device *ipc1_instance; - unsigned char message = 0; - int ret; - - printk("IPC-service REMOTE [INST 1] demo started\n"); - - ipc1_instance = DEVICE_DT_GET(DT_NODELABEL(ipc1)); - - ret = ipc_service_open_instance(ipc1_instance); - if (ret < 0 && ret != -EALREADY) { - printk("ipc_service_open_instance() failure\n"); - return; - } - - ret = ipc_service_register_endpoint(ipc1_instance, &ipc1_ept, &ipc1_ept_cfg); - if (ret < 0) { - printf("ipc_service_register_endpoint() failure\n"); - return; - } - - k_sem_take(&ipc1_bound_sem, K_FOREVER); - - while (message < 99) { - void *tx_buffer; - uint32_t tx_buffer_size = sizeof(message); - - k_sem_take(&ipc1_data_sem, K_FOREVER); - message = *((uint8_t *) ipc1_received_data); - - ret = ipc_service_release_rx_buffer(&ipc1_ept, (void *) ipc1_received_data); - if (ret < 0) { - printk("release_rx_buffer() failed with ret %d\n", ret); - break; - } - - printk("REMOTE [1]: %d\n", message); - - message++; - - ret = ipc_service_get_tx_buffer(&ipc1_ept, &tx_buffer, &tx_buffer_size, K_NO_WAIT); - if (ret < 0) { - printk("get_tx_buffer(%u) failed with ret %d\n", sizeof(message), ret); - break; - } - if (tx_buffer_size != sizeof(message)) { - printk("get_tx_buffer modified buffer size to unexpected value %u\n", - tx_buffer_size); - break; - } - - *((uint8_t *) tx_buffer) = message; - - ret = ipc_service_send_nocopy(&ipc1_ept, tx_buffer, tx_buffer_size); - if (ret < 0) { - printk("send_message_nocopy(%u) failed with ret %d\n", message, ret); - break; - } - } - - printk("IPC-service REMOTE [INST 1] demo ended.\n"); -} -K_THREAD_DEFINE(ipc1_thread_id, STACKSIZE, ipc1_entry, NULL, NULL, NULL, PRIORITY, 0, 0); diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/sample.yaml b/samples/subsys/ipc/ipc_service/icmsg_me/sample.yaml deleted file mode 100644 index 8a6443de1faa33f..000000000000000 --- a/samples/subsys/ipc/ipc_service/icmsg_me/sample.yaml +++ /dev/null @@ -1,9 +0,0 @@ -sample: - name: IPC Service example integration (icmsg multi endpoint backend) -tests: - sample.ipc.icmsg_me: - platform_allow: nrf5340dk_nrf5340_cpuapp - integration_platforms: - - nrf5340dk_nrf5340_cpuapp - tags: ipc - harness: remote diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/src/main.c b/samples/subsys/ipc/ipc_service/icmsg_me/src/main.c deleted file mode 100644 index 92b3a5569ef109a..000000000000000 --- a/samples/subsys/ipc/ipc_service/icmsg_me/src/main.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#include - -#define STACKSIZE (4096) -#define PRIORITY K_PRIO_PREEMPT(2) - -K_THREAD_STACK_DEFINE(ipc0A_stack, STACKSIZE); -K_THREAD_STACK_DEFINE(ipc0B_stack, STACKSIZE); -K_THREAD_STACK_DEFINE(ipc1_stack, STACKSIZE); - -static volatile uint8_t ipc0A_received_data; -static volatile uint8_t ipc0B_received_data; -static const void *ipc1_received_data; - -static K_SEM_DEFINE(ipc0A_bound_sem, 0, 1); -static K_SEM_DEFINE(ipc0B_bound_sem, 0, 1); -static K_SEM_DEFINE(ipc1_bound_sem, 0, 1); - -static K_SEM_DEFINE(ipc0A_data_sem, 0, 1); -static K_SEM_DEFINE(ipc0B_data_sem, 0, 1); -static K_SEM_DEFINE(ipc1_data_sem, 0, 1); - -/* - * ==> THREAD 0A (IPC instance 0 - endpoint A) <== - */ - -static void ipc0A_ept_bound(void *priv) -{ - k_sem_give(&ipc0A_bound_sem); -} - -static void ipc0A_ept_recv(const void *data, size_t len, void *priv) -{ - ipc0A_received_data = *((uint8_t *) data); - - k_sem_give(&ipc0A_data_sem); -} - -static struct ipc_ept_cfg ipc0A_ept_cfg = { - .name = "ipc0A", - .cb = { - .bound = ipc0A_ept_bound, - .received = ipc0A_ept_recv, - }, -}; - -static void ipc0A_entry(void *dummy0, void *dummy1, void *dummy2) -{ - ARG_UNUSED(dummy0); - ARG_UNUSED(dummy1); - ARG_UNUSED(dummy2); - - const struct device *ipc0_instance; - unsigned char message = 0; - struct ipc_ept ipc0A_ept; - int ret; - - printk("IPC-service HOST [INST 0 - ENDP A] demo started\n"); - - ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); - - ret = ipc_service_open_instance(ipc0_instance); - if (ret < 0 && ret != -EALREADY) { - printk("ipc_service_open_instance() failure\n"); - return; - } - - /* - * Wait 1 sec to give the opportunity to the SECONDARY core to register - * the endpoint first - */ - - k_sleep(K_MSEC(1000)); - - ret = ipc_service_register_endpoint(ipc0_instance, &ipc0A_ept, &ipc0A_ept_cfg); - if (ret < 0) { - printf("ipc_service_register_endpoint() failure\n"); - return; - } - - k_sem_take(&ipc0A_bound_sem, K_FOREVER); - - while (message < 100) { - ret = ipc_service_send(&ipc0A_ept, &message, sizeof(message)); - if (ret < 0) { - printk("send_message(%d) failed with ret %d\n", message, ret); - break; - } - - k_sem_take(&ipc0A_data_sem, K_FOREVER); - message = ipc0A_received_data; - - printk("HOST [0A]: %d\n", message); - message++; - } - - printk("IPC-service HOST [INST 0 - ENDP A] demo ended.\n"); -} -K_THREAD_DEFINE(ipc0A_thread_id, STACKSIZE, ipc0A_entry, NULL, NULL, NULL, PRIORITY, 0, 0); - -/* - * ==> THREAD 0B (IPC instance 0 - endpoint B) <== - */ - -static void ipc0B_ept_bound(void *priv) -{ - k_sem_give(&ipc0B_bound_sem); -} - -static void ipc0B_ept_recv(const void *data, size_t len, void *priv) -{ - ipc0B_received_data = *((uint8_t *) data); - - k_sem_give(&ipc0B_data_sem); -} - -static struct ipc_ept_cfg ipc0B_ept_cfg = { - .name = "ipc0B", - .cb = { - .bound = ipc0B_ept_bound, - .received = ipc0B_ept_recv, - }, -}; - -static void ipc0B_entry(void *dummy0, void *dummy1, void *dummy2) -{ - ARG_UNUSED(dummy0); - ARG_UNUSED(dummy1); - ARG_UNUSED(dummy2); - - const struct device *ipc0_instance; - unsigned char message = 0; - struct ipc_ept ipc0B_ept; - int ret; - - printk("IPC-service HOST [INST 0 - ENDP B] demo started\n"); - - ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); - - ret = ipc_service_open_instance(ipc0_instance); - if (ret < 0 && ret != -EALREADY) { - printk("ipc_service_open_instance() failure\n"); - return; - } - - ret = ipc_service_register_endpoint(ipc0_instance, &ipc0B_ept, &ipc0B_ept_cfg); - if (ret < 0) { - printf("ipc_service_register_endpoint() failure\n"); - return; - } - - k_sem_take(&ipc0B_bound_sem, K_FOREVER); - - while (message < 100) { - ret = ipc_service_send(&ipc0B_ept, &message, sizeof(message)); - if (ret < 0) { - printk("send_message(%d) failed with ret %d\n", message, ret); - break; - } - - k_sem_take(&ipc0B_data_sem, K_FOREVER); - message = ipc0B_received_data; - - printk("HOST [0B]: %d\n", message); - message++; - } - - printk("IPC-service HOST [INST 0 - ENDP B] demo ended.\n"); -} -K_THREAD_DEFINE(ipc0B_thread_id, STACKSIZE, ipc0B_entry, NULL, NULL, NULL, PRIORITY, 0, 0); - -/* - * ==> THREAD 1 (IPC instance 1) <== - * - * NOTE: This instance is using the NOCOPY copability of the backend. - */ - -static struct ipc_ept ipc1_ept; - -static void ipc1_ept_bound(void *priv) -{ - k_sem_give(&ipc1_bound_sem); -} - -static void ipc1_ept_recv(const void *data, size_t len, void *priv) -{ - ipc_service_hold_rx_buffer(&ipc1_ept, (void *)data); - ipc1_received_data = data; - - k_sem_give(&ipc1_data_sem); -} - -static struct ipc_ept_cfg ipc1_ept_cfg = { - .name = "ipc1", - .cb = { - .bound = ipc1_ept_bound, - .received = ipc1_ept_recv, - }, -}; - -static void ipc1_entry(void *dummy0, void *dummy1, void *dummy2) -{ - ARG_UNUSED(dummy0); - ARG_UNUSED(dummy1); - ARG_UNUSED(dummy2); - - const struct device *ipc1_instance; - unsigned char message = 0; - int ret; - - printk("IPC-service HOST [INST 1] demo started\n"); - - ipc1_instance = DEVICE_DT_GET(DT_NODELABEL(ipc1)); - - ret = ipc_service_open_instance(ipc1_instance); - if (ret < 0 && ret != -EALREADY) { - printk("ipc_service_open_instance() failure\n"); - return; - } - - ret = ipc_service_register_endpoint(ipc1_instance, &ipc1_ept, &ipc1_ept_cfg); - if (ret < 0) { - printf("ipc_service_register_endpoint() failure\n"); - return; - } - - k_sem_take(&ipc1_bound_sem, K_FOREVER); - - /* - * Wait 1 sec to start sending simultaneously with other threads - * the endpoint first - */ - - k_sleep(K_MSEC(1000)); - - while (message < 100) { - void *tx_buffer; - uint32_t tx_buffer_size = sizeof(message); - - ret = ipc_service_get_tx_buffer(&ipc1_ept, &tx_buffer, &tx_buffer_size, K_NO_WAIT); - if (ret < 0) { - printk("get_tx_buffer(%u) failed with ret %d\n", sizeof(message), ret); - break; - } - if (tx_buffer_size != sizeof(message)) { - printk("get_tx_buffer modified buffer size to unexpected value %u\n", - tx_buffer_size); - break; - } - - *((uint8_t *) tx_buffer) = message; - - ret = ipc_service_send_nocopy(&ipc1_ept, tx_buffer, tx_buffer_size); - if (ret < 0) { - printk("send_message_nocopy(%u) failed with ret %d\n", message, ret); - break; - } - - k_sem_take(&ipc1_data_sem, K_FOREVER); - message = *((uint8_t *) ipc1_received_data); - - ret = ipc_service_release_rx_buffer(&ipc1_ept, (void *) ipc1_received_data); - if (ret < 0) { - printk("release_rx_buffer() failed with ret %d\n", ret); - break; - } - - printk("HOST [1]: %d\n", message); - message++; - } - - printk("IPC-service HOST [INST 1] demo ended.\n"); -} -K_THREAD_DEFINE(ipc1_thread_id, STACKSIZE, ipc1_entry, NULL, NULL, NULL, PRIORITY, 0, 0); diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/CMakeLists.txt b/samples/subsys/ipc/ipc_service/multi_endpoint/CMakeLists.txt new file mode 100644 index 000000000000000..b342f55061637fa --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +if(NOT ("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp")) + message(FATAL_ERROR "${BOARD} is not supported for this sample") +endif() + +project(ipc_service) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/Kconfig.sysbuild b/samples/subsys/ipc/ipc_service/multi_endpoint/Kconfig.sysbuild new file mode 100644 index 000000000000000..47884745130c147 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/Kconfig.sysbuild @@ -0,0 +1,9 @@ +# 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" diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/README.rst b/samples/subsys/ipc/ipc_service/multi_endpoint/README.rst new file mode 100644 index 000000000000000..faff69e007fbc5a --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/README.rst @@ -0,0 +1,73 @@ +.. _ipc_multi_endpoint_sample: + +IPC Service - Multi-endpoint Sample Application +############################################### + +This application demonstrates how to use IPC Service with multiple endpoints. +By default, it uses the ``icmsg_me`` backend. +You can also configure it to use the ``icbmsg`` backend. + +Building the application for nrf5340dk_nrf5340_cpuapp +***************************************************** + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/ipc/ipc_service/multi_endpoint + :board: nrf5340dk_nrf5340_cpuapp + :goals: debug + +Open a serial terminal (for example Minicom or PuTTY) and connect the board with the following settings: + +* Speed: 115200 +* Data: 8 bits +* Parity: None +* Stop bits: 1 + +After resetting the board, the following message will appear on the corresponding +serial port: + +.. code-block:: console + + *** Booting Zephyr OS build v3.4.0-rc1-108-gccfbac8b0721 *** + IPC-service HOST [INST 0 - ENDP A] demo started + IPC-service HOST [INST 0 - ENDP B] demo started + IPC-service HOST [INST 1] demo started + HOST [0A]: 1 + HOST [0A]: 3 + HOST [0B]: 1 + HOST [1]: 1 + ... + HOST [0A]: 99 + IPC-service HOST [INST 0 - ENDP A] demo ended. + HOST [0B]: 99 + IPC-service HOST [INST 0 - ENDP B] demo ended. + HOST [1]: 99 + IPC-service HOST [INST 1] demo ended. + +.. code-block:: console + + *** Booting Zephyr OS build v3.4.0-rc1-108-gccfbac8b0721 *** + IPC-service REMOTE [INST 0 - ENDP A] demo started + IPC-service REMOTE [INST 0 - ENDP B] demo started + IPC-service REMOTE [INST 1] demo started + REMOTE [0A]: 0 + REMOTE [0A]: 2 + ... + REMOTE [0A]: 98 + IPC-service REMOTE [INST 0 - ENDP A] demo ended. + REMOTE [0B]: 98 + IPC-service REMOTE [INST 0 - ENDP B] demo ended. + REMOTE [1]: 98 + IPC-service REMOTE [INST 1] demo ended. + + +Changing the backend +******************** + +To change the backend to ``icbmsg``, switch the devicetree +overlay files as follows: + +.. code-block:: console + + west build -b nrf5340dk_nrf5340_cpuapp --sysbuild -- \ + -DDTC_OVERLAY_FILE=boards/nrf5340dk_nrf5340_cpuapp_icbmsg.overlay \ + -Dremote_DTC_OVERLAY_FILE=boards/nrf5340dk_nrf5340_cpunet_icbmsg.overlay diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp.conf similarity index 100% rename from samples/subsys/ipc/ipc_service/icmsg_me/boards/nrf5340dk_nrf5340_cpuapp.conf rename to samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp.conf diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/boards/nrf5340dk_nrf5340_cpuapp.overlay b/samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp.overlay similarity index 100% rename from samples/subsys/ipc/ipc_service/icmsg_me/boards/nrf5340dk_nrf5340_cpuapp.overlay rename to samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp.overlay diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp_icbmsg.overlay b/samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp_icbmsg.overlay new file mode 100644 index 000000000000000..3db9db032f4c465 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/boards/nrf5340dk_nrf5340_cpuapp_icbmsg.overlay @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /delete-property/ zephyr,ipc_shm; + }; + + reserved-memory { + /delete-node/ memory@20070000; + + sram_ipc0_tx: memory@20070000 { + reg = <0x20070000 0x4000>; + }; + + sram_ipc0_rx: memory@20074000 { + reg = <0x20074000 0x4000>; + }; + + sram_ipc1_tx: memory@20078000 { + reg = <0x20078000 0x4000>; + }; + + sram_ipc1_rx: memory@2007C000 { + reg = <0x2007C000 0x4000>; + }; + }; + + ipc { + /delete-node/ ipc0; + + ipc0: ipc0 { + compatible = "zephyr,ipc-icbmsg"; + tx-region = <&sram_ipc0_tx>; + rx-region = <&sram_ipc0_rx>; + tx-blocks = <16>; + rx-blocks = <24>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "tx", "rx"; + status = "okay"; + }; + + ipc1: ipc1 { + compatible = "zephyr,ipc-icbmsg"; + tx-region = <&sram_ipc1_tx>; + rx-region = <&sram_ipc1_rx>; + tx-blocks = <32>; + rx-blocks = <48>; + mboxes = <&mbox 2>, <&mbox 3>; + mbox-names = "tx", "rx"; + status = "okay"; + }; + }; +}; diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/prj.conf b/samples/subsys/ipc/ipc_service/multi_endpoint/prj.conf new file mode 100644 index 000000000000000..3d2c799c4eb607c --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/prj.conf @@ -0,0 +1,8 @@ +CONFIG_PRINTK=y +CONFIG_LOG_PRINTK=n + +CONFIG_IPC_SERVICE=y +CONFIG_MBOX=y + +CONFIG_LOG=y +CONFIG_IPC_SERVICE_LOG_LEVEL_INF=y diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/remote/CMakeLists.txt b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/CMakeLists.txt similarity index 100% rename from samples/subsys/ipc/ipc_service/icmsg_me/remote/CMakeLists.txt rename to samples/subsys/ipc/ipc_service/multi_endpoint/remote/CMakeLists.txt diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/remote/boards/nrf5340dk_nrf5340_cpunet.conf b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet.conf similarity index 100% rename from samples/subsys/ipc/ipc_service/icmsg_me/remote/boards/nrf5340dk_nrf5340_cpunet.conf rename to samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet.conf diff --git a/samples/subsys/ipc/ipc_service/icmsg_me/remote/boards/nrf5340dk_nrf5340_cpunet.overlay b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet.overlay similarity index 100% rename from samples/subsys/ipc/ipc_service/icmsg_me/remote/boards/nrf5340dk_nrf5340_cpunet.overlay rename to samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet.overlay diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet_icbmsg.overlay b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet_icbmsg.overlay new file mode 100644 index 000000000000000..6247ed812aa8382 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/boards/nrf5340dk_nrf5340_cpunet_icbmsg.overlay @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /delete-property/ zephyr,ipc_shm; + }; + + reserved-memory { + /delete-node/ memory@20070000; + + sram_ipc0_rx: memory@20070000 { + reg = <0x20070000 0x4000>; + }; + + sram_ipc0_tx: memory@20074000 { + reg = <0x20074000 0x4000>; + }; + + sram_ipc1_rx: memory@20078000 { + reg = <0x20078000 0x4000>; + }; + + sram_ipc1_tx: memory@2007C000 { + reg = <0x2007C000 0x4000>; + }; + }; + + ipc { + /delete-node/ ipc0; + + ipc0: ipc0 { + compatible = "zephyr,ipc-icbmsg"; + tx-region = <&sram_ipc0_tx>; + rx-region = <&sram_ipc0_rx>; + tx-blocks = <24>; + rx-blocks = <16>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "rx", "tx"; + status = "okay"; + }; + + ipc1: ipc1 { + compatible = "zephyr,ipc-icbmsg"; + tx-region = <&sram_ipc1_tx>; + rx-region = <&sram_ipc1_rx>; + tx-blocks = <48>; + rx-blocks = <32>; + mboxes = <&mbox 2>, <&mbox 3>; + mbox-names = "rx", "tx"; + status = "okay"; + }; + }; +}; diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/remote/prj.conf b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/prj.conf new file mode 100644 index 000000000000000..3d2c799c4eb607c --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/prj.conf @@ -0,0 +1,8 @@ +CONFIG_PRINTK=y +CONFIG_LOG_PRINTK=n + +CONFIG_IPC_SERVICE=y +CONFIG_MBOX=y + +CONFIG_LOG=y +CONFIG_IPC_SERVICE_LOG_LEVEL_INF=y diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c new file mode 100644 index 000000000000000..f285f4b6d23c983 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/remote/src/main.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +#define STACKSIZE (1024) +#define PRIORITY K_PRIO_PREEMPT(2) + +K_THREAD_STACK_DEFINE(ipc0A_stack, STACKSIZE); +K_THREAD_STACK_DEFINE(ipc0B_stack, STACKSIZE); +K_THREAD_STACK_DEFINE(ipc1_stack, STACKSIZE); + +static volatile uint8_t ipc0A_received_data; +static volatile uint8_t ipc0B_received_data; +static volatile uint8_t ipc1_received_data; + +static K_SEM_DEFINE(ipc0A_bound_sem, 0, 1); +static K_SEM_DEFINE(ipc0B_bound_sem, 0, 1); +static K_SEM_DEFINE(ipc1_bound_sem, 0, 1); + +static K_SEM_DEFINE(ipc0A_data_sem, 0, 1); +static K_SEM_DEFINE(ipc0B_data_sem, 0, 1); +static K_SEM_DEFINE(ipc1_data_sem, 0, 1); + +/* + * ==> THREAD 0A (IPC instance 0 - endpoint A) <== + */ + +static void ipc0A_ept_bound(void *priv) +{ + k_sem_give(&ipc0A_bound_sem); +} + +static void ipc0A_ept_recv(const void *data, size_t len, void *priv) +{ + ipc0A_received_data = *((uint8_t *) data); + + k_sem_give(&ipc0A_data_sem); +} + +static struct ipc_ept_cfg ipc0A_ept_cfg = { + .name = "ipc0A", + .cb = { + .bound = ipc0A_ept_bound, + .received = ipc0A_ept_recv, + }, +}; + +static void ipc0A_entry(void *dummy0, void *dummy1, void *dummy2) +{ + ARG_UNUSED(dummy0); + ARG_UNUSED(dummy1); + ARG_UNUSED(dummy2); + + const struct device *ipc0_instance; + unsigned char message = 0; + struct ipc_ept ipc0A_ept; + int ret; + + printk("IPC-service REMOTE [INST 0 - ENDP A] demo started\n"); + + ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); + + ret = ipc_service_open_instance(ipc0_instance); + if (ret < 0 && ret != -EALREADY) { + printk("ipc_service_open_instance() failure\n"); + return; + } + + ret = ipc_service_register_endpoint(ipc0_instance, &ipc0A_ept, &ipc0A_ept_cfg); + if (ret < 0) { + printf("ipc_service_register_endpoint() failure\n"); + return; + } + + k_sem_take(&ipc0A_bound_sem, K_FOREVER); + + while (message < 99) { + k_sem_take(&ipc0A_data_sem, K_FOREVER); + message = ipc0A_received_data; + + printk("REMOTE [0A]: %d\n", message); + + message++; + + ret = ipc_service_send(&ipc0A_ept, &message, sizeof(message)); + if (ret < 0) { + printk("send_message(%d) failed with ret %d\n", message, ret); + break; + } + } + + printk("IPC-service REMOTE [INST 0 - ENDP A] demo ended.\n"); +} +K_THREAD_DEFINE(ipc0A_thread_id, STACKSIZE, ipc0A_entry, NULL, NULL, NULL, PRIORITY, 0, 0); + +/* + * ==> THREAD 0B (IPC instance 0 - endpoint B) <== + */ + +static void ipc0B_ept_bound(void *priv) +{ + k_sem_give(&ipc0B_bound_sem); +} + +static void ipc0B_ept_recv(const void *data, size_t len, void *priv) +{ + ipc0B_received_data = *((uint8_t *) data); + + k_sem_give(&ipc0B_data_sem); +} + +static struct ipc_ept_cfg ipc0B_ept_cfg = { + .name = "ipc0B", + .cb = { + .bound = ipc0B_ept_bound, + .received = ipc0B_ept_recv, + }, +}; + +static void ipc0B_entry(void *dummy0, void *dummy1, void *dummy2) +{ + ARG_UNUSED(dummy0); + ARG_UNUSED(dummy1); + ARG_UNUSED(dummy2); + + const struct device *ipc0_instance; + unsigned char message = 0; + struct ipc_ept ipc0B_ept; + int ret; + + printk("IPC-service REMOTE [INST 0 - ENDP B] demo started\n"); + + ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); + + ret = ipc_service_open_instance(ipc0_instance); + if (ret < 0 && ret != -EALREADY) { + printk("ipc_service_open_instance() failure\n"); + return; + } + + /* + * Wait 1 sec to give the opportunity to the PRIMARY core to register + * the endpoint first + */ + + k_sleep(K_MSEC(1000)); + + ret = ipc_service_register_endpoint(ipc0_instance, &ipc0B_ept, &ipc0B_ept_cfg); + if (ret < 0) { + printf("ipc_service_register_endpoint() failure\n"); + return; + } + + k_sem_take(&ipc0B_bound_sem, K_FOREVER); + + while (message < 99) { + k_sem_take(&ipc0B_data_sem, K_FOREVER); + message = ipc0B_received_data; + + printk("REMOTE [0B]: %d\n", message); + + message++; + + ret = ipc_service_send(&ipc0B_ept, &message, sizeof(message)); + if (ret < 0) { + printk("send_message(%d) failed with ret %d\n", message, ret); + break; + } + } + + printk("IPC-service REMOTE [INST 0 - ENDP B] demo ended.\n"); +} +K_THREAD_DEFINE(ipc0B_thread_id, STACKSIZE, ipc0B_entry, NULL, NULL, NULL, PRIORITY, 0, 0); + +/* + * ==> THREAD 1 (IPC instance 1) <== + * + */ + +static void ipc1_ept_bound(void *priv) +{ + k_sem_give(&ipc1_bound_sem); +} + +static void ipc1_ept_recv(const void *data, size_t len, void *priv) +{ + ipc1_received_data = *((uint8_t *) data); + + k_sem_give(&ipc1_data_sem); +} + +static struct ipc_ept_cfg ipc1_ept_cfg = { + .name = "ipc1", + .cb = { + .bound = ipc1_ept_bound, + .received = ipc1_ept_recv, + }, +}; + +static void ipc1_entry(void *dummy0, void *dummy1, void *dummy2) +{ + ARG_UNUSED(dummy0); + ARG_UNUSED(dummy1); + ARG_UNUSED(dummy2); + + const struct device *ipc1_instance; + unsigned char message = 0; + struct ipc_ept ipc1_ept; + int ret; + + printk("IPC-service REMOTE [INST 1] demo started\n"); + + ipc1_instance = DEVICE_DT_GET(DT_NODELABEL(ipc1)); + + ret = ipc_service_open_instance(ipc1_instance); + if (ret < 0 && ret != -EALREADY) { + printk("ipc_service_open_instance() failure\n"); + return; + } + + ret = ipc_service_register_endpoint(ipc1_instance, &ipc1_ept, &ipc1_ept_cfg); + if (ret < 0) { + printf("ipc_service_register_endpoint() failure\n"); + return; + } + + k_sem_take(&ipc1_bound_sem, K_FOREVER); + + while (message < 99) { + k_sem_take(&ipc1_data_sem, K_FOREVER); + message = ipc1_received_data; + + printk("REMOTE [1]: %d\n", message); + + message++; + + ret = ipc_service_send(&ipc1_ept, &message, sizeof(message)); + if (ret < 0) { + printk("send_message(%d) failed with ret %d\n", message, ret); + break; + } + } + + printk("IPC-service REMOTE [INST 1] demo ended.\n"); +} +K_THREAD_DEFINE(ipc1_thread_id, STACKSIZE, ipc1_entry, NULL, NULL, NULL, PRIORITY, 0, 0); diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/sample.yaml b/samples/subsys/ipc/ipc_service/multi_endpoint/sample.yaml new file mode 100644 index 000000000000000..fdb3c707d8e5adc --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/sample.yaml @@ -0,0 +1,19 @@ +sample: + name: IPC Service example integration (icmsg multi endpoint backend) +tests: + sample.ipc.multi_endpoint: + platform_allow: nrf5340dk_nrf5340_cpuapp + integration_platforms: + - nrf5340dk_nrf5340_cpuapp + tags: ipc + sysbuild: true + harness: remote + sample.ipc.multi_endpoint.icbmsg: + platform_allow: nrf5340dk_nrf5340_cpuapp + integration_platforms: + - nrf5340dk_nrf5340_cpuapp + tags: ipc + sysbuild: true + extra_args: + DTC_OVERLAY_FILE=boards/nrf5340dk_nrf5340_cpuapp_icbmsg.overlay + remote_DTC_OVERLAY_FILE=boards/nrf5340dk_nrf5340_cpunet_icbmsg.overlay diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c b/samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c new file mode 100644 index 000000000000000..4ad5659df382325 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/src/main.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +#define STACKSIZE (4096) +#define PRIORITY K_PRIO_PREEMPT(2) + +K_THREAD_STACK_DEFINE(ipc0A_stack, STACKSIZE); +K_THREAD_STACK_DEFINE(ipc0B_stack, STACKSIZE); +K_THREAD_STACK_DEFINE(ipc1_stack, STACKSIZE); + +static volatile uint8_t ipc0A_received_data; +static volatile uint8_t ipc0B_received_data; +static volatile uint8_t ipc1_received_data; + +static K_SEM_DEFINE(ipc0A_bound_sem, 0, 1); +static K_SEM_DEFINE(ipc0B_bound_sem, 0, 1); +static K_SEM_DEFINE(ipc1_bound_sem, 0, 1); + +static K_SEM_DEFINE(ipc0A_data_sem, 0, 1); +static K_SEM_DEFINE(ipc0B_data_sem, 0, 1); +static K_SEM_DEFINE(ipc1_data_sem, 0, 1); + +/* + * ==> THREAD 0A (IPC instance 0 - endpoint A) <== + */ + +static void ipc0A_ept_bound(void *priv) +{ + k_sem_give(&ipc0A_bound_sem); +} + +static void ipc0A_ept_recv(const void *data, size_t len, void *priv) +{ + ipc0A_received_data = *((uint8_t *) data); + + k_sem_give(&ipc0A_data_sem); +} + +static struct ipc_ept_cfg ipc0A_ept_cfg = { + .name = "ipc0A", + .cb = { + .bound = ipc0A_ept_bound, + .received = ipc0A_ept_recv, + }, +}; + +static void ipc0A_entry(void *dummy0, void *dummy1, void *dummy2) +{ + ARG_UNUSED(dummy0); + ARG_UNUSED(dummy1); + ARG_UNUSED(dummy2); + + const struct device *ipc0_instance; + unsigned char message = 0; + struct ipc_ept ipc0A_ept; + int ret; + + printk("IPC-service HOST [INST 0 - ENDP A] demo started\n"); + + ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); + + ret = ipc_service_open_instance(ipc0_instance); + if (ret < 0 && ret != -EALREADY) { + printk("ipc_service_open_instance() failure\n"); + return; + } + + /* + * Wait 1 sec to give the opportunity to the SECONDARY core to register + * the endpoint first + */ + + k_sleep(K_MSEC(1000)); + + ret = ipc_service_register_endpoint(ipc0_instance, &ipc0A_ept, &ipc0A_ept_cfg); + if (ret < 0) { + printf("ipc_service_register_endpoint() failure\n"); + return; + } + + k_sem_take(&ipc0A_bound_sem, K_FOREVER); + + while (message < 100) { + ret = ipc_service_send(&ipc0A_ept, &message, sizeof(message)); + if (ret < 0) { + printk("send_message(%d) failed with ret %d\n", message, ret); + break; + } + + k_sem_take(&ipc0A_data_sem, K_FOREVER); + message = ipc0A_received_data; + + printk("HOST [0A]: %d\n", message); + message++; + } + + printk("IPC-service HOST [INST 0 - ENDP A] demo ended.\n"); +} +K_THREAD_DEFINE(ipc0A_thread_id, STACKSIZE, ipc0A_entry, NULL, NULL, NULL, PRIORITY, 0, 0); + +/* + * ==> THREAD 0B (IPC instance 0 - endpoint B) <== + */ + +static void ipc0B_ept_bound(void *priv) +{ + k_sem_give(&ipc0B_bound_sem); +} + +static void ipc0B_ept_recv(const void *data, size_t len, void *priv) +{ + ipc0B_received_data = *((uint8_t *) data); + + k_sem_give(&ipc0B_data_sem); +} + +static struct ipc_ept_cfg ipc0B_ept_cfg = { + .name = "ipc0B", + .cb = { + .bound = ipc0B_ept_bound, + .received = ipc0B_ept_recv, + }, +}; + +static void ipc0B_entry(void *dummy0, void *dummy1, void *dummy2) +{ + ARG_UNUSED(dummy0); + ARG_UNUSED(dummy1); + ARG_UNUSED(dummy2); + + const struct device *ipc0_instance; + unsigned char message = 0; + struct ipc_ept ipc0B_ept; + int ret; + + printk("IPC-service HOST [INST 0 - ENDP B] demo started\n"); + + ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); + + ret = ipc_service_open_instance(ipc0_instance); + if (ret < 0 && ret != -EALREADY) { + printk("ipc_service_open_instance() failure\n"); + return; + } + + ret = ipc_service_register_endpoint(ipc0_instance, &ipc0B_ept, &ipc0B_ept_cfg); + if (ret < 0) { + printf("ipc_service_register_endpoint() failure\n"); + return; + } + + k_sem_take(&ipc0B_bound_sem, K_FOREVER); + + while (message < 100) { + ret = ipc_service_send(&ipc0B_ept, &message, sizeof(message)); + if (ret < 0) { + printk("send_message(%d) failed with ret %d\n", message, ret); + break; + } + + k_sem_take(&ipc0B_data_sem, K_FOREVER); + message = ipc0B_received_data; + + printk("HOST [0B]: %d\n", message); + message++; + } + + printk("IPC-service HOST [INST 0 - ENDP B] demo ended.\n"); +} +K_THREAD_DEFINE(ipc0B_thread_id, STACKSIZE, ipc0B_entry, NULL, NULL, NULL, PRIORITY, 0, 0); + +/* + * ==> THREAD 1 (IPC instance 1) <== + */ + +static void ipc1_ept_bound(void *priv) +{ + k_sem_give(&ipc1_bound_sem); +} + +static void ipc1_ept_recv(const void *data, size_t len, void *priv) +{ + ipc1_received_data = *((uint8_t *) data); + + k_sem_give(&ipc1_data_sem); +} + +static struct ipc_ept_cfg ipc1_ept_cfg = { + .name = "ipc1", + .cb = { + .bound = ipc1_ept_bound, + .received = ipc1_ept_recv, + }, +}; + +static void ipc1_entry(void *dummy0, void *dummy1, void *dummy2) +{ + ARG_UNUSED(dummy0); + ARG_UNUSED(dummy1); + ARG_UNUSED(dummy2); + + const struct device *ipc1_instance; + unsigned char message = 0; + struct ipc_ept ipc1_ept; + int ret; + + printk("IPC-service HOST [INST 1] demo started\n"); + + ipc1_instance = DEVICE_DT_GET(DT_NODELABEL(ipc1)); + + ret = ipc_service_open_instance(ipc1_instance); + if (ret < 0 && ret != -EALREADY) { + printk("ipc_service_open_instance() failure\n"); + return; + } + + ret = ipc_service_register_endpoint(ipc1_instance, &ipc1_ept, &ipc1_ept_cfg); + if (ret < 0) { + printf("ipc_service_register_endpoint() failure\n"); + return; + } + + k_sem_take(&ipc1_bound_sem, K_FOREVER); + + /* + * Wait 1 sec to start sending simultaneously with other threads + * the endpoint first + */ + + k_sleep(K_MSEC(1000)); + + while (message < 100) { + ret = ipc_service_send(&ipc1_ept, &message, sizeof(message)); + if (ret < 0) { + printk("send_message(%d) failed with ret %d\n", message, ret); + break; + } + + k_sem_take(&ipc1_data_sem, K_FOREVER); + message = ipc1_received_data; + + printk("HOST [1]: %d\n", message); + message++; + } + + printk("IPC-service HOST [INST 1] demo ended.\n"); +} +K_THREAD_DEFINE(ipc1_thread_id, STACKSIZE, ipc1_entry, NULL, NULL, NULL, PRIORITY, 0, 0); diff --git a/samples/subsys/ipc/ipc_service/multi_endpoint/sysbuild.cmake b/samples/subsys/ipc/ipc_service/multi_endpoint/sysbuild.cmake new file mode 100644 index 000000000000000..d0d79b8f2408402 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/multi_endpoint/sysbuild.cmake @@ -0,0 +1,14 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "") + message(FATAL_ERROR + "Target ${BOARD} not supported for this sample. " + "There is no remote board selected in Kconfig.sysbuild") +endif() + +ExternalZephyrProject_Add( + APPLICATION remote + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_NET_CORE_BOARD} +) diff --git a/samples/subsys/ipc/ipc_service/static_vrings/CMakeLists.txt b/samples/subsys/ipc/ipc_service/static_vrings/CMakeLists.txt index c5ae1a2f8d900d8..6af69691e1e0c1c 100644 --- a/samples/subsys/ipc/ipc_service/static_vrings/CMakeLists.txt +++ b/samples/subsys/ipc/ipc_service/static_vrings/CMakeLists.txt @@ -6,27 +6,14 @@ cmake_minimum_required(VERSION 3.20.0) -set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/ipc_service_remote-prefix/src/ipc_service_remote-build/zephyr) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") - set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet") -else() +if(NOT ("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp")) message(FATAL_ERROR "${BOARD} is not supported for this sample") endif() -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(ipc_service) target_sources(app PRIVATE src/main.c) include(ExternalProject) - -ExternalProject_Add( - ipc_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 -) diff --git a/samples/subsys/ipc/ipc_service/static_vrings/Kconfig.sysbuild b/samples/subsys/ipc/ipc_service/static_vrings/Kconfig.sysbuild new file mode 100644 index 000000000000000..47884745130c147 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/Kconfig.sysbuild @@ -0,0 +1,9 @@ +# 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" diff --git a/samples/subsys/ipc/ipc_service/static_vrings/README.rst b/samples/subsys/ipc/ipc_service/static_vrings/README.rst index e9633ad63d66c19..7fbed84cad8ced1 100644 --- a/samples/subsys/ipc/ipc_service/static_vrings/README.rst +++ b/samples/subsys/ipc/ipc_service/static_vrings/README.rst @@ -18,6 +18,7 @@ Building the application for nrf5340dk_nrf5340_cpuapp :zephyr-app: samples/subsys/ipc/ipc_service/static_vrings :board: nrf5340dk_nrf5340_cpuapp :goals: debug + :west-args: --sysbuild Open a serial terminal (minicom, putty, etc.) and connect the board with the following settings: diff --git a/samples/subsys/ipc/ipc_service/static_vrings/remote/sample.yaml b/samples/subsys/ipc/ipc_service/static_vrings/remote/sample.yaml deleted file mode 100644 index ab70e115c9a64cb..000000000000000 --- a/samples/subsys/ipc/ipc_service/static_vrings/remote/sample.yaml +++ /dev/null @@ -1,9 +0,0 @@ -sample: - name: IPC Service example integration (OpenAMP static_vrings backend) (remote) -tests: - sample.ipc.static_vrings_remote: - platform_allow: nrf5340dk_nrf5340_cpunet - integration_platforms: - - nrf5340dk_nrf5340_cpunet - tags: ipc - harness: remote diff --git a/samples/subsys/ipc/ipc_service/static_vrings/sample.yaml b/samples/subsys/ipc/ipc_service/static_vrings/sample.yaml index 42e487503ba3b89..3e57abf32eb932e 100644 --- a/samples/subsys/ipc/ipc_service/static_vrings/sample.yaml +++ b/samples/subsys/ipc/ipc_service/static_vrings/sample.yaml @@ -6,4 +6,5 @@ tests: integration_platforms: - nrf5340dk_nrf5340_cpuapp tags: ipc + sysbuild: true harness: remote diff --git a/samples/subsys/ipc/ipc_service/static_vrings/sysbuild.cmake b/samples/subsys/ipc/ipc_service/static_vrings/sysbuild.cmake new file mode 100644 index 000000000000000..d0d79b8f2408402 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/sysbuild.cmake @@ -0,0 +1,14 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "") + message(FATAL_ERROR + "Target ${BOARD} not supported for this sample. " + "There is no remote board selected in Kconfig.sysbuild") +endif() + +ExternalZephyrProject_Add( + APPLICATION remote + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_NET_CORE_BOARD} +) diff --git a/samples/subsys/ipc/openamp/remote/boards/mimxrt1160_evk_cm4.overlay b/samples/subsys/ipc/openamp/remote/boards/mimxrt1160_evk_cm4.overlay index 32d5003bb19fd89..87159192cf249ee 100644 --- a/samples/subsys/ipc/openamp/remote/boards/mimxrt1160_evk_cm4.overlay +++ b/samples/subsys/ipc/openamp/remote/boards/mimxrt1160_evk_cm4.overlay @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + / { /* Switch to lpuart2, since primary core uses lpuart1 */ chosen { diff --git a/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evk_cm4.overlay b/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evk_cm4.overlay index 32d5003bb19fd89..87159192cf249ee 100644 --- a/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evk_cm4.overlay +++ b/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evk_cm4.overlay @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + / { /* Switch to lpuart2, since primary core uses lpuart1 */ chosen { diff --git a/samples/subsys/ipc/openamp/remote/src/main.c b/samples/subsys/ipc/openamp/remote/src/main.c index 337d011453126e8..06622d49e44e308 100644 --- a/samples/subsys/ipc/openamp/remote/src/main.c +++ b/samples/subsys/ipc/openamp/remote/src/main.c @@ -144,6 +144,7 @@ void app_task(void *arg1, void *arg2, void *arg3) ARG_UNUSED(arg1); ARG_UNUSED(arg2); ARG_UNUSED(arg3); + int status = 0; unsigned int message = 0U; struct metal_device *device; @@ -259,7 +260,7 @@ int main(void) { printk("Starting application thread!\n"); k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE, - (k_thread_entry_t)app_task, + app_task, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); return 0; } diff --git a/samples/subsys/ipc/openamp/src/main.c b/samples/subsys/ipc/openamp/src/main.c index b2a06ec8a8cd15f..5b2ce5fddbba222 100644 --- a/samples/subsys/ipc/openamp/src/main.c +++ b/samples/subsys/ipc/openamp/src/main.c @@ -168,6 +168,7 @@ void app_task(void *arg1, void *arg2, void *arg3) ARG_UNUSED(arg1); ARG_UNUSED(arg2); ARG_UNUSED(arg3); + int status = 0; unsigned int message = 0U; struct metal_device *device; @@ -284,7 +285,7 @@ int main(void) { printk("Starting application thread!\n"); k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE, - (k_thread_entry_t)app_task, + app_task, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); #if defined(CONFIG_SOC_MPS2_AN521) || \ diff --git a/samples/subsys/ipc/openamp_rsc_table/README.rst b/samples/subsys/ipc/openamp_rsc_table/README.rst index 95eaabfae603c3f..a0d46e3a4bd2c86 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 a5bd2e9c76c88bd..50c93f3905c298c 100644 --- a/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c +++ b/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c @@ -276,6 +276,7 @@ void app_rpmsg_client_sample(void *arg1, void *arg2, void *arg3) ARG_UNUSED(arg1); ARG_UNUSED(arg2); ARG_UNUSED(arg3); + unsigned int msg_cnt = 0; int ret = 0; @@ -290,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); @@ -302,12 +305,13 @@ void app_rpmsg_tty(void *arg1, void *arg2, void *arg3) ARG_UNUSED(arg1); ARG_UNUSED(arg2); ARG_UNUSED(arg3); + unsigned char tx_buff[512]; int ret = 0; 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", @@ -317,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; @@ -335,11 +340,12 @@ void rpmsg_mng_task(void *arg1, void *arg2, void *arg3) ARG_UNUSED(arg1); ARG_UNUSED(arg2); ARG_UNUSED(arg3); + unsigned char *msg; 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(); @@ -375,13 +381,13 @@ int main(void) { printk("Starting application threads!\n"); k_thread_create(&thread_mng_data, thread_mng_stack, APP_TASK_STACK_SIZE, - (k_thread_entry_t)rpmsg_mng_task, + rpmsg_mng_task, NULL, NULL, NULL, K_PRIO_COOP(8), 0, K_NO_WAIT); k_thread_create(&thread_rp__client_data, thread_rp__client_stack, APP_TASK_STACK_SIZE, - (k_thread_entry_t)app_rpmsg_client_sample, + app_rpmsg_client_sample, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); k_thread_create(&thread_tty_data, thread_tty_stack, APP_TTY_TASK_STACK_SIZE, - (k_thread_entry_t)app_rpmsg_tty, + app_rpmsg_tty, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); return 0; } diff --git a/samples/subsys/ipc/rpmsg_service/CMakeLists.txt b/samples/subsys/ipc/rpmsg_service/CMakeLists.txt index 7411ab59dae4dde..85356c531de62fb 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 000000000000000..9dec2087f953b8d --- /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 ce32b16b61e1952..0c63b8dc3bb0944 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 5cb30cb75c05d82..0bef3d481fdde52 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 76fc92e63077dd0..2545f2e1d719a0f 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 eee0f29606c70f5..000000000000000 --- 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 e085ef2f51b2e8d..000000000000000 --- 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/remote/src/main.c b/samples/subsys/ipc/rpmsg_service/remote/src/main.c index 9960a1132674e3e..de6de636ff55e09 100644 --- a/samples/subsys/ipc/rpmsg_service/remote/src/main.c +++ b/samples/subsys/ipc/rpmsg_service/remote/src/main.c @@ -54,6 +54,7 @@ void app_task(void *arg1, void *arg2, void *arg3) ARG_UNUSED(arg1); ARG_UNUSED(arg2); ARG_UNUSED(arg3); + int status = 0; unsigned int message = 0U; @@ -79,7 +80,7 @@ int main(void) { printk("Starting application thread!\n"); k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE, - (k_thread_entry_t)app_task, + app_task, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); return 0; } diff --git a/samples/subsys/ipc/rpmsg_service/sample.yaml b/samples/subsys/ipc/rpmsg_service/sample.yaml deleted file mode 100644 index 84647ea51a40fac..000000000000000 --- 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/src/main.c b/samples/subsys/ipc/rpmsg_service/src/main.c index f849bb3ee96d0f2..f90df9365650432 100644 --- a/samples/subsys/ipc/rpmsg_service/src/main.c +++ b/samples/subsys/ipc/rpmsg_service/src/main.c @@ -55,6 +55,7 @@ void app_task(void *arg1, void *arg2, void *arg3) ARG_UNUSED(arg1); ARG_UNUSED(arg2); ARG_UNUSED(arg3); + int status = 0; unsigned int message = 0U; @@ -88,7 +89,7 @@ int main(void) { printk("Starting application thread!\n"); k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE, - (k_thread_entry_t)app_task, + app_task, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); #if defined(CONFIG_SOC_MPS2_AN521) || \ diff --git a/samples/subsys/ipc/rpmsg_service/sysbuild.cmake b/samples/subsys/ipc/rpmsg_service/sysbuild.cmake new file mode 100644 index 000000000000000..08af67aeb85e0eb --- /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/prj.conf b/samples/subsys/llext/shell_loader/prj.conf index 678e5eb55ae28be..0e0d38fdcf45e14 100644 --- a/samples/subsys/llext/shell_loader/prj.conf +++ b/samples/subsys/llext/shell_loader/prj.conf @@ -2,11 +2,11 @@ CONFIG_LOG=y CONFIG_LOG_MODE_IMMEDIATE=y CONFIG_SHELL=y -CONFIG_SHELL_CMD_BUFF_SIZE=32768 +CONFIG_SHELL_CMD_BUFF_SIZE=8192 CONFIG_SHELL_LOG_LEVEL_INF=y -CONFIG_SHELL_STACK_SIZE=8192 +CONFIG_SHELL_STACK_SIZE=4096 CONFIG_LLEXT=y CONFIG_LLEXT_LOG_LEVEL_DBG=y -CONFIG_LLEXT_HEAP_SIZE=32 +CONFIG_LLEXT_HEAP_SIZE=8 CONFIG_LLEXT_SHELL=y diff --git a/samples/subsys/llext/shell_loader/sample.yaml b/samples/subsys/llext/shell_loader/sample.yaml index 5ef2a080286decf..3cf54e450204d61 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 - 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 2253ff1832096d4..1d54e228664f9c5 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 000000000000000..0b3d792e707d8ea --- /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 5dca694782a82b2..8ef962daeb95e32 100644 --- a/samples/subsys/logging/logger/sample.yaml +++ b/samples/subsys/logging/logger/sample.yaml @@ -4,7 +4,7 @@ sample: tests: sample.logger.basic: integration_platforms: - - native_posix + - native_sim tags: logging harness: console harness_config: @@ -22,6 +22,8 @@ tests: - frdm_k64f tags: logging filter: CONFIG_HAS_SEGGER_RTT + arch_exclude: + - posix harness: keyboard extra_configs: - CONFIG_LOG_BACKEND_RTT=y @@ -30,6 +32,14 @@ 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: - logging - usermode diff --git a/samples/subsys/logging/multidomain/CMakeLists.txt b/samples/subsys/logging/multidomain/CMakeLists.txt index 378ff66c7d8fbcf..a0cc842a6a8b497 100644 --- a/samples/subsys/logging/multidomain/CMakeLists.txt +++ b/samples/subsys/logging/multidomain/CMakeLists.txt @@ -6,15 +6,13 @@ cmake_minimum_required(VERSION 3.20.0) -set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/log_multidomain_remote-prefix/src/log_multidomain_remote-build/zephyr) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") - set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet") -else() +if(NOT(("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") + OR ("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp"))) message(FATAL_ERROR "${BOARD} is not supported for this sample") endif() -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(log_multidomain) target_sources(app PRIVATE src/main.c) @@ -22,14 +20,3 @@ target_sources(app PRIVATE src/main.c) if (CONFIG_IPC_SERVICE) target_sources(app PRIVATE src/ipc_service.c) endif() - -include(ExternalProject) - -ExternalProject_Add( - log_multidomain_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}" - BUILD_ALWAYS True -) diff --git a/samples/subsys/logging/multidomain/Kconfig.sysbuild b/samples/subsys/logging/multidomain/Kconfig.sysbuild new file mode 100644 index 000000000000000..b6dc3d0a6d0d359 --- /dev/null +++ b/samples/subsys/logging/multidomain/Kconfig.sysbuild @@ -0,0 +1,10 @@ +# 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 "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" diff --git a/samples/subsys/logging/multidomain/boards/nrf5340bsim_nrf5340_cpuapp.conf b/samples/subsys/logging/multidomain/boards/nrf5340bsim_nrf5340_cpuapp.conf new file mode 100644 index 000000000000000..f14ca9ebc20c52e --- /dev/null +++ b/samples/subsys/logging/multidomain/boards/nrf5340bsim_nrf5340_cpuapp.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NRFX_IPC=y +# For the mailbox to be initialized logger initialization is delayed like in real HW +CONFIG_LOG_PROCESS_THREAD=y +CONFIG_LOG_MODE_DEFERRED=y diff --git a/samples/subsys/logging/multidomain/boards/nrf5340bsim_nrf5340_cpuapp.overlay b/samples/subsys/logging/multidomain/boards/nrf5340bsim_nrf5340_cpuapp.overlay new file mode 100644 index 000000000000000..fbcced931532a30 --- /dev/null +++ b/samples/subsys/logging/multidomain/boards/nrf5340bsim_nrf5340_cpuapp.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nrf5340dk_nrf5340_cpuapp.overlay" diff --git a/samples/subsys/logging/multidomain/remote/boards/nrf5340bsim_nrf5340_cpunet.conf b/samples/subsys/logging/multidomain/remote/boards/nrf5340bsim_nrf5340_cpunet.conf new file mode 100644 index 000000000000000..2d6de6e7c7c0c1e --- /dev/null +++ b/samples/subsys/logging/multidomain/remote/boards/nrf5340bsim_nrf5340_cpunet.conf @@ -0,0 +1,5 @@ +CONFIG_MBOX_NRFX_IPC=y +CONFIG_BUILD_OUTPUT_EXE=n +# For the mailbox to be initialized logger initialization is delayed like in real HW +CONFIG_LOG_PROCESS_THREAD=y +CONFIG_LOG_MODE_DEFERRED=y diff --git a/samples/subsys/logging/multidomain/remote/boards/nrf5340bsim_nrf5340_cpunet.overlay b/samples/subsys/logging/multidomain/remote/boards/nrf5340bsim_nrf5340_cpunet.overlay new file mode 100644 index 000000000000000..ccb145fa34b27e3 --- /dev/null +++ b/samples/subsys/logging/multidomain/remote/boards/nrf5340bsim_nrf5340_cpunet.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nrf5340dk_nrf5340_cpunet.overlay" diff --git a/samples/subsys/logging/multidomain/remote/boards/nrf5340dk_nrf5340_cpunet.conf b/samples/subsys/logging/multidomain/remote/boards/nrf5340dk_nrf5340_cpunet.conf index a1ab15fae142abb..cb04b37b233e88e 100644 --- a/samples/subsys/logging/multidomain/remote/boards/nrf5340dk_nrf5340_cpunet.conf +++ b/samples/subsys/logging/multidomain/remote/boards/nrf5340dk_nrf5340_cpunet.conf @@ -1 +1,2 @@ CONFIG_MBOX_NRFX_IPC=y +CONFIG_MPU_STACK_GUARD=y diff --git a/samples/subsys/logging/multidomain/remote/prj.conf b/samples/subsys/logging/multidomain/remote/prj.conf index 65d5bc08f581154..11cddd823fb00e4 100644 --- a/samples/subsys/logging/multidomain/remote/prj.conf +++ b/samples/subsys/logging/multidomain/remote/prj.conf @@ -15,6 +15,5 @@ CONFIG_LOG_PRINTK=n CONFIG_LOG_BUFFER_SIZE=4096 CONFIG_ASSERT=y -CONFIG_MPU_STACK_GUARD=y CONFIG_LOG_BACKEND_UART=n CONFIG_LOG_BACKEND_RTT=n diff --git a/samples/subsys/logging/multidomain/sample.yaml b/samples/subsys/logging/multidomain/sample.yaml index 737a44ffdedfbd8..79523c9951a3a07 100644 --- a/samples/subsys/logging/multidomain/sample.yaml +++ b/samples/subsys/logging/multidomain/sample.yaml @@ -1,9 +1,31 @@ sample: name: Logging in multi-domain environment +common: + sysbuild: true + tags: ipc tests: - sample.logging.multidomain.ipc_static_vrings: - platform_allow: nrf5340dk_nrf5340_cpuapp + sample.logging.multidomain.ipc_static_vrings.hw: + platform_allow: + - nrf5340dk_nrf5340_cpuapp integration_platforms: - nrf5340dk_nrf5340_cpuapp - tags: ipc build_only: true + sample.logging.multidomain.ipc_static_vrings.simu: + platform_allow: + - nrf5340bsim_nrf5340_cpuapp + integration_platforms: + - nrf5340bsim_nrf5340_cpuapp + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "IPC-service REMOTE \\[INST 1\\] demo started" + - "app: loop: 0" + - "app: ipc open" + - "app: wait for bound" + - "app: bounded" + - "app: REMOTE \\[1\\]: 0" + - "app: HOST \\[1\\]: 1" + - "IPC-service REMOTE \\[INST 1\\] demo ended." + - "app: IPC-service HOST \\[INST 1\\] demo ended." diff --git a/samples/subsys/logging/multidomain/sysbuild.cmake b/samples/subsys/logging/multidomain/sysbuild.cmake new file mode 100644 index 000000000000000..496a7a03f9de94c --- /dev/null +++ b/samples/subsys/logging/multidomain/sysbuild.cmake @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "") + message(FATAL_ERROR + "Target ${BOARD} not supported for this sample. " + "There is no remote board selected in Kconfig.sysbuild") +endif() + +set(NET_APP remote) + +ExternalZephyrProject_Add( + APPLICATION ${NET_APP} + SOURCE_DIR ${APP_DIR}/${NET_APP} + BOARD ${SB_CONFIG_NET_CORE_BOARD} +) + +native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) + +native_simulator_set_final_executable(${DEFAULT_IMAGE}) diff --git a/samples/subsys/lorawan/class_a/README.rst b/samples/subsys/lorawan/class_a/README.rst index 3a7a794499775c9..c29853ae0642aaf 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 000000000000000..6bd5165564328ba --- /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 fb0a3c0de30c040..7a757da815d9937 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/hawkbit/prj.conf b/samples/subsys/mgmt/hawkbit/prj.conf index a96c9461a831b1a..e8539c7a120985e 100644 --- a/samples/subsys/mgmt/hawkbit/prj.conf +++ b/samples/subsys/mgmt/hawkbit/prj.conf @@ -53,7 +53,7 @@ CONFIG_LOG=y CONFIG_HAWKBIT_LOG_LEVEL_INF=n #General Config -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y CONFIG_LOG_BUFFER_SIZE=4096 #Generate HEX output diff --git a/samples/subsys/mgmt/hawkbit/sample.yaml b/samples/subsys/mgmt/hawkbit/sample.yaml index 4df4c6d3f69c8c5..6a60360e4237571 100644 --- a/samples/subsys/mgmt/hawkbit/sample.yaml +++ b/samples/subsys/mgmt/hawkbit/sample.yaml @@ -1,5 +1,5 @@ common: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + filter: CONFIG_FULL_LIBC_SUPPORTED sample: description: Hawkbit Firmware Over-the-Air (FOTA) name: hawkbit diff --git a/samples/subsys/mgmt/mcumgr/smp_svr/overlay-bt.conf b/samples/subsys/mgmt/mcumgr/smp_svr/overlay-bt.conf index b2db245ddd47052..8942068beb4194a 100644 --- a/samples/subsys/mgmt/mcumgr/smp_svr/overlay-bt.conf +++ b/samples/subsys/mgmt/mcumgr/smp_svr/overlay-bt.conf @@ -14,6 +14,7 @@ CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL=y # Enable the Shell mcumgr transport. CONFIG_BASE64=y +CONFIG_CRC=y CONFIG_SHELL=y CONFIG_SHELL_BACKEND_SERIAL=y CONFIG_MCUMGR_TRANSPORT_SHELL=y diff --git a/samples/subsys/mgmt/mcumgr/smp_svr/overlay-cdc.conf b/samples/subsys/mgmt/mcumgr/smp_svr/overlay-cdc.conf index 6fb996b0e5d0a71..1d98bc9899d5135 100644 --- a/samples/subsys/mgmt/mcumgr/smp_svr/overlay-cdc.conf +++ b/samples/subsys/mgmt/mcumgr/smp_svr/overlay-cdc.conf @@ -7,3 +7,4 @@ CONFIG_CONSOLE=y # USB backend is serial device CONFIG_MCUMGR_TRANSPORT_UART=y CONFIG_BASE64=y +CONFIG_CRC=y diff --git a/samples/subsys/mgmt/mcumgr/smp_svr/overlay-serial-console.conf b/samples/subsys/mgmt/mcumgr/smp_svr/overlay-serial-console.conf index 24e15c9d09298f2..ec2fadf3cfed34c 100644 --- a/samples/subsys/mgmt/mcumgr/smp_svr/overlay-serial-console.conf +++ b/samples/subsys/mgmt/mcumgr/smp_svr/overlay-serial-console.conf @@ -1,5 +1,6 @@ # Enable console with MCUmgr pass through CONFIG_BASE64=y +CONFIG_CRC=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_UART_CONSOLE_MCUMGR=y diff --git a/samples/subsys/mgmt/mcumgr/smp_svr/overlay-serial.conf b/samples/subsys/mgmt/mcumgr/smp_svr/overlay-serial.conf index cf542238a48c58b..47d4e8d0b853224 100644 --- a/samples/subsys/mgmt/mcumgr/smp_svr/overlay-serial.conf +++ b/samples/subsys/mgmt/mcumgr/smp_svr/overlay-serial.conf @@ -1,4 +1,5 @@ # Enable the serial MCUmgr transport. CONFIG_BASE64=y +CONFIG_CRC=y CONFIG_MCUMGR_TRANSPORT_UART=y CONFIG_CONSOLE=y diff --git a/samples/subsys/mgmt/mcumgr/smp_svr/overlay-shell-mgmt.conf b/samples/subsys/mgmt/mcumgr/smp_svr/overlay-shell-mgmt.conf index 235cd04b32d1a0e..01156e341ec0fc1 100644 --- a/samples/subsys/mgmt/mcumgr/smp_svr/overlay-shell-mgmt.conf +++ b/samples/subsys/mgmt/mcumgr/smp_svr/overlay-shell-mgmt.conf @@ -1,5 +1,6 @@ # Enable shell commands. CONFIG_BASE64=y +CONFIG_CRC=y CONFIG_SHELL=y CONFIG_SHELL_BACKEND_SERIAL=n CONFIG_MCUMGR_GRP_SHELL=y diff --git a/samples/subsys/mgmt/mcumgr/smp_svr/overlay-shell.conf b/samples/subsys/mgmt/mcumgr/smp_svr/overlay-shell.conf index 8021768c12dd272..59c8b18ed9ed651 100644 --- a/samples/subsys/mgmt/mcumgr/smp_svr/overlay-shell.conf +++ b/samples/subsys/mgmt/mcumgr/smp_svr/overlay-shell.conf @@ -1,5 +1,6 @@ # Enable the shell MCUmgr transport. CONFIG_BASE64=y +CONFIG_CRC=y CONFIG_SHELL=y CONFIG_SHELL_BACKEND_SERIAL=y CONFIG_MCUMGR_TRANSPORT_SHELL=y diff --git a/samples/subsys/mgmt/mcumgr/smp_svr/src/main.c b/samples/subsys/mgmt/mcumgr/smp_svr/src/main.c index 2e4f206502e1056..8b0c0b44a885f54 100644 --- a/samples/subsys/mgmt/mcumgr/smp_svr/src/main.c +++ b/samples/subsys/mgmt/mcumgr/smp_svr/src/main.c @@ -73,7 +73,9 @@ int main(void) if (IS_ENABLED(CONFIG_USB_DEVICE_STACK)) { rc = usb_enable(NULL); - if (rc) { + + /* Ignore EALREADY error as USB CDC is likely already initialised */ + if (rc != 0 && rc != -EALREADY) { LOG_ERR("Failed to enable USB"); return 0; } diff --git a/samples/subsys/mgmt/osdp/README.rst b/samples/subsys/mgmt/osdp/README.rst index 7656d1cd8abae08..ac65db5ee57b562 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 000000000000000..a13fc8f12b7dced --- /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 c9322a4ebd97a2e..5fecf6ad24a796f 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 000000000000000..cd67c09e7bc1c20 --- /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 ded4397ac417e7b..994ea535e3ff79a 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 000000000000000..ee0f1af77ac6df7 --- /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/pm/latency/boards/native_posix.overlay b/samples/subsys/pm/latency/boards/native_posix.overlay index c718cbdd1ffc2cd..6a3daca3241ac6e 100644 --- a/samples/subsys/pm/latency/boards/native_posix.overlay +++ b/samples/subsys/pm/latency/boards/native_posix.overlay @@ -1,31 +1 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * SPDX-License-Identifier: Apache-2.0 - */ - -/ { - power-states { - runtime_idle: runtime-idle { - compatible = "zephyr,power-state"; - power-state-name = "runtime-idle"; - min-residency-us = <1000000>; - exit-latency-us = <10000>; - }; - suspend_to_idle: suspend-to-idle { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1100000>; - exit-latency-us = <20000>; - }; - standby: standby { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <1200000>; - exit-latency-us = <30000>; - }; - }; -}; - -&cpu0 { - cpu-power-states = <&runtime_idle &suspend_to_idle &standby>; -}; +#include "native_sim.overlay" diff --git a/samples/subsys/pm/latency/boards/native_sim.overlay b/samples/subsys/pm/latency/boards/native_sim.overlay new file mode 100644 index 000000000000000..c718cbdd1ffc2cd --- /dev/null +++ b/samples/subsys/pm/latency/boards/native_sim.overlay @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + power-states { + runtime_idle: runtime-idle { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <1000000>; + exit-latency-us = <10000>; + }; + suspend_to_idle: suspend-to-idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1100000>; + exit-latency-us = <20000>; + }; + standby: standby { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <1200000>; + exit-latency-us = <30000>; + }; + }; +}; + +&cpu0 { + cpu-power-states = <&runtime_idle &suspend_to_idle &standby>; +}; diff --git a/samples/subsys/pm/latency/sample.yaml b/samples/subsys/pm/latency/sample.yaml index 4989a63dbe78e2b..2d6f68879c34cef 100644 --- a/samples/subsys/pm/latency/sample.yaml +++ b/samples/subsys/pm/latency/sample.yaml @@ -2,9 +2,11 @@ sample: name: Demonstrate usage of the PM policy latency APIs tests: sample.pm.latency: - platform_allow: native_posix - integration_platforms: + platform_allow: - native_posix + - native_sim + integration_platforms: + - native_sim tags: pm harness: console harness_config: diff --git a/samples/subsys/portability/cmsis_rtos_v1/philosophers/sample.yaml b/samples/subsys/portability/cmsis_rtos_v1/philosophers/sample.yaml index 4f4fe6cf366150c..64fd5053d85df7c 100644 --- a/samples/subsys/portability/cmsis_rtos_v1/philosophers/sample.yaml +++ b/samples/subsys/portability/cmsis_rtos_v1/philosophers/sample.yaml @@ -2,7 +2,7 @@ sample: name: CMSIS_RTOS_V1 Dining Philosophers common: integration_platforms: - - native_posix + - native_sim extra_args: DEBUG_PRINTF=1 tags: cmsis_rtos min_ram: 32 diff --git a/samples/subsys/portability/cmsis_rtos_v1/timer_synchronization/sample.yaml b/samples/subsys/portability/cmsis_rtos_v1/timer_synchronization/sample.yaml index 2d8df98d7708f4d..e87d8449938313a 100644 --- a/samples/subsys/portability/cmsis_rtos_v1/timer_synchronization/sample.yaml +++ b/samples/subsys/portability/cmsis_rtos_v1/timer_synchronization/sample.yaml @@ -3,7 +3,7 @@ sample: tests: sample.portability.cmsis_rtos_v1.timer_synchronization: integration_platforms: - - native_posix + - native_sim tags: cmsis_rtos min_ram: 32 min_flash: 34 diff --git a/samples/subsys/portability/cmsis_rtos_v2/philosophers/sample.yaml b/samples/subsys/portability/cmsis_rtos_v2/philosophers/sample.yaml index 5f15a4d1ce0d099..af5a69f0af78948 100644 --- a/samples/subsys/portability/cmsis_rtos_v2/philosophers/sample.yaml +++ b/samples/subsys/portability/cmsis_rtos_v2/philosophers/sample.yaml @@ -2,7 +2,7 @@ sample: name: CMSIS_RTOS_V2 Dining Philosophers common: integration_platforms: - - native_posix + - native_sim extra_args: DEBUG_PRINTF=1 tags: cmsis_rtos min_ram: 32 diff --git a/samples/subsys/portability/cmsis_rtos_v2/timer_synchronization/sample.yaml b/samples/subsys/portability/cmsis_rtos_v2/timer_synchronization/sample.yaml index 7b7103cfb9e07c7..f4a8ad690cf27f7 100644 --- a/samples/subsys/portability/cmsis_rtos_v2/timer_synchronization/sample.yaml +++ b/samples/subsys/portability/cmsis_rtos_v2/timer_synchronization/sample.yaml @@ -3,7 +3,7 @@ sample: tests: sample.portability.cmsis_rtos_v2.timer_synchronization: integration_platforms: - - native_posix + - native_sim platform_exclude: - qemu_arc_hs5x # See issue #62405 tags: cmsis_rtos diff --git a/samples/subsys/portability/portability.rst b/samples/subsys/portability/portability.rst index b47ee35edc9e48a..9034372320f88a4 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/rtio/sensor_batch_processing/sample.yaml b/samples/subsys/rtio/sensor_batch_processing/sample.yaml index 956af3a567a3863..99732a25574e918 100644 --- a/samples/subsys/rtio/sensor_batch_processing/sample.yaml +++ b/samples/subsys/rtio/sensor_batch_processing/sample.yaml @@ -4,7 +4,7 @@ tests: sample.rtio.sensor_batch_processing: tags: rtio integration_platforms: - - native_posix + - native_sim harness: console harness_config: type: multi_line diff --git a/samples/subsys/sensing/simple/README.rst b/samples/subsys/sensing/simple/README.rst index b24d48685855ded..f8ff0857b315ba0 100644 --- a/samples/subsys/sensing/simple/README.rst +++ b/samples/subsys/sensing/simple/README.rst @@ -26,14 +26,14 @@ The program runs in the following sequence: Building and Running ******************** -This application can be built and executed on native_posix as follows: +This application can be built and executed on :ref:`native_sim ` as follows: .. zephyr-app-commands:: :zephyr-app: samples/subsys/sensing/simple :host-os: unix - :board: native_posix + :board: native_sim :goals: run :compact: -To build for another board, change "native_posix" above to that board's name. -At the current stage, it only support native posix +To build for another board, change "native_sim" above to that board's name. +At the current stage, it only support native sim. diff --git a/samples/subsys/sensing/simple/boards/native_posix.overlay b/samples/subsys/sensing/simple/boards/native_posix.overlay deleted file mode 100644 index d11630cd5d98af1..000000000000000 --- a/samples/subsys/sensing/simple/boards/native_posix.overlay +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&i2c0 { - bmi160_i2c: bmi@68 { - compatible = "bosch,bmi160"; - reg = <0x68>; - }; -}; - -&spi0 { - bmi160_spi: bmi@3 { - compatible = "bosch,bmi160"; - spi-max-frequency = <50000000>; - reg = <0x3>; - }; -}; - -/ { - sensing: sensing-node { - compatible = "zephyr,sensing"; - status = "okay"; - - base_accel: base-accel { - compatible = "zephyr,sensing-phy-3d-sensor"; - status = "okay"; - sensor-type = <0x73>; - friendly-name = "Base Accelerometer Sensor"; - minimal-interval = <625>; - underlying-device = <&bmi160_i2c>; - }; - - lid_accel: lid-accel { - compatible = "zephyr,sensing-phy-3d-sensor"; - status = "okay"; - sensor-type = <0x73>; - friendly-name = "Lid Accelerometer Sensor"; - minimal-interval = <625>; - underlying-device = <&bmi160_spi>; - }; - }; -}; diff --git a/samples/subsys/sensing/simple/boards/native_posix.conf b/samples/subsys/sensing/simple/boards/native_sim.conf similarity index 100% rename from samples/subsys/sensing/simple/boards/native_posix.conf rename to samples/subsys/sensing/simple/boards/native_sim.conf diff --git a/samples/subsys/sensing/simple/boards/native_sim.overlay b/samples/subsys/sensing/simple/boards/native_sim.overlay new file mode 100644 index 000000000000000..73a81b81f640a12 --- /dev/null +++ b/samples/subsys/sensing/simple/boards/native_sim.overlay @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&i2c0 { + bmi160_i2c: bmi@68 { + compatible = "bosch,bmi160"; + reg = <0x68>; + }; +}; + +&spi0 { + bmi160_spi: bmi@3 { + compatible = "bosch,bmi160"; + spi-max-frequency = <50000000>; + reg = <0x3>; + }; +}; + +/ { + sensing: sensing-node { + compatible = "zephyr,sensing"; + status = "okay"; + + base_accel_gyro: base-accel-gyro { + compatible = "zephyr,sensing-phy-3d-sensor"; + status = "okay"; + sensor-types = ; + friendly-name = "Base Accel Gyro Sensor"; + minimal-interval = <625>; + underlying-device = <&bmi160_i2c>; + }; + + lid_accel_gyro: lid-accel-gyro { + compatible = "zephyr,sensing-phy-3d-sensor"; + status = "okay"; + 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/sample.yaml b/samples/subsys/sensing/simple/sample.yaml index b930aff274be83b..de2508c0d49af31 100644 --- a/samples/subsys/sensing/simple/sample.yaml +++ b/samples/subsys/sensing/simple/sample.yaml @@ -4,13 +4,14 @@ sample: common: tags: sensing integration_platforms: - - native_posix + - native_sim harness: console harness_config: type: multi_line regex: - "sensing subsystem run successfully" tests: - sample.subsys.sensing.simple: - platform_allow: native_posix + sample.sensing.simple: + platform_allow: + - native_sim tags: sensing diff --git a/samples/subsys/sensing/simple/src/main.c b/samples/subsys/sensing/simple/src/main.c index 9a5b66876826f95..d0749d3b52cd98e 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/settings/boards/native_posix.overlay b/samples/subsys/settings/boards/native_posix.overlay index 0e4839ad0265855..6a3daca3241ac6e 100644 --- a/samples/subsys/settings/boards/native_posix.overlay +++ b/samples/subsys/settings/boards/native_posix.overlay @@ -1,22 +1 @@ -/* - * Copyright (c) 2019 Jan Van Winkel - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/delete-node/ &storage_partition; -/delete-node/ &scratch_partition; - -&flash0 { - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - storage_partition: partition@70000 { - label = "storage"; - reg = <0x00070000 0x8000>; - }; - }; -}; +#include "native_sim.overlay" diff --git a/samples/subsys/settings/boards/native_posix_64.overlay b/samples/subsys/settings/boards/native_posix_64.overlay index 0e4839ad0265855..6a3daca3241ac6e 100644 --- a/samples/subsys/settings/boards/native_posix_64.overlay +++ b/samples/subsys/settings/boards/native_posix_64.overlay @@ -1,22 +1 @@ -/* - * Copyright (c) 2019 Jan Van Winkel - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/delete-node/ &storage_partition; -/delete-node/ &scratch_partition; - -&flash0 { - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - storage_partition: partition@70000 { - label = "storage"; - reg = <0x00070000 0x8000>; - }; - }; -}; +#include "native_sim.overlay" diff --git a/samples/subsys/settings/boards/native_sim.conf b/samples/subsys/settings/boards/native_sim.conf new file mode 100644 index 000000000000000..21877f886f3a7e8 --- /dev/null +++ b/samples/subsys/settings/boards/native_sim.conf @@ -0,0 +1,5 @@ +# Enable the LittleFS file system. +CONFIG_FILE_SYSTEM=y +CONFIG_FILE_SYSTEM_LITTLEFS=y +CONFIG_SETTINGS_FILE=y +CONFIG_SETTINGS_FILE_PATH="/ff/settings/run" diff --git a/samples/subsys/settings/boards/native_sim.overlay b/samples/subsys/settings/boards/native_sim.overlay new file mode 100644 index 000000000000000..0e4839ad0265855 --- /dev/null +++ b/samples/subsys/settings/boards/native_sim.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &storage_partition; +/delete-node/ &scratch_partition; + +&flash0 { + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + storage_partition: partition@70000 { + label = "storage"; + reg = <0x00070000 0x8000>; + }; + }; +}; diff --git a/samples/subsys/settings/boards/native_sim_64.conf b/samples/subsys/settings/boards/native_sim_64.conf new file mode 100644 index 000000000000000..21877f886f3a7e8 --- /dev/null +++ b/samples/subsys/settings/boards/native_sim_64.conf @@ -0,0 +1,5 @@ +# Enable the LittleFS file system. +CONFIG_FILE_SYSTEM=y +CONFIG_FILE_SYSTEM_LITTLEFS=y +CONFIG_SETTINGS_FILE=y +CONFIG_SETTINGS_FILE_PATH="/ff/settings/run" diff --git a/samples/subsys/settings/boards/native_sim_64.overlay b/samples/subsys/settings/boards/native_sim_64.overlay new file mode 100644 index 000000000000000..6a3daca3241ac6e --- /dev/null +++ b/samples/subsys/settings/boards/native_sim_64.overlay @@ -0,0 +1 @@ +#include "native_sim.overlay" diff --git a/samples/subsys/settings/sample.yaml b/samples/subsys/settings/sample.yaml index 47276f1e6975d3f..2cd51d1405daa16 100644 --- a/samples/subsys/settings/sample.yaml +++ b/samples/subsys/settings/sample.yaml @@ -9,9 +9,11 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 - mr_canhubk3 integration_platforms: - - native_posix + - native_sim harness: console harness_config: type: multi_line diff --git a/samples/subsys/shell/devmem_load/README.md b/samples/subsys/shell/devmem_load/README.md index e4c457bf6a9612f..98b4059dcaf615e 100644 --- a/samples/subsys/shell/devmem_load/README.md +++ b/samples/subsys/shell/devmem_load/README.md @@ -20,7 +20,7 @@ west flash Building for boards without UART interrupt support: ```bash -west build -b native_posix -- -DOVERLAY_CONFIG=prj_poll.conf samples/subsys/shell/devmem_load +west build -b native_sim -- -DOVERLAY_CONFIG=prj_poll.conf samples/subsys/shell/devmem_load ``` ## Running After connecting to the UART console you should see the following output: diff --git a/samples/subsys/shell/devmem_load/sample.yaml b/samples/subsys/shell/devmem_load/sample.yaml index eca1e1f65cd3a4e..2d59490a0eb23bd 100644 --- a/samples/subsys/shell/devmem_load/sample.yaml +++ b/samples/subsys/shell/devmem_load/sample.yaml @@ -9,7 +9,7 @@ common: tests: sample.devmem_load.polled: integration_platforms: - - native_posix + - native_sim extra_args: OVERLAY_CONFIG="prj_poll.conf" sample.devmem_load.uart.interrupt: integration_platforms: diff --git a/samples/subsys/shell/fs/README.rst b/samples/subsys/shell/fs/README.rst index d8bdecae6cda221..f3d860832255a49 100644 --- a/samples/subsys/shell/fs/README.rst +++ b/samples/subsys/shell/fs/README.rst @@ -17,12 +17,38 @@ A board with LittleFS file system support and UART console Building ******** -Native Posix -============ +native_sim +========== + +You can build this sample for :ref:`native_sim ` with: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/shell/fs + :board: native_sim + :goals: build + :compact: + +Which by default will use the flash simulator. The flash simulator will use a file, +:file:`flash.bin`, in the current directory to keep the flash content. +You have several options to control this. You can check them with: + +.. code-block:: console + + zephyr/zephyr.exe -help + +Check the :ref:`native_sim UART documentation ` for information on how to connect +to the UART. + +With FUSE access in the host filesystem +--------------------------------------- + +If you enable the :ref:`host FUSE filsystem access ` +you will also have the flash filesystem mounted and accessible from your Linux host filesystem. Before starting a build, make sure that the i386 pkgconfig directory is in your search path and that a 32-bit version of libfuse is installed. For more -background information on this requirement see :ref:`native_posix`. +background information on this requirement check +:ref:`the native_sim documentation `. .. code-block:: console @@ -30,12 +56,11 @@ background information on this requirement see :ref:`native_posix`. .. zephyr-app-commands:: :zephyr-app: samples/subsys/shell/fs - :board: native_posix + :board: native_sim + :gen-args: -DCONFIG_FUSE_FS_ACCESS=y :goals: build :compact: -See :ref:`native_posix` on how to connect to the UART. - Reel Board ========== @@ -198,7 +223,7 @@ Remove a file or directory Flash Host Access ================= -For the Native POSIX board the flash partitions can be accessed from the host +For the :ref:`native sim board ` the flash partitions can be accessed from the host Linux system. By default the flash partitions are accessible through the directory *flash* diff --git a/samples/subsys/shell/fs/boards/native_posix.conf b/samples/subsys/shell/fs/boards/native_posix.conf deleted file mode 100644 index 80357cdf245772e..000000000000000 --- a/samples/subsys/shell/fs/boards/native_posix.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_FUSE_FS_ACCESS=y diff --git a/samples/subsys/shell/fs/boards/native_posix_64.conf b/samples/subsys/shell/fs/boards/native_posix_64.conf deleted file mode 100644 index 80357cdf245772e..000000000000000 --- a/samples/subsys/shell/fs/boards/native_posix_64.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_FUSE_FS_ACCESS=y diff --git a/samples/subsys/shell/fs/sample.yaml b/samples/subsys/shell/fs/sample.yaml index e66f984e929d9ac..2f30aad68bbb5be 100644 --- a/samples/subsys/shell/fs/sample.yaml +++ b/samples/subsys/shell/fs/sample.yaml @@ -1,25 +1,30 @@ sample: description: FS shell sample name: FS shell +common: + tags: + - shell + - filesystem + harness: keyboard tests: sample.filesystem.shell: - tags: - - shell - - filesystem - harness: keyboard platform_allow: - reel_board - mimxrt1060_evk - mr_canhubk3 + - native_sim integration_platforms: - reel_board - + sample.filesystem.shell.fuse: + platform_allow: + - native_sim + extra_configs: + - CONFIG_FUSE_FS_ACCESS=y + # This test cannot be run in CI as we lack the fuse library + skip: true sample.filesystem.shell.flash_load: tags: - - shell - - filesystem - flash_load - harness: keyboard platform_allow: nrf52dk_nrf52832 extra_args: CONF_FILE=prj_flash_load.conf integration_platforms: 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 489e3f9fe16a058..b96ff81fe83394d 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 a35c307aeca9d1c..c7de2dd452901cd 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 c11e1133d250bae..41d51f8e22a7f1f 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/shell/shell_module/sample.yaml b/samples/subsys/shell/shell_module/sample.yaml index 7aac79eac903513..95ac36bc6b33e9b 100644 --- a/samples/subsys/shell/shell_module/sample.yaml +++ b/samples/subsys/shell/shell_module/sample.yaml @@ -7,7 +7,7 @@ tests: harness: keyboard min_ram: 40 integration_platforms: - - native_posix + - native_sim - intel_socfpga_agilex5_socdk sample.shell.shell_module.usb: depends_on: usb_device @@ -20,14 +20,14 @@ tests: - OVERLAY_CONFIG="overlay-usb.conf" - DTC_OVERLAY_FILE="usb.overlay" integration_platforms: - - native_posix + - native_sim sample.shell.shell_module.minimal: filter: CONFIG_SERIAL and dt_chosen_enabled("zephyr,shell-uart") tags: shell harness: keyboard extra_args: CONF_FILE="prj_minimal.conf" integration_platforms: - - native_posix + - native_sim sample.shell.shell_module.getopt: integration_platforms: - qemu_x86 @@ -51,7 +51,7 @@ tests: min_ram: 40 extra_args: CONF_FILE="prj_login.conf" integration_platforms: - - native_posix + - native_sim sample.shell.shell_module.robot: harness: robot harness_config: diff --git a/samples/subsys/task_wdt/sample.yaml b/samples/subsys/task_wdt/sample.yaml index 1c9c300a8782122..334d6e3a24f7cb0 100644 --- a/samples/subsys/task_wdt/sample.yaml +++ b/samples/subsys/task_wdt/sample.yaml @@ -1,8 +1,9 @@ sample: name: Task Watchdog Subsytem Sample common: - tags: subsys harness: console + tags: + - task_wdt harness_config: type: multi_line ordered: true @@ -19,10 +20,10 @@ common: - s32z270dc2_rtu0_r52 - s32z270dc2_rtu1_r52 tests: - sample.subsys.task_wdt: + sample.task_wdt: integration_platforms: - nucleo_g474re - sample.subsys.task_wdt.no_hw_fallback: + sample.task_wdt.no_hw_fallback: extra_args: CONF_FILE="prj_no_hw_fallback.conf" platform_allow: - mr_canhubk3 diff --git a/samples/subsys/testsuite/integration/prj.conf b/samples/subsys/testsuite/integration/prj.conf index 9228251051ec064..9467c2926896dd7 100644 --- a/samples/subsys/testsuite/integration/prj.conf +++ b/samples/subsys/testsuite/integration/prj.conf @@ -1,2 +1 @@ CONFIG_ZTEST=y -CONFIG_ZTEST_NEW_API=y diff --git a/samples/subsys/testsuite/integration/testcase.yaml b/samples/subsys/testsuite/integration/testcase.yaml index 8a4c9743b75451a..1cc0ad1c8ee195e 100644 --- a/samples/subsys/testsuite/integration/testcase.yaml +++ b/samples/subsys/testsuite/integration/testcase.yaml @@ -2,7 +2,9 @@ tests: # section.subsection sample.testing.ztest: build_only: true - platform_allow: native_posix - integration_platforms: + platform_allow: - native_posix + - native_sim + integration_platforms: + - native_sim tags: test_framework diff --git a/samples/subsys/testsuite/pytest/basic/prj.conf b/samples/subsys/testsuite/pytest/basic/prj.conf index 989b0c1b2cf8b28..c3e81438cedda96 100644 --- a/samples/subsys/testsuite/pytest/basic/prj.conf +++ b/samples/subsys/testsuite/pytest/basic/prj.conf @@ -1,3 +1,2 @@ CONFIG_ZTEST=y -CONFIG_ZTEST_NEW_API=y CONFIG_IDLE_STACK_SIZE=4096 diff --git a/samples/subsys/testsuite/pytest/basic/testcase.yaml b/samples/subsys/testsuite/pytest/basic/testcase.yaml index a7c28cafc3b6c63..6dc504cd64c143e 100644 --- a/samples/subsys/testsuite/pytest/basic/testcase.yaml +++ b/samples/subsys/testsuite/pytest/basic/testcase.yaml @@ -1,6 +1,8 @@ tests: sample.twister.pytest: - platform_allow: native_posix + platform_allow: + - native_posix + - native_sim harness: pytest harness_config: pytest_args: ["--custom-pytest-arg", "foo", "--cmdopt", "."] @@ -8,4 +10,4 @@ tests: - test_framework - pytest integration_platforms: - - native_posix + - native_sim diff --git a/samples/subsys/testsuite/pytest/shell/README.rst b/samples/subsys/testsuite/pytest/shell/README.rst new file mode 100644 index 000000000000000..4fb4eea11fcc68c --- /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/pytest/shell/testcase.yaml b/samples/subsys/testsuite/pytest/shell/testcase.yaml index 02a3bcf9620ba94..86b9314f444416d 100644 --- a/samples/subsys/testsuite/pytest/shell/testcase.yaml +++ b/samples/subsys/testsuite/pytest/shell/testcase.yaml @@ -6,7 +6,7 @@ tests: extra_configs: - arch:posix:CONFIG_NATIVE_UART_0_ON_STDINOUT=y integration_platforms: - - native_posix + - native_sim - qemu_cortex_m3 tags: - test_framework diff --git a/samples/subsys/testsuite/testsuite.rst b/samples/subsys/testsuite/testsuite.rst new file mode 100644 index 000000000000000..7c84784e9a63b59 --- /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/tracing/README.rst b/samples/subsys/tracing/README.rst index 5214e35ce48af00..299ab0a751d61cd 100644 --- a/samples/subsys/tracing/README.rst +++ b/samples/subsys/tracing/README.rst @@ -83,8 +83,7 @@ Build a POSIX-tracing image with: .. zephyr-app-commands:: :zephyr-app: samples/subsys/tracing - :board: native_posix - :conf: "prj_native_posix.conf" + :board: native_sim :goals: build :compact: @@ -92,8 +91,8 @@ or: .. zephyr-app-commands:: :zephyr-app: samples/subsys/tracing - :board: native_posix - :conf: "prj_native_posix_ctf.conf" + :board: native_sim + :conf: "prj_native_ctf.conf" :goals: build :compact: diff --git a/samples/subsys/tracing/boards/native_sim.conf b/samples/subsys/tracing/boards/native_sim.conf new file mode 100644 index 000000000000000..2a60b33a7677fff --- /dev/null +++ b/samples/subsys/tracing/boards/native_sim.conf @@ -0,0 +1,5 @@ +CONFIG_TRACING=y +CONFIG_TRACING_TEST=y +CONFIG_TRACING_SYNC=y +CONFIG_TRACING_BACKEND_POSIX=y +CONFIG_TRACING_PACKET_MAX_SIZE=64 diff --git a/samples/subsys/tracing/prj_native_posix_ctf.conf b/samples/subsys/tracing/prj_native_ctf.conf similarity index 100% rename from samples/subsys/tracing/prj_native_posix_ctf.conf rename to samples/subsys/tracing/prj_native_ctf.conf diff --git a/samples/subsys/tracing/sample.yaml b/samples/subsys/tracing/sample.yaml index dda98638a58816b..23db8876ceebc56 100644 --- a/samples/subsys/tracing/sample.yaml +++ b/samples/subsys/tracing/sample.yaml @@ -60,11 +60,19 @@ tests: platform_allow: sam_e70_xplained depends_on: usb_device extra_args: CONF_FILE="prj_usb_ctf.conf" - sample.tracing.transport.native_posix: - platform_allow: native_posix - sample.tracing.transport.native_posix.ctf: - platform_allow: native_posix - extra_args: CONF_FILE="prj_native_posix_ctf.conf" + sample.tracing.transport.native: + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim + sample.tracing.transport.native.ctf: + platform_allow: + - native_posix + - native_sim + integration_platforms: + - native_sim + extra_args: CONF_FILE="prj_native_ctf.conf" sample.tracing.percepio: platform_allow: frdm_k64f extra_args: CONF_FILE="prj_percepio.conf" diff --git a/samples/subsys/usb/cdc_acm/CMakeLists.txt b/samples/subsys/usb/cdc_acm/CMakeLists.txt index 0cba7b39068d4fd..c97b499076633bd 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 000000000000000..96c5455894806dd --- /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/sample.yaml b/samples/subsys/usb/cdc_acm/sample.yaml index 19e645174f71ef3..61b72fa41efdc1e 100644 --- a/samples/subsys/usb/cdc_acm/sample.yaml +++ b/samples/subsys/usb/cdc_acm/sample.yaml @@ -41,4 +41,4 @@ tests: arch_allow: posix build_only: true integration_platforms: - - native_posix + - native_sim diff --git a/samples/subsys/usb/cdc_acm/src/main.c b/samples/subsys/usb/cdc_acm/src/main.c index 4276bb2a12e3986..1fa40ace3665389 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 @@ -29,67 +31,22 @@ uint8_t ring_buffer[RING_BUF_SIZE]; struct ring_buf ringbuf; -#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"); +static bool rx_throttled; -USBD_DEVICE_DEFINE(sample_usbd, - DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)), - 0x2fe3, 0x0001); +#if defined(CONFIG_USB_DEVICE_STACK_NEXT) +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; + sample_usbd = sample_usbd_init_device(); + if (sample_usbd == NULL) { + LOG_ERR("Failed to initialize USB device"); + return -ENODEV; } - 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; - } - - err = usbd_enable(&sample_usbd); + err = usbd_enable(sample_usbd); if (err) { LOG_ERR("Failed to enable device support"); return err; @@ -106,12 +63,19 @@ static void interrupt_handler(const struct device *dev, void *user_data) ARG_UNUSED(user_data); while (uart_irq_update(dev) && uart_irq_is_pending(dev)) { - if (uart_irq_rx_ready(dev)) { + if (!rx_throttled && uart_irq_rx_ready(dev)) { int recv_len, rb_len; uint8_t buffer[64]; size_t len = MIN(ring_buf_space_get(&ringbuf), sizeof(buffer)); + if (len == 0) { + /* Throttle because ring buffer is full */ + uart_irq_rx_disable(dev); + rx_throttled = true; + continue; + } + recv_len = uart_fifo_read(dev, buffer, len); if (recv_len < 0) { LOG_ERR("Failed to read UART FIFO"); @@ -140,6 +104,11 @@ static void interrupt_handler(const struct device *dev, void *user_data) continue; } + if (rx_throttled) { + uart_irq_rx_enable(dev); + rx_throttled = false; + } + send_len = uart_fifo_fill(dev, buffer, rb_len); if (send_len < rb_len) { LOG_ERR("Drop %d bytes", rb_len - send_len); diff --git a/samples/subsys/usb/cdc_acm/usbd_next_prj.conf b/samples/subsys/usb/cdc_acm/usbd_next_prj.conf index 36076b593adb0ed..c5147519f870444 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 000000000000000..1d330c2ad08746c --- /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 000000000000000..08d90a8661293f0 --- /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 000000000000000..95880f02b0a3684 --- /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 000000000000000..ce4d5ce7fc9bdc3 --- /dev/null +++ b/samples/subsys/usb/common/sample_usbd_init.c @@ -0,0 +1,102 @@ +/* + * 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)) { + /* + * 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 cf1601304ab6bfd..8ef0ebe2e708f25 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 000000000000000..96c5455894806dd --- /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/sample.yaml b/samples/subsys/usb/console/sample.yaml index f7fc8c03c0eef9b..0a291d23a678a9b 100644 --- a/samples/subsys/usb/console/sample.yaml +++ b/samples/subsys/usb/console/sample.yaml @@ -6,9 +6,6 @@ tests: - usb_device - usb_cdc tags: usb - platform_exclude: - - native_posix - - native_posix_64 harness: console harness_config: fixture: fixture_usb_cdc diff --git a/samples/subsys/usb/console/src/main.c b/samples/subsys/usb/console/src/main.c index d0cd78b60dc64e7..6c39cac89a6e273 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 36076b593adb0ed..841bffbf012b5ac 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/hid/sample.yaml b/samples/subsys/usb/hid/sample.yaml index 7f63562bbf73eb9..ba6cf22a2d4fbe2 100644 --- a/samples/subsys/usb/hid/sample.yaml +++ b/samples/subsys/usb/hid/sample.yaml @@ -17,6 +17,8 @@ tests: platform_allow: - native_posix - native_posix_64 + - native_sim + - native_sim_64 build_only: true integration_platforms: - - native_posix + - native_sim diff --git a/samples/subsys/usb/mass/CMakeLists.txt b/samples/subsys/usb/mass/CMakeLists.txt index ef71596104d7d37..3b4d6a7ee64308b 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 e031a4545dbd078..69cf30f5186d40e 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/boards/sensortile_box_pro.conf b/samples/subsys/usb/mass/boards/sensortile_box_pro.conf new file mode 100644 index 000000000000000..eca492a4505319d --- /dev/null +++ b/samples/subsys/usb/mass/boards/sensortile_box_pro.conf @@ -0,0 +1,16 @@ +# +# Copyright (c) 2022 O.S.Systems +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=8192 + +CONFIG_DISK_ACCESS=y +CONFIG_DISK_DRIVERS=y +CONFIG_DISK_DRIVER_SDMMC=y + +CONFIG_FILE_SYSTEM=y +CONFIG_FAT_FILESYSTEM_ELM=y + +CONFIG_APP_MSC_STORAGE_SDCARD=y diff --git a/samples/subsys/usb/mass/src/main.c b/samples/subsys/usb/mass/src/main.c index 0d8d6ba982ad671..760612279cf52c5 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 cdf37f75ada10ff..1f7345d25fd3155 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 000000000000000..ff51b08078efcfc --- /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/webusb/src/main.c b/samples/subsys/usb/webusb/src/main.c index d9e40d9b9911eff..69317465877ae67 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/usb_c/sink/boards/b_g474e_dpow1.overlay b/samples/subsys/usb_c/sink/boards/b_g474e_dpow1.overlay index 8a68e092b7c9e60..de70e93899212e3 100644 --- a/samples/subsys/usb_c/sink/boards/b_g474e_dpow1.overlay +++ b/samples/subsys/usb_c/sink/boards/b_g474e_dpow1.overlay @@ -8,6 +8,10 @@ #include / { + aliases { + usbc-port0 = &port1; + }; + /* usbc.rst vbus-voltage-divider-adc start */ vbus1: vbus { compatible = "zephyr,usb-c-vbus-adc"; diff --git a/samples/subsys/usb_c/sink/boards/stm32g081b_eval.overlay b/samples/subsys/usb_c/sink/boards/stm32g081b_eval.overlay index 2ff32caba68996c..ca6e32206c6b225 100644 --- a/samples/subsys/usb_c/sink/boards/stm32g081b_eval.overlay +++ b/samples/subsys/usb_c/sink/boards/stm32g081b_eval.overlay @@ -8,6 +8,10 @@ #include / { + aliases { + usbc-port0 = &port1; + }; + vbus1: vbus { compatible = "zephyr,usb-c-vbus-adc"; io-channels = <&adc1 9>; diff --git a/samples/subsys/usb_c/sink/boards/weact_stm32g431_core.overlay b/samples/subsys/usb_c/sink/boards/weact_stm32g431_core.overlay new file mode 100644 index 000000000000000..1b951a5ef772e00 --- /dev/null +++ b/samples/subsys/usb_c/sink/boards/weact_stm32g431_core.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Andreas Sandberg + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include + +&adc2 { + status = "okay"; +}; + +&vbus1 { + status = "okay"; +}; + +&usbc1 { + status = "okay"; +}; + +&clk_hsi { + /* The HSI is used by ucpd1 */ + status = "okay"; +}; + +&ucpd1 { + status = "okay"; + dead-battery; +}; diff --git a/samples/subsys/usb_c/sink/src/main.c b/samples/subsys/usb_c/sink/src/main.c index 87ed5114838075c..fb6407a030917d5 100644 --- a/samples/subsys/usb_c/sink/src/main.c +++ b/samples/subsys/usb_c/sink/src/main.c @@ -13,10 +13,10 @@ #include LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG); -#define PORT1_NODE DT_NODELABEL(port1) -#define PORT1_POWER_ROLE DT_ENUM_IDX(DT_NODELABEL(port1), power_role) +#define USBC_PORT0_NODE DT_ALIAS(usbc_port0) +#define USBC_PORT0_POWER_ROLE DT_ENUM_IDX(USBC_PORT0_NODE, power_role) -#if (PORT1_POWER_ROLE != TC_ROLE_SINK) +#if (USBC_PORT0_POWER_ROLE != TC_ROLE_SINK) #error "Unsupported board: Only Sink device supported" #endif @@ -26,9 +26,9 @@ LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG); /** * @brief A structure that encapsulates Port data. */ -static struct port1_data_t { +static struct port0_data_t { /** Sink Capabilities */ - uint32_t snk_caps[DT_PROP_LEN(DT_NODELABEL(port1), sink_pdos)]; + uint32_t snk_caps[DT_PROP_LEN(USBC_PORT0_NODE, sink_pdos)]; /** Number of Sink Capabilities */ int snk_cap_cnt; /** Source Capabilities */ @@ -37,9 +37,9 @@ static struct port1_data_t { int src_cap_cnt; /* Power Supply Ready flag */ atomic_t ps_ready; -} port1_data = { - .snk_caps = {DT_FOREACH_PROP_ELEM(DT_NODELABEL(port1), sink_pdos, SINK_PDO)}, - .snk_cap_cnt = DT_PROP_LEN(DT_NODELABEL(port1), sink_pdos), +} port0_data = { + .snk_caps = {DT_FOREACH_PROP_ELEM(USBC_PORT0_NODE, sink_pdos, SINK_PDO)}, + .snk_cap_cnt = DT_PROP_LEN(USBC_PORT0_NODE, sink_pdos), .src_caps = {0}, .src_cap_cnt = 0, .ps_ready = 0 @@ -61,7 +61,7 @@ static struct port1_data_t { * @note Generally a sink application would build an RDO from the * Source Capabilities stored in the dpm_data object */ -static uint32_t build_rdo(const struct port1_data_t *dpm_data) +static uint32_t build_rdo(const struct port0_data_t *dpm_data) { union pd_rdo rdo; @@ -161,7 +161,7 @@ static void display_pdo(const int idx, static void display_source_caps(const struct device *dev) { - struct port1_data_t *dpm_data = usbc_get_dpm_data(dev); + struct port0_data_t *dpm_data = usbc_get_dpm_data(dev); LOG_INF("Source Caps:"); for (int i = 0; i < dpm_data->src_cap_cnt; i++) { @@ -171,11 +171,11 @@ static void display_source_caps(const struct device *dev) } /* usbc.rst callbacks start */ -static int port1_policy_cb_get_snk_cap(const struct device *dev, +static int port0_policy_cb_get_snk_cap(const struct device *dev, uint32_t **pdos, int *num_pdos) { - struct port1_data_t *dpm_data = usbc_get_dpm_data(dev); + struct port0_data_t *dpm_data = usbc_get_dpm_data(dev); *pdos = dpm_data->snk_caps; *num_pdos = dpm_data->snk_cap_cnt; @@ -183,11 +183,11 @@ static int port1_policy_cb_get_snk_cap(const struct device *dev, return 0; } -static void port1_policy_cb_set_src_cap(const struct device *dev, +static void port0_policy_cb_set_src_cap(const struct device *dev, const uint32_t *pdos, const int num_pdos) { - struct port1_data_t *dpm_data; + struct port0_data_t *dpm_data; int num; int i; @@ -205,19 +205,19 @@ static void port1_policy_cb_set_src_cap(const struct device *dev, dpm_data->src_cap_cnt = num; } -static uint32_t port1_policy_cb_get_rdo(const struct device *dev) +static uint32_t port0_policy_cb_get_rdo(const struct device *dev) { - struct port1_data_t *dpm_data = usbc_get_dpm_data(dev); + struct port0_data_t *dpm_data = usbc_get_dpm_data(dev); return build_rdo(dpm_data); } /* usbc.rst callbacks end */ /* usbc.rst notify start */ -static void port1_notify(const struct device *dev, +static void port0_notify(const struct device *dev, const enum usbc_policy_notify_t policy_notify) { - struct port1_data_t *dpm_data = usbc_get_dpm_data(dev); + struct port0_data_t *dpm_data = usbc_get_dpm_data(dev); switch (policy_notify) { case PROTOCOL_ERROR: @@ -269,7 +269,7 @@ static void port1_notify(const struct device *dev, /* usbc.rst notify end */ /* usbc.rst check start */ -bool port1_policy_check(const struct device *dev, +bool port0_policy_check(const struct device *dev, const enum usbc_policy_check_t policy_check) { switch (policy_check) { @@ -295,12 +295,12 @@ bool port1_policy_check(const struct device *dev, int main(void) { - const struct device *usbc_port1; + const struct device *usbc_port0; /* Get the device for this port */ - usbc_port1 = DEVICE_DT_GET(PORT1_NODE); - if (!device_is_ready(usbc_port1)) { - LOG_ERR("PORT1 device not ready"); + usbc_port0 = DEVICE_DT_GET(USBC_PORT0_NODE); + if (!device_is_ready(usbc_port0)) { + LOG_ERR("PORT0 device not ready"); return 0; } @@ -308,33 +308,33 @@ int main(void) /* Register USB-C Callbacks */ /* Register Policy Check callback */ - usbc_set_policy_cb_check(usbc_port1, port1_policy_check); + usbc_set_policy_cb_check(usbc_port0, port0_policy_check); /* Register Policy Notify callback */ - usbc_set_policy_cb_notify(usbc_port1, port1_notify); + usbc_set_policy_cb_notify(usbc_port0, port0_notify); /* Register Policy Get Sink Capabilities callback */ - usbc_set_policy_cb_get_snk_cap(usbc_port1, port1_policy_cb_get_snk_cap); + usbc_set_policy_cb_get_snk_cap(usbc_port0, port0_policy_cb_get_snk_cap); /* Register Policy Set Source Capabilities callback */ - usbc_set_policy_cb_set_src_cap(usbc_port1, port1_policy_cb_set_src_cap); + usbc_set_policy_cb_set_src_cap(usbc_port0, port0_policy_cb_set_src_cap); /* Register Policy Get Request Data Object callback */ - usbc_set_policy_cb_get_rdo(usbc_port1, port1_policy_cb_get_rdo); + usbc_set_policy_cb_get_rdo(usbc_port0, port0_policy_cb_get_rdo); /* usbc.rst register end */ /* usbc.rst user data start */ /* Set Application port data object. This object is passed to the policy callbacks */ - port1_data.ps_ready = ATOMIC_INIT(0); - usbc_set_dpm_data(usbc_port1, &port1_data); + port0_data.ps_ready = ATOMIC_INIT(0); + usbc_set_dpm_data(usbc_port0, &port0_data); /* usbc.rst user data end */ /* usbc.rst usbc start */ /* Start the USB-C Subsystem */ - usbc_start(usbc_port1); + usbc_start(usbc_port0); /* usbc.rst usbc end */ while (1) { /* Perform Application Specific functions */ - if (atomic_test_and_clear_bit(&port1_data.ps_ready, 0)) { + if (atomic_test_and_clear_bit(&port0_data.ps_ready, 0)) { /* Display the Source Capabilities */ - display_source_caps(usbc_port1); + display_source_caps(usbc_port0); } /* Arbitrary delay */ diff --git a/samples/subsys/usb_c/source/boards/stm32g081b_eval.overlay b/samples/subsys/usb_c/source/boards/stm32g081b_eval.overlay index 9e56510ee6b7fe9..d81b3d9dbee99fb 100644 --- a/samples/subsys/usb_c/source/boards/stm32g081b_eval.overlay +++ b/samples/subsys/usb_c/source/boards/stm32g081b_eval.overlay @@ -8,6 +8,9 @@ #include / { + aliases { + usbc-port0 = &port1; + }; pwmleds { compatible = "pwm-leds"; diff --git a/samples/subsys/usb_c/source/src/main.c b/samples/subsys/usb_c/source/src/main.c index 416c717a3ed9ece..1e7018c2748fa33 100644 --- a/samples/subsys/usb_c/source/src/main.c +++ b/samples/subsys/usb_c/source/src/main.c @@ -15,11 +15,11 @@ LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG); #include "power_ctrl.h" -#define PORT1_NODE DT_NODELABEL(port1) -#define PORT1_POWER_ROLE DT_ENUM_IDX(DT_NODELABEL(port1), power_role) +#define USBC_PORT0_NODE DT_ALIAS(usbc_port0) +#define USBC_PORT0_POWER_ROLE DT_ENUM_IDX(USBC_PORT0_NODE, power_role) /* A Source power role evauates to 1. See usbc_tc.h: TC_ROLE_SOURCE */ -#if (PORT1_POWER_ROLE != 1) +#if (USBC_PORT0_POWER_ROLE != 1) #error "Unsupported board: Only Source device supported" #endif @@ -29,9 +29,9 @@ LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG); /** * @brief A structure that encapsulates Port data. */ -static struct port1_data_t { +static struct port0_data_t { /** Source Capabilities */ - uint32_t src_caps[DT_PROP_LEN(DT_NODELABEL(port1), source_pdos)]; + uint32_t src_caps[DT_PROP_LEN(USBC_PORT0_NODE, source_pdos)]; /** Number of Source Capabilities */ int src_cap_cnt; /** CC Rp value */ @@ -48,10 +48,10 @@ static struct port1_data_t { bool ps_tran_start; /** Log Sink Requested RDO to console */ atomic_t show_sink_request; -} port1_data = { - .rp = DT_ENUM_IDX(DT_NODELABEL(port1), typec_power_opmode), - .src_caps = {DT_FOREACH_PROP_ELEM(DT_NODELABEL(port1), source_pdos, SOURCE_PDO)}, - .src_cap_cnt = DT_PROP_LEN(DT_NODELABEL(port1), source_pdos), +} port0_data = { + .rp = DT_ENUM_IDX(USBC_PORT0_NODE, typec_power_opmode), + .src_caps = {DT_FOREACH_PROP_ELEM(USBC_PORT0_NODE, source_pdos, SOURCE_PDO)}, + .src_cap_cnt = DT_PROP_LEN(USBC_PORT0_NODE, source_pdos), }; /* usbc.rst port data object end */ @@ -84,10 +84,10 @@ static void dump_sink_request_rdo(const uint32_t rdo) /** * @brief PE calls this function when it needs to set the Rp on CC */ -int port1_policy_cb_get_src_rp(const struct device *dev, +int port0_policy_cb_get_src_rp(const struct device *dev, enum tc_rp_value *rp) { - struct port1_data_t *dpm_data = usbc_get_dpm_data(dev); + struct port0_data_t *dpm_data = usbc_get_dpm_data(dev); *rp = dpm_data->rp; @@ -98,7 +98,7 @@ int port1_policy_cb_get_src_rp(const struct device *dev, * @brief PE calls this function to Enable (5V) or Disable (0V) the * Power Supply */ -int port1_policy_cb_src_en(const struct device *dev, bool en) +int port0_policy_cb_src_en(const struct device *dev, bool en) { source_ctrl_set(en ? SOURCE_5V : SOURCE_0V); @@ -108,9 +108,9 @@ int port1_policy_cb_src_en(const struct device *dev, bool en) /** * @brief PE calls this function to Enable or Disable VCONN */ -int port1_policy_cb_vconn_en(const struct device *dev, enum tc_cc_polarity pol, bool en) +int port0_policy_cb_vconn_en(const struct device *dev, enum tc_cc_polarity pol, bool en) { - struct port1_data_t *dpm_data = usbc_get_dpm_data(dev); + struct port0_data_t *dpm_data = usbc_get_dpm_data(dev); dpm_data->vconn_pol = pol; @@ -132,10 +132,10 @@ int port1_policy_cb_vconn_en(const struct device *dev, enum tc_cc_polarity pol, * @brief PE calls this function to get the Source Caps that will be sent * to the Sink */ -int port1_policy_cb_get_src_caps(const struct device *dev, +int port0_policy_cb_get_src_caps(const struct device *dev, const uint32_t **pdos, uint32_t *num_pdos) { - struct port1_data_t *dpm_data = usbc_get_dpm_data(dev); + struct port0_data_t *dpm_data = usbc_get_dpm_data(dev); *pdos = dpm_data->src_caps; *num_pdos = dpm_data->src_cap_cnt; @@ -146,10 +146,10 @@ int port1_policy_cb_get_src_caps(const struct device *dev, /** * @brief PE calls this function to verify that a Sink's request if valid */ -static enum usbc_snk_req_reply_t port1_policy_cb_check_sink_request(const struct device *dev, +static enum usbc_snk_req_reply_t port0_policy_cb_check_sink_request(const struct device *dev, const uint32_t request_msg) { - struct port1_data_t *dpm_data = usbc_get_dpm_data(dev); + struct port0_data_t *dpm_data = usbc_get_dpm_data(dev); union pd_fixed_supply_pdo_source pdo; uint32_t obj_pos; uint32_t op_current; @@ -171,13 +171,13 @@ static enum usbc_snk_req_reply_t port1_policy_cb_check_sink_request(const struct dpm_data->obj_pos = obj_pos; - atomic_set_bit(&port1_data.show_sink_request, 0); + atomic_set_bit(&port0_data.show_sink_request, 0); /* * Clear PS ready. This will be set to true after PS is ready after * it transitions to the new level. */ - port1_data.ps_ready = false; + port0_data.ps_ready = false; return SNK_REQUEST_VALID; } @@ -186,9 +186,9 @@ static enum usbc_snk_req_reply_t port1_policy_cb_check_sink_request(const struct * @brief PE calls this function to check if the Power Supply is at the requested * level */ -static bool port1_policy_cb_is_ps_ready(const struct device *dev) +static bool port0_policy_cb_is_ps_ready(const struct device *dev) { - struct port1_data_t *dpm_data = usbc_get_dpm_data(dev); + struct port0_data_t *dpm_data = usbc_get_dpm_data(dev); /* Return true to inform that the Power Supply is ready */ @@ -199,10 +199,10 @@ static bool port1_policy_cb_is_ps_ready(const struct device *dev) * @brief PE calls this function to check if the Present Contract is still * valid */ -static bool port1_policy_cb_present_contract_is_valid(const struct device *dev, +static bool port0_policy_cb_present_contract_is_valid(const struct device *dev, const uint32_t present_contract) { - struct port1_data_t *dpm_data = usbc_get_dpm_data(dev); + struct port0_data_t *dpm_data = usbc_get_dpm_data(dev); union pd_fixed_supply_pdo_source pdo; union pd_rdo request; uint32_t obj_pos; @@ -228,10 +228,10 @@ static bool port1_policy_cb_present_contract_is_valid(const struct device *dev, /* usbc.rst callbacks end */ /* usbc.rst notify start */ -static void port1_notify(const struct device *dev, +static void port0_notify(const struct device *dev, const enum usbc_policy_notify_t policy_notify) { - struct port1_data_t *dpm_data = usbc_get_dpm_data(dev); + struct port0_data_t *dpm_data = usbc_get_dpm_data(dev); switch (policy_notify) { case PROTOCOL_ERROR: @@ -277,10 +277,10 @@ static void port1_notify(const struct device *dev, /* usbc.rst notify end */ /* usbc.rst check start */ -bool port1_policy_check(const struct device *dev, +bool port0_policy_check(const struct device *dev, const enum usbc_policy_check_t policy_check) { - struct port1_data_t *dpm_data = usbc_get_dpm_data(dev); + struct port0_data_t *dpm_data = usbc_get_dpm_data(dev); switch (policy_check) { case CHECK_POWER_ROLE_SWAP: @@ -315,12 +315,12 @@ bool port1_policy_check(const struct device *dev, int main(void) { - const struct device *usbc_port1; + const struct device *usbc_port0; /* Get the device for this port */ - usbc_port1 = DEVICE_DT_GET(PORT1_NODE); - if (!device_is_ready(usbc_port1)) { - LOG_ERR("PORT1 device not ready"); + usbc_port0 = DEVICE_DT_GET(USBC_PORT0_NODE); + if (!device_is_ready(usbc_port0)) { + LOG_ERR("PORT0 device not ready"); return 0; } @@ -328,63 +328,63 @@ int main(void) /* Register USB-C Callbacks */ /* Register Policy Check callback */ - usbc_set_policy_cb_check(usbc_port1, port1_policy_check); + usbc_set_policy_cb_check(usbc_port0, port0_policy_check); /* Register Policy Notify callback */ - usbc_set_policy_cb_notify(usbc_port1, port1_notify); + usbc_set_policy_cb_notify(usbc_port0, port0_notify); /* Register Policy callback to set the Rp on CC lines */ - usbc_set_policy_cb_get_src_rp(usbc_port1, port1_policy_cb_get_src_rp); + usbc_set_policy_cb_get_src_rp(usbc_port0, port0_policy_cb_get_src_rp); /* Register Policy callback to enable or disable power supply */ - usbc_set_policy_cb_src_en(usbc_port1, port1_policy_cb_src_en); + usbc_set_policy_cb_src_en(usbc_port0, port0_policy_cb_src_en); /* Register Policy callback to enable or disable vconn */ - usbc_set_vconn_control_cb(usbc_port1, port1_policy_cb_vconn_en); + usbc_set_vconn_control_cb(usbc_port0, port0_policy_cb_vconn_en); /* Register Policy callback to send the source caps to the sink */ - usbc_set_policy_cb_get_src_caps(usbc_port1, port1_policy_cb_get_src_caps); + usbc_set_policy_cb_get_src_caps(usbc_port0, port0_policy_cb_get_src_caps); /* Register Policy callback to check if the sink request is valid */ - usbc_set_policy_cb_check_sink_request(usbc_port1, port1_policy_cb_check_sink_request); + usbc_set_policy_cb_check_sink_request(usbc_port0, port0_policy_cb_check_sink_request); /* Register Policy callback to check if the power supply is ready */ - usbc_set_policy_cb_is_ps_ready(usbc_port1, port1_policy_cb_is_ps_ready); + usbc_set_policy_cb_is_ps_ready(usbc_port0, port0_policy_cb_is_ps_ready); /* Register Policy callback to check if Present Contract is still valid */ - usbc_set_policy_cb_present_contract_is_valid(usbc_port1, - port1_policy_cb_present_contract_is_valid); + usbc_set_policy_cb_present_contract_is_valid(usbc_port0, + port0_policy_cb_present_contract_is_valid); /* usbc.rst register end */ /* usbc.rst user data start */ /* Set Application port data object. This object is passed to the policy callbacks */ - usbc_set_dpm_data(usbc_port1, &port1_data); + usbc_set_dpm_data(usbc_port0, &port0_data); /* usbc.rst user data end */ /* Flag to show sink request */ - port1_data.show_sink_request = ATOMIC_INIT(0); + port0_data.show_sink_request = ATOMIC_INIT(0); /* Init power supply transition start */ - port1_data.ps_tran_start = false; + port0_data.ps_tran_start = false; /* Init power supply ready */ - port1_data.ps_ready = false; + port0_data.ps_ready = false; /* usbc.rst usbc start */ /* Start the USB-C Subsystem */ - usbc_start(usbc_port1); + usbc_start(usbc_port0); /* usbc.rst usbc end */ while (1) { /* Perform Application Specific functions */ /* Transition PS to new level */ - if (port1_data.ps_tran_start) { + if (port0_data.ps_tran_start) { /* * Transition Power Supply to new voltage. * Okay if this blocks. */ - source_ctrl_set(port1_data.obj_pos); - port1_data.ps_ready = true; - port1_data.ps_tran_start = false; + source_ctrl_set(port0_data.obj_pos); + port0_data.ps_ready = true; + port0_data.ps_tran_start = false; } /* Display Sink Requests */ - if (atomic_test_and_clear_bit(&port1_data.show_sink_request, 0)) { + if (atomic_test_and_clear_bit(&port0_data.show_sink_request, 0)) { /* Display the Sink request */ - dump_sink_request_rdo(port1_data.sink_request.raw_value); + dump_sink_request_rdo(port0_data.sink_request.raw_value); } /* Arbitrary delay */ k_msleep(10); diff --git a/samples/subsys/zbus/benchmark/CMakeLists.txt b/samples/subsys/zbus/benchmark/CMakeLists.txt index e66cd1e4ace6b9c..548225af792fcce 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 2fdeb3ff76b0b8a..3a21c2fd6f8ee4a 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 4dd146076230421..52a7d864481839b 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 ef637f358f139f9..db2ab59d6a4a547 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 2c2865f39185938..d79ae4dffe83704 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 b090cc9d4670e11..089d62209e23100 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 ac781a6306f96e3..267c593b4b18f16 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 000000000000000..0a1e3a7757e21dc --- /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 000000000000000..d4edc5db7746e34 --- /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 000000000000000..f6a0053126079aa --- /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 a344a9ee0876c65..716ffd9b829e413 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 03f9cead113a59a..aa5bb42c4f1a363 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 000000000000000..f2d9b7273216322 --- /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 000000000000000..ca903a7183c5f57 --- /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 000000000000000..67af0befda1a2a2 --- /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 000000000000000..5bbdc7720302d02 --- /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 000000000000000..b54a44468c28cc7 --- /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 000000000000000..e1c58da9b289c49 --- /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 000000000000000..c912344567a2907 --- /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 000000000000000..bf2df426e3abc45 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/zbus_publishing_process_example_scenario.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/subsys/zbus/remote_mock/README.rst b/samples/subsys/zbus/remote_mock/README.rst index c1a098839de016c..f599783e0fa325b 100644 --- a/samples/subsys/zbus/remote_mock/README.rst +++ b/samples/subsys/zbus/remote_mock/README.rst @@ -16,12 +16,12 @@ Building and Running ******************** This project outputs to the console. It can be built and executed -on native_posix as follows: +on :ref:`native_sim ` as follows: .. zephyr-app-commands:: :zephyr-app: samples/subsys/zbus/remote_mock :host-os: unix - :board: native_posix + :board: native_sim :goals: run Sample Output @@ -63,7 +63,11 @@ The :file:`remote_mock.py` script can be executed using the following command: python3.8 samples/subsys/zbus/remote_mock/remote_mock.py /dev/pts/2 -Note the run command above prints the value of pts port because it is running in ``native_posix``. Look at the line indicating ``uart_1 connected to pseudotty: /dev/pts/2``. It can be different in your case. If you are using a board, read the documentation to get the correct port destination (in Linux is something like ``/dev/tty...`` or in Windows ``COM...``). +Note the run command above prints the value of pts port because it is running in +:ref:`native_sim `. +Look at the line indicating ``uart_1 connected to pseudotty: /dev/pts/2``. +It can be different in your case. If you are using a board, read the documentation to get the +correct port destination (in Linux is something like ``/dev/tty...`` or in Windows ``COM...``). From the remote mock (Python script), you would see something like this: diff --git a/samples/subsys/zbus/remote_mock/sample.yaml b/samples/subsys/zbus/remote_mock/sample.yaml index 3e49a6e2b03fb88..1b632901ed21d55 100644 --- a/samples/subsys/zbus/remote_mock/sample.yaml +++ b/samples/subsys/zbus/remote_mock/sample.yaml @@ -9,4 +9,4 @@ tests: - native_sim - hifive1_revb integration_platforms: - - native_posix + - native_sim diff --git a/samples/subsys/zbus/uart_bridge/README.rst b/samples/subsys/zbus/uart_bridge/README.rst index c14c0e8d64daf0f..a0101fa45b24ccf 100644 --- a/samples/subsys/zbus/uart_bridge/README.rst +++ b/samples/subsys/zbus/uart_bridge/README.rst @@ -14,12 +14,12 @@ Building and Running ******************** This project outputs to the console. It can be built and executed -on native_posix as follows: +on native_sim as follows: .. zephyr-app-commands:: :zephyr-app: samples/subsys/zbus/uart_bridge :host-os: unix - :board: native_posix + :board: native_sim :goals: run Sample Output @@ -68,7 +68,11 @@ The :file:`decoder.py` script can be executed using the following command: python3.8 samples/subsys/zbus/uart_bridge/decoder.py /dev/pts/2 -Note the run command above prints the value of pts port because it is running in ``native_posix``. Look at the line indicating ``uart_1 connected to pseudotty: /dev/pts/2``. It can be different in your case. If you are using a board, read the documentation to get the correct port destination (in Linux is something like ``/dev/tty...`` or in Windows ``COM...``). +Note the run command above prints the value of pts port because it is running in +:ref:`native_sim `. +Look at the line indicating ``uart_1 connected to pseudotty: /dev/pts/2``. +It can be different in your case. If you are using a board, read the documentation to get the +correct port destination (in Linux is something like ``/dev/tty...`` or in Windows ``COM...``). From the serial decoder (Python script), you would see something like this: diff --git a/samples/synchronization/src/main.c b/samples/synchronization/src/main.c index 027abd1ed9671e7..e72eea92f92533a 100644 --- a/samples/synchronization/src/main.c +++ b/samples/synchronization/src/main.c @@ -1,4 +1,4 @@ -/* main.c - Hello World demo */ +/* main.c - Synchronization demo */ /* * Copyright (c) 2012-2014 Wind River Systems, Inc. @@ -10,7 +10,7 @@ #include /* - * The hello world demo has two threads that utilize semaphores and sleeping + * The synchronization demo has two threads that utilize semaphores and sleeping * to take turns printing a greeting message at a controlled rate. The demo * shows both the static and dynamic approaches for spawning a thread; a real * world application would likely use the static approach for both threads. @@ -33,8 +33,8 @@ * @param my_sem thread's own semaphore * @param other_sem other thread's semaphore */ -void helloLoop(const char *my_name, - struct k_sem *my_sem, struct k_sem *other_sem) +void hello_loop(const char *my_name, + struct k_sem *my_sem, struct k_sem *other_sem) { const char *tname; uint8_t cpu; @@ -68,66 +68,52 @@ void helloLoop(const char *my_name, } /* define semaphores */ +K_SEM_DEFINE(thread_a_sem, 1, 1); /* starts off "available" */ +K_SEM_DEFINE(thread_b_sem, 0, 1); /* starts off "not available" */ -K_SEM_DEFINE(threadA_sem, 1, 1); /* starts off "available" */ -K_SEM_DEFINE(threadB_sem, 0, 1); /* starts off "not available" */ - - -/* threadB is a dynamic thread that is spawned by threadA */ - -void threadB(void *dummy1, void *dummy2, void *dummy3) +/* thread_a is a dynamic thread that is spawned in main */ +void thread_a_entry_point(void *dummy1, void *dummy2, void *dummy3) { ARG_UNUSED(dummy1); ARG_UNUSED(dummy2); ARG_UNUSED(dummy3); - /* invoke routine to ping-pong hello messages with threadA */ - helloLoop(__func__, &threadB_sem, &threadA_sem); + /* invoke routine to ping-pong hello messages with thread_b */ + hello_loop(__func__, &thread_a_sem, &thread_b_sem); } +K_THREAD_STACK_DEFINE(thread_a_stack_area, STACKSIZE); +static struct k_thread thread_a_data; -K_THREAD_STACK_DEFINE(threadA_stack_area, STACKSIZE); -static struct k_thread threadA_data; - -K_THREAD_STACK_DEFINE(threadB_stack_area, STACKSIZE); -static struct k_thread threadB_data; - -/* threadA is a static thread that is spawned automatically */ - -void threadA(void *dummy1, void *dummy2, void *dummy3) +/* thread_b is a static thread spawned immediately */ +void thread_b_entry_point(void *dummy1, void *dummy2, void *dummy3) { ARG_UNUSED(dummy1); ARG_UNUSED(dummy2); ARG_UNUSED(dummy3); - /* invoke routine to ping-pong hello messages with threadB */ - helloLoop(__func__, &threadA_sem, &threadB_sem); + /* invoke routine to ping-pong hello messages with thread_a */ + hello_loop(__func__, &thread_b_sem, &thread_a_sem); } +K_THREAD_DEFINE(thread_b, STACKSIZE, + thread_b_entry_point, NULL, NULL, NULL, + PRIORITY, 0, 0); +extern const k_tid_t thread_b; int main(void) { - k_thread_create(&threadA_data, threadA_stack_area, - K_THREAD_STACK_SIZEOF(threadA_stack_area), - threadA, NULL, NULL, NULL, + k_thread_create(&thread_a_data, thread_a_stack_area, + K_THREAD_STACK_SIZEOF(thread_a_stack_area), + thread_a_entry_point, NULL, NULL, NULL, PRIORITY, 0, K_FOREVER); - k_thread_name_set(&threadA_data, "thread_a"); -#if PIN_THREADS - if (arch_num_cpus() > 1) { - k_thread_cpu_pin(&threadA_data, 0); - } -#endif + k_thread_name_set(&thread_a_data, "thread_a"); - k_thread_create(&threadB_data, threadB_stack_area, - K_THREAD_STACK_SIZEOF(threadB_stack_area), - threadB, NULL, NULL, NULL, - PRIORITY, 0, K_FOREVER); - k_thread_name_set(&threadB_data, "thread_b"); #if PIN_THREADS if (arch_num_cpus() > 1) { - k_thread_cpu_pin(&threadB_data, 1); + k_thread_cpu_pin(&thread_a_data, 0); + k_thread_cpu_pin(thread_b, 1); } #endif - k_thread_start(&threadA_data); - k_thread_start(&threadB_data); + k_thread_start(&thread_a_data); return 0; } diff --git a/samples/tfm_integration/psa_crypto/CMakeLists.txt b/samples/tfm_integration/psa_crypto/CMakeLists.txt index 17339b470b81180..f8ef1eca23fb78b 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_crypto/prj.conf b/samples/tfm_integration/psa_crypto/prj.conf index a5f38632d518565..97df07964112801 100644 --- a/samples/tfm_integration/psa_crypto/prj.conf +++ b/samples/tfm_integration/psa_crypto/prj.conf @@ -35,4 +35,4 @@ CONFIG_JSON_LIBRARY=y CONFIG_TFM_PARTITION_INITIAL_ATTESTATION=y CONFIG_TFM_QCBOR_PATH="DOWNLOAD" -CONFIG_NEWLIB_LIBC=y +CONFIG_REQUIRES_FULL_LIBC=y diff --git a/samples/tfm_integration/psa_protected_storage/CMakeLists.txt b/samples/tfm_integration/psa_protected_storage/CMakeLists.txt index bbb8a2041fd7ebb..dfb0169eda6c826 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 f11b67af843dcf4..896af7bfbdaa2ea 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 7179705cbe3c8b7..133c7203b0ef73f 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 9dcbf12ae6422d1..0d11c021627fb5c 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 3ceca57452877db..bab1254229da316 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 232fc505cfdf236..9d2809fe26963bf 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 5f34b1c0b26eb2e..b86eebc4a81e740 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 6817a7f717b27f0..0a6573f811c7777 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 69901f73928fd62..beadae9230ab59b 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 0e335a73028ef74..013332ccb1a0e94 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 6519723058c4ab1..d618868ddbfd879 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 b31ce897d275af5..7ca52b3c5c4c00f 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 1a0a407e893c395..b40042f71f5e6b3 100644 --- a/samples/userspace/hello_world_user/sample.yaml +++ b/samples/userspace/hello_world_user/sample.yaml @@ -14,4 +14,8 @@ common: tests: sample.helloworld: 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 0a2b724117e28b1..3223d4a1a27495d 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 791f103b6ef45a4..232fdd31f063d6a 100644 --- a/samples/userspace/prod_consumer/sample.yaml +++ b/samples/userspace/prod_consumer/sample.yaml @@ -13,3 +13,7 @@ common: tests: sample.userspace.prod_consumer: filter: CONFIG_ARCH_HAS_USERSPACE + arch_exclude: + - posix + platform_exclude: + - ucans32k1sic diff --git a/samples/userspace/prod_consumer/src/app_syscall.c b/samples/userspace/prod_consumer/src/app_syscall.c index 0f66c54c159b690..c1b630ba9f2ad0e 100644 --- a/samples/userspace/prod_consumer/src/app_syscall.c +++ b/samples/userspace/prod_consumer/src/app_syscall.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include LOG_MODULE_REGISTER(app_syscall); @@ -38,7 +38,7 @@ static int z_vrfy_magic_syscall(unsigned int *cookie) /* Confirm that this user-supplied pointer is valid memory that * can be accessed. If it's OK, copy into cookie_copy. */ - if (z_user_from_copy(&cookie_copy, cookie, sizeof(*cookie)) != 0) { + if (k_usermode_from_copy(&cookie_copy, cookie, sizeof(*cookie)) != 0) { return -EPERM; } @@ -47,7 +47,7 @@ static int z_vrfy_magic_syscall(unsigned int *cookie) ret = z_impl_magic_syscall(&cookie_copy); if (ret == 0 && - z_user_to_copy(cookie, &cookie_copy, sizeof(*cookie)) != 0) { + k_usermode_to_copy(cookie, &cookie_copy, sizeof(*cookie)) != 0) { return -EPERM; } diff --git a/samples/userspace/prod_consumer/src/sample_driver_handlers.c b/samples/userspace/prod_consumer/src/sample_driver_handlers.c index 8531b2b88f3d732..89a4ff1204462e6 100644 --- a/samples/userspace/prod_consumer/src/sample_driver_handlers.c +++ b/samples/userspace/prod_consumer/src/sample_driver_handlers.c @@ -5,12 +5,12 @@ */ #include -#include +#include #include "sample_driver.h" int z_vrfy_sample_driver_state_set(const struct device *dev, bool active) { - if (Z_SYSCALL_DRIVER_SAMPLE(dev, state_set)) { + if (K_SYSCALL_DRIVER_SAMPLE(dev, state_set)) { return -EINVAL; } @@ -21,11 +21,11 @@ int z_vrfy_sample_driver_state_set(const struct device *dev, bool active) int z_vrfy_sample_driver_write(const struct device *dev, void *buf) { - if (Z_SYSCALL_DRIVER_SAMPLE(dev, write)) { + if (K_SYSCALL_DRIVER_SAMPLE(dev, write)) { return -EINVAL; } - if (Z_SYSCALL_MEMORY_READ(buf, SAMPLE_DRIVER_MSG_SIZE)) { + if (K_SYSCALL_MEMORY_READ(buf, SAMPLE_DRIVER_MSG_SIZE)) { return -EFAULT; } diff --git a/samples/userspace/shared_mem/boards/nucleo_f746zg.overlay b/samples/userspace/shared_mem/boards/nucleo_f746zg.overlay new file mode 100644 index 000000000000000..50fa5dcc6e1bf13 --- /dev/null +++ b/samples/userspace/shared_mem/boards/nucleo_f746zg.overlay @@ -0,0 +1,13 @@ +/* + * Copyright 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Disable quadspi MPU region for testing + * on this stm32f7 target + * else one region is missing among 8 MPU regions + */ + +/delete-node/ &quadspi_memory; diff --git a/samples/userspace/shared_mem/sample.yaml b/samples/userspace/shared_mem/sample.yaml index 3e45ba1bbd65f0f..5b42ae2b7e3ece5 100644 --- a/samples/userspace/shared_mem/sample.yaml +++ b/samples/userspace/shared_mem/sample.yaml @@ -14,9 +14,12 @@ common: tests: sample.kernel.memory_protection.shared_mem: filter: CONFIG_ARCH_HAS_USERSPACE + arch_exclude: + - posix platform_exclude: - twr_ke18f - cy8cproto_062_4343w - cy8cproto_063_ble + - ucans32k1sic extra_configs: - CONFIG_TEST_HW_STACK_PROTECTION=n diff --git a/samples/userspace/shared_mem/src/main.c b/samples/userspace/shared_mem/src/main.c index 7eaecfc254acf1a..c8b9adbae1b507c 100644 --- a/samples/userspace/shared_mem/src/main.c +++ b/samples/userspace/shared_mem/src/main.c @@ -133,7 +133,7 @@ int main(void) * then add the thread to the domain. */ tENC = k_thread_create(&enc_thread, enc_stack, STACKSIZE, - (k_thread_entry_t)enc, NULL, NULL, NULL, + enc, NULL, NULL, NULL, -1, K_USER, K_FOREVER); k_thread_access_grant(tENC, &allforone); @@ -150,7 +150,7 @@ int main(void) tPT = k_thread_create(&pt_thread, pt_stack, STACKSIZE, - (k_thread_entry_t)pt, NULL, NULL, NULL, + pt, NULL, NULL, NULL, -1, K_USER, K_FOREVER); k_thread_access_grant(tPT, &allforone); @@ -163,7 +163,7 @@ int main(void) printk("pt_domain Created\n"); tCT = k_thread_create(&ct_thread, ct_stack, STACKSIZE, - (k_thread_entry_t)ct, NULL, NULL, NULL, + ct, NULL, NULL, NULL, -1, K_USER, K_FOREVER); k_thread_access_grant(tCT, &allforone); @@ -204,8 +204,11 @@ int main(void) * Copy memory from pt thread and encrypt to a local buffer * then copy to the ct thread. */ -void enc(void) +void enc(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); int index, index_out; @@ -252,8 +255,11 @@ void enc(void) * It can be extended to receive data from a serial port * and pass the data to enc */ -void pt(void) +void pt(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); k_sleep(K_MSEC(20)); while (1) { @@ -282,8 +288,11 @@ void pt(void) * CT waits for fBUFOUT = 1 then copies * the message clears the flag and prints */ -void ct(void) +void ct(void *p1, void *p2, void *p3) { + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); char tbuf[60]; diff --git a/samples/userspace/shared_mem/src/main.h b/samples/userspace/shared_mem/src/main.h index 3fa72b5df1fb16b..40c18364c96e7f2 100644 --- a/samples/userspace/shared_mem/src/main.h +++ b/samples/userspace/shared_mem/src/main.h @@ -20,9 +20,9 @@ #include #endif -void enc(void); -void pt(void); -void ct(void); +void enc(void *p1, void *p2, void *p3); +void pt(void *p1, void *p2, void *p3); +void ct(void *p1, void *p2, void *p3); #define _app_user_d K_APP_DMEM(user_part) #define _app_user_b K_APP_BMEM(user_part) diff --git a/samples/userspace/syscall_perf/prj.conf b/samples/userspace/syscall_perf/prj.conf index c16c800cc935de1..08f8fc9aaf74b9c 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/check_init_priorities.py b/scripts/build/check_init_priorities.py index 582d7dd0e88b24d..ba6f476fba53c64 100755 --- a/scripts/build/check_init_priorities.py +++ b/scripts/build/check_init_priorities.py @@ -77,7 +77,7 @@ def __repr__(self): _DEVICE_INIT_LEVELS[self._level], self._priority) def __str__(self): - return "%s %d" % (_DEVICE_INIT_LEVELS[self._level], self._priority) + return "%s+%d" % (_DEVICE_INIT_LEVELS[self._level], self._priority) def __lt__(self, other): return self._level_priority < other._level_priority @@ -214,7 +214,7 @@ def _process_initlevels(self): ordinal = self._device_ord_from_name(arg1_name) if ordinal: prio = Priority(level, priority) - self.devices[ordinal] = prio + self.devices[ordinal] = (prio, arg0_name) addr += size priority += 1 @@ -244,7 +244,6 @@ def __init__(self, elf_file_path, edt_pickle, log): self._obj = ZephyrInitLevels(elf_file_path) - self.warnings = 0 self.errors = 0 def _check_dep(self, dev_ord, dep_ord): @@ -268,41 +267,35 @@ def _check_dep(self, dev_ord, dep_ord): self.log.info(f"Swapped priority: {dev_compat}, {dep_compat}") dev_ord, dep_ord = dep_ord, dev_ord - dev_prio = self._obj.devices.get(dev_ord, None) - dep_prio = self._obj.devices.get(dep_ord, None) + dev_prio, dev_init = self._obj.devices.get(dev_ord, (None, None)) + dep_prio, dep_init = self._obj.devices.get(dep_ord, (None, None)) if not dev_prio or not dep_prio: return if dev_prio == dep_prio: - self.warnings += 1 - self.log.warning( - f"{dev_node.path} {dev_prio} == {dep_node.path} {dep_prio}") + raise ValueError(f"{dev_node.path} and {dep_node.path} have the " + f"same priority: {dev_prio}") elif dev_prio < dep_prio: + if not self.errors: + self.log.error("Device initialization priority validation failed, " + "the sequence of initialization calls does not match " + "the devicetree dependencies.") self.errors += 1 self.log.error( - f"{dev_node.path} {dev_prio} < {dep_node.path} {dep_prio}") + f"{dev_node.path} <{dev_init}> is initialized before its dependency " + f"{dep_node.path} <{dep_init}> ({dev_prio} < {dep_prio})") else: self.log.info( - f"{dev_node.path} {dev_prio} > {dep_node.path} {dep_prio}") - - def _check_edt_r(self, dev_ord, dev): - """Recursively check for dependencies of a device.""" - for dep in dev.depends_on: - self._check_dep(dev_ord, dep.dep_ordinal) - if dev._binding and dev._binding.child_binding: - for child in dev.children.values(): - if "compatible" in child.props: - continue - if dev._binding.path != child._binding.path: - continue - self._check_edt_r(dev_ord, child) + f"{dev_node.path} <{dev_init}> {dev_prio} > " + f"{dep_node.path} <{dep_init}> {dep_prio}") def check_edt(self): """Scan through all known devices and validate the init priorities.""" for dev_ord in self._obj.devices: dev = self._ord2node[dev_ord] - self._check_edt_r(dev_ord, dev) + for dep in dev.depends_on: + self._check_dep(dev_ord, dep.dep_ordinal) def print_initlevels(self): for level, calls in self._obj.initlevels.items(): @@ -322,8 +315,6 @@ def _parse_args(argv): parser.add_argument("-v", "--verbose", action="count", help=("enable verbose output, can be used multiple times " "to increase verbosity level")) - parser.add_argument("-w", "--fail-on-warning", action="store_true", - help="fail on both warnings and errors") parser.add_argument("--always-succeed", action="store_true", help="always exit with a return code of 0, used for testing") parser.add_argument("-o", "--output", @@ -374,9 +365,6 @@ def main(argv=None): if args.always_succeed: return 0 - if args.fail_on_warning and validator.warnings: - return 1 - if validator.errors: return 1 diff --git a/scripts/build/check_init_priorities_test.py b/scripts/build/check_init_priorities_test.py index 6e4042211942fd8..c7b2aabb25f466c 100755 --- a/scripts/build/check_init_priorities_test.py +++ b/scripts/build/check_init_priorities_test.py @@ -49,7 +49,7 @@ def test_priority_levels(self): def test_priority_strings(self): prio = check_init_priorities.Priority("POST_KERNEL", 12) - self.assertEqual(str(prio), "POST_KERNEL 12") + self.assertEqual(str(prio), "POST_KERNEL+12") self.assertEqual(repr(prio), "") class testZephyrInitLevels(unittest.TestCase): @@ -236,8 +236,8 @@ def mock_obj_name(*args): "SMP": [], }) self.assertDictEqual(obj.devices, { - 11: check_init_priorities.Priority("PRE_KERNEL_2", 0), - 22: check_init_priorities.Priority("PRE_KERNEL_2", 1), + 11: (check_init_priorities.Priority("PRE_KERNEL_2", 0), "i0"), + 22: (check_init_priorities.Priority("PRE_KERNEL_2", 1), "i1"), }) class testValidator(unittest.TestCase): @@ -280,10 +280,10 @@ def test_check_dep_no_prio(self, mock_vinit): validator._ord2node[1]._binding = None validator._ord2node[2]._binding = None - validator._obj.devices = {1: 10} + validator._obj.devices = {1: (10, "i1")} validator._check_dep(1, 2) - validator._obj.devices = {2: 20} + validator._obj.devices = {2: (20, "i2")} validator._check_dep(1, 2) self.assertFalse(validator.log.info.called) @@ -295,35 +295,48 @@ def test_check(self, mock_vinit): validator = check_init_priorities.Validator("", "", None) validator.log = mock.Mock() validator._obj = mock.Mock() - validator.warnings = 0 validator.errors = 0 - validator._ord2node = {1: mock.Mock(), 2: mock.Mock(), 3: mock.Mock()} + validator._ord2node = {1: mock.Mock(), 2: mock.Mock()} validator._ord2node[1]._binding = None validator._ord2node[1].path = "/1" validator._ord2node[2]._binding = None validator._ord2node[2].path = "/2" - validator._ord2node[3]._binding = None - validator._ord2node[3].path = "/3" - validator._obj.devices = {1: 10, 2: 10, 3: 20} + validator._obj.devices = {1: (10, "i1"), 2: (20, "i2")} - validator._check_dep(3, 1) validator._check_dep(2, 1) - validator._check_dep(1, 3) + validator._check_dep(1, 2) - validator.log.info.assert_called_once_with("/3 20 > /1 10") - validator.log.warning.assert_called_once_with("/2 10 == /1 10") - validator.log.error.assert_called_once_with("/1 10 < /3 20") - self.assertEqual(validator.warnings, 1) + validator.log.info.assert_called_once_with("/2 20 > /1 10") + validator.log.error.assert_has_calls([ + mock.call("/1 is initialized before its dependency /2 (10 < 20)") + ]) self.assertEqual(validator.errors, 1) + @mock.patch("check_init_priorities.Validator.__init__", return_value=None) + def test_check_same_prio_assert(self, mock_vinit): + validator = check_init_priorities.Validator("", "", None) + validator.log = mock.Mock() + validator._obj = mock.Mock() + validator.errors = 0 + + validator._ord2node = {1: mock.Mock(), 2: mock.Mock()} + validator._ord2node[1]._binding = None + validator._ord2node[1].path = "/1" + validator._ord2node[2]._binding = None + validator._ord2node[2].path = "/2" + + validator._obj.devices = {1: (10, "i1"), 2: (10, "i2")} + + with self.assertRaises(ValueError): + validator._check_dep(1, 2) + @mock.patch("check_init_priorities.Validator.__init__", return_value=None) def test_check_swapped(self, mock_vinit): validator = check_init_priorities.Validator("", "", None) validator.log = mock.Mock() validator._obj = mock.Mock() - validator.warnings = 0 validator.errors = 0 save_inverted_priorities = check_init_priorities._INVERTED_PRIORITY_COMPATIBLES @@ -336,15 +349,14 @@ def test_check_swapped(self, mock_vinit): validator._ord2node[3]._binding.compatible = "compat-3" validator._ord2node[3].path = "/3" - validator._obj.devices = {1: 20, 3: 10} + validator._obj.devices = {1: (20, "i1"), 3: (10, "i3")} validator._check_dep(3, 1) self.assertListEqual(validator.log.info.call_args_list, [ mock.call("Swapped priority: compat-3, compat-1"), - mock.call("/3 20 > /1 10"), + mock.call("/3 20 > /1 10"), ]) - self.assertEqual(validator.warnings, 0) self.assertEqual(validator.errors, 0) check_init_priorities._INVERTED_PRIORITY_COMPATIBLES = save_inverted_priorities @@ -354,7 +366,6 @@ def test_check_ignored(self, mock_vinit): validator = check_init_priorities.Validator("", "", None) validator.log = mock.Mock() validator._obj = mock.Mock() - validator.warnings = 0 validator.errors = 0 save_ignore_compatibles = check_init_priorities._IGNORE_COMPATIBLES @@ -374,59 +385,38 @@ def test_check_ignored(self, mock_vinit): self.assertListEqual(validator.log.info.call_args_list, [ mock.call("Ignoring priority: compat-3"), ]) - self.assertEqual(validator.warnings, 0) self.assertEqual(validator.errors, 0) check_init_priorities._IGNORE_COMPATIBLES = save_ignore_compatibles @mock.patch("check_init_priorities.Validator._check_dep") @mock.patch("check_init_priorities.Validator.__init__", return_value=None) - def test_check_edt_r(self, mock_vinit, mock_cd): - validator = check_init_priorities.Validator("", "", None) - + def test_check_edt(self, mock_vinit, mock_cd): d0 = mock.Mock() d0.dep_ordinal = 1 d1 = mock.Mock() d1.dep_ordinal = 2 + d2 = mock.Mock() + d2.dep_ordinal = 3 - c0 = mock.Mock() - c0.props = {"compatible": "c"} - c1 = mock.Mock() - c1.props = {} - c1._binding.path = "another-binding-path.yaml" - c2 = mock.Mock() - c2.props = {} - c2._binding.path = "binding-path.yaml" - c2._binding.child_binding = None - c2.depends_on = [d1] - - dev = mock.Mock() - dev.depends_on = [d0] - dev._binding.child_binding = "child-binding" - dev._binding.path = "binding-path.yaml" - dev.children.values.return_value = [c0, c1, c2] - - validator._check_edt_r(0, dev) + dev0 = mock.Mock() + dev0.depends_on = [d0] + dev1 = mock.Mock() + dev1.depends_on = [d1] + dev2 = mock.Mock() + dev2.depends_on = [d2] - self.assertListEqual(mock_cd.call_args_list, [ - mock.call(0, 1), - mock.call(0, 2), - ]) - - @mock.patch("check_init_priorities.Validator._check_edt_r") - @mock.patch("check_init_priorities.Validator.__init__", return_value=None) - def test_check_edt(self, mock_vinit, mock_cer): validator = check_init_priorities.Validator("", "", None) - validator._ord2node = {1: mock.Mock(), 2: mock.Mock(), 3: mock.Mock()} + validator._ord2node = {1: dev0, 2: dev1, 3: dev2} validator._obj = mock.Mock() validator._obj.devices = {1: 10, 2: 10, 3: 20} validator.check_edt() - self.assertListEqual(mock_cer.call_args_list, [ - mock.call(1, validator._ord2node[1]), - mock.call(2, validator._ord2node[2]), - mock.call(3, validator._ord2node[3]), + self.assertListEqual(mock_cd.call_args_list, [ + mock.call(1, 1), + mock.call(2, 2), + mock.call(3, 3), ]) if __name__ == "__main__": diff --git a/scripts/build/elf_parser.py b/scripts/build/elf_parser.py index bd7a970431c6940..101e61dbadfcf5b 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 5c525d678783699..e257074e55b4ab8 100755 --- a/scripts/build/gen_isr_tables.py +++ b/scripts/build/gen_isr_tables.py @@ -23,9 +23,7 @@ # 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_LVL_BITMASK = [0x000000FF, 0x0000FF00, 0x00FF0000] INTERRUPT_BITS = [8, 8, 8] @@ -42,7 +40,7 @@ def endian_prefix(): else: return "<" -def read_intlist(intlist_path, syms): +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: @@ -66,7 +64,7 @@ def read_intlist(intlist_path, syms): const void *param; }; """ - + intList_sect = None intlist = {} prefix = endian_prefix() @@ -77,8 +75,16 @@ def read_intlist(intlist_path, syms): else: intlist_entry_fmt = prefix + "iiII" - with open(intlist_path, "rb") as fp: - intdata = fp.read() + 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 + + if intList_sect is None: + error("Cannot find the intlist section!") + + intdata = intList_sect.data() header_sz = struct.calcsize(intlist_header_fmt) header = struct.unpack_from(intlist_header_fmt, intdata, 0) @@ -122,8 +128,9 @@ def parse_args(): help="Generate SW ISR table") parser.add_argument("-V", "--vector-table", action="store_true", help="Generate vector table") - parser.add_argument("-i", "--intlist", required=True, - help="Zephyr intlist binary for intList extraction") + parser.add_argument("-i", "--intlist-section", action="append", required=True, + 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() @@ -243,7 +250,7 @@ def write_source_file(fp, vt, swt, intlist, syms, shared): 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("\t{{(const void *){0}, (ISR){1}}}, /* {2} */\n".format(param, func_as_string, i)) fp.write("};\n") def get_symbols(obj): @@ -269,16 +276,18 @@ def bit_mask(bits): 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] + INTERRUPT_LVL_BITMASK[0] = bit_mask(INTERRUPT_BITS[0]) + INTERRUPT_LVL_BITMASK[1] = bit_mask(INTERRUPT_BITS[1]) << INTERRUPT_BITS[0] + INTERRUPT_LVL_BITMASK[2] = bit_mask(INTERRUPT_BITS[2]) << INTERRUPT_BITS[0] + INTERRUPT_BITS[1] + + debug("Level Bits Bitmask") + debug("----------------------------") + for i in range(3): + bitmask_str = "0x" + format(INTERRUPT_LVL_BITMASK[i], '08X') + debug(f"{i + 1:>5} {INTERRUPT_BITS[i]:>7} {bitmask_str:>14}") def main(): parse_args() @@ -286,6 +295,7 @@ def main(): 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"] @@ -313,7 +323,6 @@ def main(): debug('3rd level offsets: {}'.format(list_3rd_lvl_offsets)) - intlist = read_intlist(args.intlist, syms) nvec = intlist["num_vectors"] offset = intlist["offset"] @@ -349,6 +358,10 @@ def main(): for irq, flags, func, param in intlist["interrupts"]: if flags & ISR_FLAG_DIRECT: + if not vt: + error("Direct Interrupt %d declared with parameter 0x%x " + "but no vector table in use" + % (irq, param)) if param != 0: error("Direct irq %d declared, but has non-NULL parameter" % irq) @@ -368,9 +381,9 @@ def main(): 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 + irq3 = (irq & INTERRUPT_LVL_BITMASK[2]) >> INTERRUPT_BITS[0] + INTERRUPT_BITS[1] + irq2 = (irq & INTERRUPT_LVL_BITMASK[1]) >> INTERRUPT_BITS[0] + irq1 = irq & INTERRUPT_LVL_BITMASK[0] if irq3: irq_parent = irq2 diff --git a/scripts/build/gen_kobject_list.py b/scripts/build/gen_kobject_list.py index 64524c67499d52a..6e41adb797dbb72 100755 --- a/scripts/build/gen_kobject_list.py +++ b/scripts/build/gen_kobject_list.py @@ -110,8 +110,8 @@ ("k_event", ("CONFIG_EVENTS", False, True)), ("ztest_suite_node", ("CONFIG_ZTEST", True, False)), ("ztest_suite_stats", ("CONFIG_ZTEST", True, False)), - ("ztest_unit_test", ("CONFIG_ZTEST_NEW_API", True, False)), - ("ztest_test_rule", ("CONFIG_ZTEST_NEW_API", True, False)), + ("ztest_unit_test", ("CONFIG_ZTEST", True, False)), + ("ztest_test_rule", ("CONFIG_ZTEST", True, False)), ("rtio", ("CONFIG_RTIO", False, False)), ("rtio_iodev", ("CONFIG_RTIO", False, False)), ("sensor_decoder_api", ("CONFIG_SENSOR_ASYNC_API", True, False)) @@ -724,10 +724,10 @@ def get_symbols(elf): %{ #include #include -#include +#include #include %} -struct z_object; +struct k_object; """ # Different versions of gperf have different prototypes for the lookup @@ -735,7 +735,7 @@ def get_symbols(elf): # turned into a string, we told gperf to expect binary strings that are not # NULL-terminated. footer = """%% -struct z_object *z_object_gperf_find(const void *obj) +struct k_object *z_object_gperf_find(const void *obj) { return z_object_lookup((const char *)obj, sizeof(void *)); } @@ -752,10 +752,10 @@ def get_symbols(elf): } #ifndef CONFIG_DYNAMIC_OBJECTS -struct z_object *z_object_find(const void *obj) +struct k_object *k_object_find(const void *obj) ALIAS_OF(z_object_gperf_find); -void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context) +void k_object_wordlist_foreach(_wordlist_cb_func_t func, void *context) ALIAS_OF(z_object_gperf_wordlist_foreach); #endif """ @@ -885,7 +885,7 @@ def write_gperf_table(fp, syms, objs, little_endian, static_begin, static_end): driver_macro_tpl = """ -#define Z_SYSCALL_DRIVER_%(driver_upper)s(ptr, op) Z_SYSCALL_DRIVER_GEN(ptr, op, %(driver_lower)s, %(driver_upper)s) +#define K_SYSCALL_DRIVER_%(driver_upper)s(ptr, op) K_SYSCALL_DRIVER_GEN(ptr, op, %(driver_lower)s, %(driver_upper)s) """ @@ -893,9 +893,9 @@ def write_validation_output(fp): fp.write("#ifndef DRIVER_VALIDATION_GEN_H\n") fp.write("#define DRIVER_VALIDATION_GEN_H\n") - fp.write("""#define Z_SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\ - (Z_SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case) || \\ - Z_SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op)) + fp.write("""#define K_SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\ + (K_SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case) || \\ + K_SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op)) """) for subsystem in subsystems: diff --git a/scripts/build/gen_relocate_app.py b/scripts/build/gen_relocate_app.py index 1d7783cd38a9566..f1bcccf1df6997b 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/gen_syscalls.py b/scripts/build/gen_syscalls.py index 9ee4e323994173c..68d0f15f48bb696 100755 --- a/scripts/build/gen_syscalls.py +++ b/scripts/build/gen_syscalls.py @@ -322,7 +322,7 @@ def marshall_defs(func_name, func_type, args): mrsh += "\t(void) arg%d;\t/* unused */\n" % unused_arg if nmrsh > 6: - mrsh += ("\tZ_OOPS(Z_SYSCALL_MEMORY_READ(more, " + mrsh += ("\tK_OOPS(K_SYSCALL_MEMORY_READ(more, " + str(nmrsh - 5) + " * sizeof(uintptr_t)));\n") argnum = 0 @@ -349,7 +349,7 @@ def marshall_defs(func_name, func_type, args): if need_split(func_type): ptr = "((uint64_t *)%s)" % mrsh_rval(nmrsh - 1, nmrsh) - mrsh += "\t" + "Z_OOPS(Z_SYSCALL_MEMORY_WRITE(%s, 8));\n" % ptr + mrsh += "\t" + "K_OOPS(K_SYSCALL_MEMORY_WRITE(%s, 8));\n" % ptr mrsh += "\t" + "*%s = ret;\n" % ptr mrsh += "\t" + "_current->syscall_frame = NULL;\n" mrsh += "\t" + "return 0;\n" diff --git a/scripts/build/parse_syscalls.py b/scripts/build/parse_syscalls.py index 636404950dbfad6..ebdb9bb73abd39e 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/build/process_gperf.py b/scripts/build/process_gperf.py index 002cd9cc1e6bb2c..95bbd244dc7f0f5 100755 --- a/scripts/build/process_gperf.py +++ b/scripts/build/process_gperf.py @@ -83,7 +83,7 @@ def process_line(line, fp): return # Set the lookup function to static inline so it gets rolled into - # z_object_find(), nothing else will use it + # k_object_find(), nothing else will use it if re.search(args.pattern + " [*]$", line): fp.write("static inline " + line) return diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 544fc4ea0e46907..b3bfd180ccaf686 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 22406b6734ad22f..c9f09520277eaa6 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -16,6 +16,8 @@ import tempfile import traceback import shlex +import shutil +import textwrap from yamllint import config, linter @@ -284,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 @@ -302,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) @@ -324,7 +326,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. @@ -335,9 +337,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) @@ -356,6 +372,8 @@ def parse_kconfig(self): if not os.path.exists(kconfig_path): self.error(kconfig_path + " not found") + kconfiglib_dir = tempfile.mkdtemp(prefix="kconfiglib_") + sys.path.insert(0, kconfig_path) # Import globally so that e.g. kconfiglib.Symbol can be referenced in # tests @@ -370,7 +388,7 @@ def parse_kconfig(self): os.environ["ARCH_DIR"] = "arch/" os.environ["BOARD_DIR"] = "boards/*/*" os.environ["ARCH"] = "*" - os.environ["KCONFIG_BINARY_DIR"] = tempfile.gettempdir() + os.environ["KCONFIG_BINARY_DIR"] = kconfiglib_dir os.environ['DEVICETREE_CONF'] = "dummy" os.environ['TOOLCHAIN_HAS_NEWLIB'] = "y" @@ -379,10 +397,11 @@ def parse_kconfig(self): os.environ["GENERATED_DTS_BOARD_CONF"] = "dummy" # For multi repo support - self.get_modules(os.path.join(tempfile.gettempdir(), "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(tempfile.gettempdir(), "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 @@ -397,6 +416,9 @@ def parse_kconfig(self): except kconfiglib.KconfigError as e: self.failure(str(e)) raise EndTest + finally: + # Clean up the temporary directory + shutil.rmtree(kconfiglib_dir) def get_defined_syms(self, kconf): # Returns a set() with the names of all defined Kconfig symbols (with no @@ -507,7 +529,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)) @@ -638,6 +660,8 @@ def check_no_undef_outside_kconfig(self, kconf): "BTTESTER_LOG_LEVEL", # Used in tests/bluetooth/tester "BTTESTER_LOG_LEVEL_DBG", # Used in tests/bluetooth/tester "CDC_ACM_PORT_NAME_", + "CHRE", # Optional module + "CHRE_LOG_LEVEL_DBG", # Optional module "CLOCK_STM32_SYSCLK_SRC_", "CMU", "COMPILER_RT_RTLIB", @@ -656,6 +680,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 @@ -684,6 +709,7 @@ def check_no_undef_outside_kconfig(self, kconf): "PEDO_THS_MIN", "REG1", "REG2", + "RIMAGE_SIGNING_SCHEMA", # Optional module "SAMPLE_MODULE_LOG_LEVEL", # Used as an example in samples/subsys/logging "SAMPLE_MODULE_LOG_LEVEL_DBG", # Used in tests/subsys/logging/log_api "LOG_BACKEND_MOCK_OUTPUT_DEFAULT", #Referenced in tests/subsys/logging/log_syst @@ -1158,6 +1184,76 @@ def run(self): p.line, col=p.column, desc=p.desc) +class KeepSorted(ComplianceTest): + """ + Check for blocks of code or config that should be kept sorted. + """ + name = "KeepSorted" + doc = "Check for blocks of code or config that should be kept sorted." + path_hint = "" + + 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 + + block_data = "" + in_block = False + + start_marker = f"{self.MARKER}-start" + stop_marker = f"{self.MARKER}-stop" + + for line_num, line in enumerate(fp.readlines(), start=1): + if start_marker in line: + if in_block: + desc = f"nested {start_marker}" + self.fmtd_failure("error", "KeepSorted", file, line_num, + desc=desc) + in_block = True + block_data = "" + elif stop_marker in line: + if not in_block: + desc = f"{stop_marker} without {start_marker}" + self.fmtd_failure("error", "KeepSorted", file, line_num, + desc=desc) + in_block = False + + 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) + elif not line.strip() or line.startswith("#"): + # Ignore comments and blank lines + continue + elif in_block: + block_data += line + + if in_block: + self.failure(f"unterminated {start_marker} in {file}") + + def run(self): + for file in get_files(filter="d"): + with open(file, "r") as fp: + self.check_file(file, fp) + def init_logs(cli_arg): # Initializes logging diff --git a/scripts/ci/guideline_check.py b/scripts/ci/guideline_check.py index 0d4266eb3a38dba..57c878f651f2774 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 000000000000000..9daaa560c2dc836 --- /dev/null +++ b/scripts/ci/stats/merged_prs.py @@ -0,0 +1,175 @@ +#!/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 + + # less than 2 business days ... + if business_days < 2 and not ('Trivial' in labels or 'Hotfix' in labels) or \ + deltah < 4 and 'Trivial' in labels: + prj['time_rule'] = "no" + else: + prj['time_rule'] = "yes" + + # 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/tags.yaml b/scripts/ci/tags.yaml index b9152b10d680dc8..f66745fb208fdf2 100644 --- a/scripts/ci/tags.yaml +++ b/scripts/ci/tags.yaml @@ -72,7 +72,7 @@ cmsis_dsp: mcumgr: files: - - subsys/mcumgr/ + - subsys/mgmt/mcumgr/ - tests/subsys/mgmt/mcumgr/ - samples/subsys/mgmt/mcumgr/ - include/zephyr/mgmt/mcumgr/ diff --git a/scripts/ci/test_plan.py b/scripts/ci/test_plan.py index 8f2f24b08256bfe..a2ba406d8ce380c 100755 --- a/scripts/ci/test_plan.py +++ b/scripts/ci/test_plan.py @@ -12,6 +12,7 @@ import json import logging import sys +import glob from pathlib import Path from git import Repo from west.manifest import Manifest @@ -19,10 +20,17 @@ if "ZEPHYR_BASE" not in os.environ: exit("$ZEPHYR_BASE environment variable undefined.") -repository_path = Path(os.environ['ZEPHYR_BASE']) +# These are globaly used variables. They are assigned in __main__ and are visible in further methods +# however, pylint complains that it doesn't recognized them when used (used-before-assignment). +zephyr_base = Path(os.environ['ZEPHYR_BASE']) +repository_path = zephyr_base +repo_to_scan = zephyr_base +args = None + + logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO) -sys.path.append(os.path.join(repository_path, 'scripts')) +sys.path.append(os.path.join(zephyr_base, 'scripts')) import list_boards def _get_match_fn(globs, regexes): @@ -86,15 +94,20 @@ def __repr__(self): return "".format(self.name) class Filters: - def __init__(self, modified_files, pull_request=False, platforms=[]): + def __init__(self, modified_files, ignore_path, alt_tags, testsuite_root, + pull_request=False, platforms=[], detailed_test_id=True): self.modified_files = modified_files + self.testsuite_root = testsuite_root + self.resolved_files = [] self.twister_options = [] self.full_twister = False self.all_tests = [] self.tag_options = [] self.pull_request = pull_request self.platforms = platforms - self.default_run = False + self.detailed_test_id = detailed_test_id + self.ignore_path = ignore_path + self.tag_cfg_file = alt_tags def process(self): self.find_modules() @@ -103,15 +116,16 @@ def process(self): if not self.platforms: self.find_archs() self.find_boards() + self.find_excludes() - if self.default_run: - self.find_excludes(skip=["tests/*", "boards/*/*/*"]) - else: - self.find_excludes() - - def get_plan(self, options, integration=False): + def get_plan(self, options, integration=False, use_testsuite_root=True): fname = "_test_plan_partial.json" - cmd = ["scripts/twister", "-c"] + options + ["--save-tests", fname ] + cmd = [f"{zephyr_base}/scripts/twister", "-c"] + options + ["--save-tests", fname ] + if not self.detailed_test_id: + cmd += ["--no-detailed-test-id"] + if self.testsuite_root and use_testsuite_root: + for root in self.testsuite_root: + cmd+=["-T", root] if integration: cmd.append("--integration") @@ -128,7 +142,7 @@ def find_modules(self): if 'west.yml' in self.modified_files: print(f"Manifest file 'west.yml' changed") print("=========") - old_manifest_content = repo.git.show(f"{args.commits[:-2]}:west.yml") + old_manifest_content = repo_to_scan.git.show(f"{args.commits[:-2]}:west.yml") with open("west_old.yml", "w") as manifest: manifest.write(old_manifest_content) old_manifest = Manifest.from_file("west_old.yml") @@ -167,7 +181,7 @@ def find_modules(self): def find_archs(self): - # we match both arch//* and include/arch/ and skip common. + # we match both arch//* and include/zephyr/arch/ and skip common. # Some architectures like riscv require special handling, i.e. riscv # directory covers 2 architectures known to twister: riscv32 and riscv64. archs = set() @@ -175,7 +189,7 @@ def find_archs(self): for f in self.modified_files: p = re.match(r"^arch\/([^/]+)\/", f) if not p: - p = re.match(r"^include\/arch\/([^/]+)\/", f) + p = re.match(r"^include\/zephyr\/arch\/([^/]+)\/", f) if p: if p.group(1) != 'common': if p.group(1) == 'riscv': @@ -183,6 +197,8 @@ def find_archs(self): archs.add('riscv64') else: archs.add(p.group(1)) + # Modified file is treated as resolved, since a matching scope was found + self.resolved_files.append(f) _options = [] for arch in archs: @@ -196,11 +212,12 @@ def find_archs(self): self.get_plan(_options, True) else: - self.get_plan(_options, False) + self.get_plan(_options, True) def find_boards(self): boards = set() all_boards = set() + resolved = [] for f in self.modified_files: if f.endswith(".rst") or f.endswith(".png") or f.endswith(".jpg"): @@ -208,9 +225,14 @@ def find_boards(self): p = re.match(r"^boards\/[^/]+\/([^/]+)\/", f) if p and p.groups(): boards.add(p.group(1)) + resolved.append(f) + + roots = [zephyr_base] + if repository_path != zephyr_base: + roots.append(repository_path) - # Limit search to $ZEPHYR_BASE since this is where the changed files are - lb_args = argparse.Namespace(**{ 'arch_roots': [repository_path], 'board_roots': [repository_path] }) + # Look for boards in monitored repositories + lb_args = argparse.Namespace(**{ 'arch_roots': roots, 'board_roots': roots}) known_boards = list_boards.find_boards(lb_args) for b in boards: name_re = re.compile(b) @@ -218,10 +240,16 @@ def find_boards(self): if name_re.search(kb.name): all_boards.add(kb.name) + # If modified file is catched by "find_boards" workflow (change in "boards" dir AND board recognized) + # it means a proper testing scope for this file was found and this file can be removed + # from further consideration + for board in all_boards: + self.resolved_files.extend(list(filter(lambda f: board in f, resolved))) + _options = [] if len(all_boards) > 20: logging.warning(f"{len(boards)} boards changed, this looks like a global change, skipping test handling, revert to default.") - self.default_run = True + self.full_twister = True return for board in all_boards: @@ -237,11 +265,27 @@ def find_tests(self): if f.endswith(".rst"): continue d = os.path.dirname(f) - while d: + scope_found = False + while not scope_found and d: + head, tail = os.path.split(d) if os.path.exists(os.path.join(d, "testcase.yaml")) or \ os.path.exists(os.path.join(d, "sample.yaml")): tests.add(d) - break + # Modified file is treated as resolved, since a matching scope was found + self.resolved_files.append(f) + scope_found = True + elif tail == "common": + # Look for yamls in directories collocated with common + + yamls_found = [yaml for yaml in glob.iglob(head + '/**/testcase.yaml', recursive=True)] + yamls_found.extend([yaml for yaml in glob.iglob(head + '/**/sample.yaml', recursive=True)]) + if yamls_found: + for yaml in yamls_found: + tests.add(os.path.dirname(yaml)) + self.resolved_files.append(f) + scope_found = True + else: + d = os.path.dirname(d) else: d = os.path.dirname(d) @@ -251,7 +295,7 @@ def find_tests(self): if len(tests) > 20: logging.warning(f"{len(tests)} tests changed, this looks like a global change, skipping test handling, revert to default") - self.default_run = True + self.full_twister = True return if _options: @@ -261,12 +305,11 @@ def find_tests(self): _options.extend(["-p", platform]) else: _options.append("--all") - self.get_plan(_options) + self.get_plan(_options, use_testsuite_root=False) def find_tags(self): - tag_cfg_file = os.path.join(repository_path, 'scripts', 'ci', 'tags.yaml') - with open(tag_cfg_file, 'r') as ymlfile: + with open(self.tag_cfg_file, 'r') as ymlfile: tags_config = yaml.safe_load(ymlfile) tags = {} @@ -303,26 +346,27 @@ def find_tags(self): logging.info(f'Potential tag based filters: {exclude_tags}') def find_excludes(self, skip=[]): - with open("scripts/ci/twister_ignore.txt", "r") as twister_ignore: + with open(self.ignore_path, "r") as twister_ignore: ignores = twister_ignore.read().splitlines() ignores = filter(lambda x: not x.startswith("#"), ignores) found = set() - files = list(filter(lambda x: x, self.modified_files)) + files_not_resolved = list(filter(lambda x: x not in self.resolved_files, self.modified_files)) for pattern in ignores: - if pattern in skip: - continue if pattern: - found.update(fnmatch.filter(files, pattern)) + found.update(fnmatch.filter(files_not_resolved, pattern)) logging.debug(found) - logging.debug(files) + logging.debug(files_not_resolved) + + # Full twister run can be ordered by detecting great number of tests/boards changed + # or if not all modified files were resolved (corresponding scope found) + self.full_twister = self.full_twister or sorted(files_not_resolved) != sorted(found) - if sorted(files) != sorted(found): + if self.full_twister: _options = [] logging.info(f'Need to run full or partial twister...') - self.full_twister = True if self.platforms: for platform in self.platforms: _options.extend(["-p", platform]) @@ -353,6 +397,27 @@ def parse_args(): help="Number of tests per builder") parser.add_argument('-n', '--default-matrix', default=10, type=int, help="Number of tests per builder") + parser.add_argument('--detailed-test-id', action='store_true', + help="Include paths to tests' locations in tests' names.") + parser.add_argument("--no-detailed-test-id", dest='detailed_test_id', action="store_false", + help="Don't put paths into tests' names.") + parser.add_argument('-r', '--repo-to-scan', default=None, + help="Repo to scan") + parser.add_argument('--ignore-path', + default=os.path.join(zephyr_base, 'scripts', 'ci', 'twister_ignore.txt'), + help="Path to a text file with patterns of files to be matched against changed files") + parser.add_argument('--alt-tags', + default=os.path.join(zephyr_base, 'scripts', 'ci', 'tags.yaml'), + help="Path to a file describing relations between directories and tags") + parser.add_argument( + "-T", "--testsuite-root", action="append", default=[], + help="Base directory to recursively search for test cases. All " + "testcase.yaml files under here will be processed. May be " + "called multiple times. Defaults to the 'samples/' and " + "'tests/' directories at the base of the Zephyr tree.") + + # Include paths in names by default. + parser.set_defaults(detailed_test_id=True) return parser.parse_args() @@ -362,9 +427,11 @@ def parse_args(): args = parse_args() files = [] errors = 0 + if args.repo_to_scan: + repository_path = Path(args.repo_to_scan) if args.commits: - repo = Repo(repository_path) - commit = repo.git.diff("--name-only", args.commits) + repo_to_scan = Repo(repository_path) + commit = repo_to_scan.git.diff("--name-only", args.commits) files = commit.split("\n") elif args.modified_files: with open(args.modified_files, "r") as fp: @@ -375,8 +442,8 @@ def parse_args(): print("\n".join(files)) print("=========") - - f = Filters(files, args.pull_request, args.platform) + f = Filters(files, args.ignore_path, args.alt_tags, args.testsuite_root, + args.pull_request, args.platform, args.detailed_test_id) f.process() # remove dupes and filtered cases diff --git a/scripts/ci/twister_ignore.txt b/scripts/ci/twister_ignore.txt index 59f735495ca02fa..acdad51eb46426e 100644 --- a/scripts/ci/twister_ignore.txt +++ b/scripts/ci/twister_ignore.txt @@ -17,25 +17,6 @@ CODEOWNERS MAINTAINERS.yml LICENSE Makefile -tests/* -samples/* -boards/*/*/* -arch/xtensa/* -arch/x86/* -arch/posix/* -arch/arc/* -arch/sparc/* -arch/arm/* -arch/nios2/* -arch/riscv/* -include/arch/xtensa/* -include/arch/x86/* -include/arch/posix/* -include/arch/arc/* -include/arch/sparc/* -include/arch/arm/* -include/arch/nios2/* -include/arch/riscv/* doc/* # GH action have no impact on code .github/* @@ -43,6 +24,7 @@ doc/* *.md # if we change this file or associated script, it should not trigger a full # twister. +scripts/ci/test_plan.py scripts/ci/twister_ignore.txt scripts/ci/what_changed.py scripts/ci/version_mgr.py @@ -51,3 +33,4 @@ scripts/checkpatch/* scripts/checkpatch.pl scripts/ci/pylintrc scripts/footprint/* +scripts/set_assignees.py diff --git a/scripts/ci/version_mgr.py b/scripts/ci/version_mgr.py index 3957595d3517025..b800f36b42bc511 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 fbe572ac16b22ab..c8829408ee2914f 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 d21fdc7564640b1..b23a4cb76fe2b59 100755 --- a/scripts/dts/gen_defines.py +++ b/scripts/dts/gen_defines.py @@ -436,8 +436,7 @@ def write_interrupts(node): # interrupts property: we have some hard-coded logic for interrupt # mapping here. # - # TODO: can we push map_arm_gic_irq_type() and - # encode_zephyr_multi_level_irq() out of Python and into C with + # TODO: can we push map_arm_gic_irq_type() out of Python and into C with # macro magic in devicetree.h? def map_arm_gic_irq_type(irq, irq_num): @@ -453,21 +452,6 @@ def map_arm_gic_irq_type(irq, irq_num): return irq_num + 16 err(f"Invalid interrupt type specified for {irq!r}") - def encode_zephyr_multi_level_irq(irq, irq_num): - # See doc/kernel/services/interrupts.rst for details - # on how this encoding works - - irq_ctrl = irq.controller - # Look for interrupt controller parent until we have none - while irq_ctrl.interrupts: - irq_num = (irq_num + 1) << 8 - if "irq" not in irq_ctrl.interrupts[0].data: - err(f"Expected binding for {irq_ctrl!r} to have 'irq' in " - "interrupt-cells") - irq_num |= irq_ctrl.interrupts[0].data["irq"] - irq_ctrl = irq_ctrl.interrupts[0].controller - return irq_num - idx_vals = [] name_vals = [] path_id = node.z_path_id @@ -482,7 +466,6 @@ def encode_zephyr_multi_level_irq(irq, irq_num): if cell_name == "irq": if "arm,gic" in irq.controller.compats: cell_value = map_arm_gic_irq_type(irq, cell_value) - cell_value = encode_zephyr_multi_level_irq(irq, cell_value) idx_vals.append((f"{path_id}_IRQ_IDX_{i}_EXISTS", 1)) idx_macro = f"{path_id}_IRQ_IDX_{i}_VAL_{name}" @@ -494,6 +477,23 @@ def encode_zephyr_multi_level_irq(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/dts/python-devicetree/src/devicetree/edtlib.py b/scripts/dts/python-devicetree/src/devicetree/edtlib.py index 0eb8dd832d190d2..851706790b990f3 100644 --- a/scripts/dts/python-devicetree/src/devicetree/edtlib.py +++ b/scripts/dts/python-devicetree/src/devicetree/edtlib.py @@ -2052,6 +2052,56 @@ def scc_order(self) -> List[List[Node]]: except Exception as e: raise EDTError(e) + def _process_properties_r(self, root_node, props_node): + """ + Process props_node properties for dependencies, and add those as + dependencies of root_node. Then walk through all the props_node + children and do the same recursively, maintaining the same root_node. + + This ensures that on a node with child nodes, the parent node includes + the dependencies of all the child nodes as well as its own. + """ + # A Node depends on any Nodes present in 'phandle', + # 'phandles', or 'phandle-array' property values. + for prop in props_node.props.values(): + if prop.type == 'phandle': + self._graph.add_edge(root_node, prop.val) + elif prop.type == 'phandles': + if TYPE_CHECKING: + assert isinstance(prop.val, list) + for phandle_node in prop.val: + self._graph.add_edge(root_node, phandle_node) + elif prop.type == 'phandle-array': + if TYPE_CHECKING: + assert isinstance(prop.val, list) + for cd in prop.val: + if cd is None: + continue + if TYPE_CHECKING: + assert isinstance(cd, ControllerAndData) + self._graph.add_edge(root_node, cd.controller) + + # A Node depends on whatever supports the interrupts it + # generates. + for intr in props_node.interrupts: + self._graph.add_edge(root_node, intr.controller) + + # If the binding defines child bindings, link the child properties to + # the root_node as well. + if props_node._binding and props_node._binding.child_binding: + for child in props_node.children.values(): + if "compatible" in child.props: + # Not a child node, normal node on a different binding. + continue + self._process_properties_r(root_node, child) + + def _process_properties(self, node): + """ + Add node dependencies based on own as well as child node properties, + start from the node itself. + """ + self._process_properties_r(node, node) + def _init_graph(self) -> None: # Constructs a graph of dependencies between Node instances, # which is usable for computing a partial order over the dependencies. @@ -2069,30 +2119,7 @@ def _init_graph(self) -> None: for child in node.children.values(): self._graph.add_edge(child, node) - # A Node depends on any Nodes present in 'phandle', - # 'phandles', or 'phandle-array' property values. - for prop in node.props.values(): - if prop.type == 'phandle': - self._graph.add_edge(node, prop.val) - elif prop.type == 'phandles': - if TYPE_CHECKING: - assert isinstance(prop.val, list) - for phandle_node in prop.val: - self._graph.add_edge(node, phandle_node) - elif prop.type == 'phandle-array': - if TYPE_CHECKING: - assert isinstance(prop.val, list) - for cd in prop.val: - if cd is None: - continue - if TYPE_CHECKING: - assert isinstance(cd, ControllerAndData) - self._graph.add_edge(node, cd.controller) - - # A Node depends on whatever supports the interrupts it - # generates. - for intr in node.interrupts: - self._graph.add_edge(node, intr.controller) + self._process_properties(node) def _init_compat2binding(self) -> None: # Creates self._compat2binding, a dictionary that maps diff --git a/scripts/dts/python-devicetree/tests/test-bindings/child-binding.yaml b/scripts/dts/python-devicetree/tests/test-bindings/child-binding.yaml index e0af091b10e9e31..7b1334954eed263 100644 --- a/scripts/dts/python-devicetree/tests/test-bindings/child-binding.yaml +++ b/scripts/dts/python-devicetree/tests/test-bindings/child-binding.yaml @@ -10,6 +10,8 @@ child-binding: child-prop: type: int required: true + child-ref: + type: phandle child-binding: description: grandchild node @@ -17,3 +19,5 @@ child-binding: grandchild-prop: type: int required: true + grandchild-ref: + type: phandle diff --git a/scripts/dts/python-devicetree/tests/test.dts b/scripts/dts/python-devicetree/tests/test.dts index 35f0f253ce7e714..213d5d45dfeea8f 100644 --- a/scripts/dts/python-devicetree/tests/test.dts +++ b/scripts/dts/python-devicetree/tests/test.dts @@ -470,16 +470,21 @@ // 'child-binding:') // + child-binding-dep { + }; + child-binding { compatible = "top-binding"; child-1 { child-prop = <1>; grandchild { grandchild-prop = <2>; + grandchild-ref = < &{/child-binding-dep} >; }; }; child-2 { child-prop = <3>; + child-ref = < &{/child-binding-dep} >; }; }; diff --git a/scripts/dts/python-devicetree/tests/test_edtlib.py b/scripts/dts/python-devicetree/tests/test_edtlib.py index 9983e1caf01021f..ca97fbcb9c2b07b 100644 --- a/scripts/dts/python-devicetree/tests/test_edtlib.py +++ b/scripts/dts/python-devicetree/tests/test_edtlib.py @@ -627,6 +627,20 @@ def test_dependencies(): assert edt.get_node("/") in edt.get_node("/in-dir-1").depends_on assert edt.get_node("/in-dir-1") in edt.get_node("/").required_by +def test_child_dependencies(): + '''Test dependencies relashionship with child nodes propagated to parent''' + with from_here(): + edt = edtlib.EDT("test.dts", ["test-bindings"]) + + dep_node = edt.get_node("/child-binding-dep") + + assert dep_node in edt.get_node("/child-binding").depends_on + assert dep_node in edt.get_node("/child-binding/child-1/grandchild").depends_on + assert dep_node in edt.get_node("/child-binding/child-2").depends_on + assert edt.get_node("/child-binding") in dep_node.required_by + assert edt.get_node("/child-binding/child-1/grandchild") in dep_node.required_by + assert edt.get_node("/child-binding/child-2") in dep_node.required_by + def test_slice_errs(tmp_path): '''Test error messages from the internal _slice() helper''' diff --git a/scripts/footprint/fpdiff.py b/scripts/footprint/fpdiff.py index fe9c40bc40d8cfc..c76bf4a5806a823 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/footprint/plan.txt b/scripts/footprint/plan.txt index a734da017e86690..948a430c62e60a9 100644 --- a/scripts/footprint/plan.txt +++ b/scripts/footprint/plan.txt @@ -25,6 +25,6 @@ bt_tmap_central,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/tmap_central, bt_tmap_peripheral,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/tmap_peripheral, bt_tmap_bms,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/tmap_bms, bt_tmap_bmr,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/tmap_bmr, -bt_hci_rpmsg,default,nrf5340dk_nrf5340_cpunet,samples/bluetooth/hci_rpmsg, -bt_hci_rpmsg,iso-broadcast,nrf5340dk_nrf5340_cpunet,samples/bluetooth/hci_rpmsg,-DCONF_FILE=nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf -bt_hci_rpmsg,iso-receive,nrf5340dk_nrf5340_cpunet,samples/bluetooth/hci_rpmsg,-DCONF_FILE=nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf +bt_hci_ipc,default,nrf5340dk_nrf5340_cpunet,samples/bluetooth/hci_ipc, +bt_hci_ipc,iso-broadcast,nrf5340dk_nrf5340_cpunet,samples/bluetooth/hci_ipc,-DCONF_FILE=nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf +bt_hci_ipc,iso-receive,nrf5340dk_nrf5340_cpunet,samples/bluetooth/hci_ipc,-DCONF_FILE=nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf diff --git a/scripts/get_maintainer.py b/scripts/get_maintainer.py index 34db3708f505aac..8e2a09b21522b09 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/hardened.csv b/scripts/kconfig/hardened.csv index ee95b54b3a74d1b..6cc978f7e5635a6 100644 --- a/scripts/kconfig/hardened.csv +++ b/scripts/kconfig/hardened.csv @@ -39,6 +39,7 @@ TEST_RANDOM_GENERATOR,n TEST_SHELL,n TEST_USERSPACE,n TFM_CMAKE_BUILD_TYPE_DEBUG,n +TFM_DUMMY_PROVISIONING,n THREAD_MONITOR,n THREAD_NAME,n TIMER_RANDOM_GENERATOR,n diff --git a/scripts/kconfig/kconfigfunctions.py b/scripts/kconfig/kconfigfunctions.py index 621ec3cb3a8bdc6..4a74c6ff88c6407 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): """ @@ -559,6 +586,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 +854,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), diff --git a/scripts/kconfig/kconfiglib.py b/scripts/kconfig/kconfiglib.py index 75ff3c1ee9ab594..bd541d07b42aeb7 100644 --- a/scripts/kconfig/kconfiglib.py +++ b/scripts/kconfig/kconfiglib.py @@ -1096,6 +1096,8 @@ def _init(self, filename, warn, warn_to_stderr, encoding): # Do various menu tree post-processing self._finalize_node(self.top_node, self.y) + for s in self.syms.values(): + self._finalize_sym(s) self.unique_defined_syms = _ordered_unique(self.defined_syms) self.unique_choices = _ordered_unique(self.choices) @@ -2305,6 +2307,7 @@ def _lookup_sym(self, name): sym.kconfig = self sym.name = name sym.is_constant = False + sym.configdefaults = [] sym.rev_dep = sym.weak_rev_dep = sym.direct_dep = self.n if self._parsing_kconfigs: @@ -2324,6 +2327,7 @@ def _lookup_const_sym(self, name): sym.kconfig = self sym.name = name sym.is_constant = True + sym.configdefaults = [] sym.rev_dep = sym.weak_rev_dep = sym.direct_dep = self.n if self._parsing_kconfigs: @@ -2913,7 +2917,7 @@ def _parse_block(self, end_token, parent, prev): while self._next_line(): t0 = self._tokens[0] - if t0 is _T_CONFIG or t0 is _T_MENUCONFIG: + if t0 in [_T_CONFIG, _T_MENUCONFIG, _T_CONFIGDEFAULT]: # The tokenizer allocates Symbol objects for us sym = self._tokens[1] @@ -2928,7 +2932,8 @@ def _parse_block(self, end_token, parent, prev): node = MenuNode() node.kconfig = self node.item = sym - node.is_menuconfig = (t0 is _T_MENUCONFIG) + node.is_menuconfig = t0 is _T_MENUCONFIG + node.is_configdefault = t0 is _T_CONFIGDEFAULT node.prompt = node.help = node.list = None node.parent = parent node.filename = self.filename @@ -2939,6 +2944,14 @@ def _parse_block(self, end_token, parent, prev): self._parse_props(node) + if node.is_configdefault: + if (node.prompt or + node.dep != self.y or + len(node.ranges) > 0 or + len(node.selects) > 0 or + len(node.implies) > 0): + self._parse_error("configdefault can only contain `default`") + if node.is_menuconfig and not node.prompt: self._warn("the menuconfig symbol {} has no prompt" .format(sym.name_and_loc)) @@ -3551,6 +3564,23 @@ def _invalidate_all(self): # Post-parsing menu tree processing, including dependency propagation and # implicit submenu creation # + def _finalize_sym(self, sym): + # Finalizes symbol definitions + # + # - Applies configdefault node defaults to final symbols + # + # sym: + # The symbol to finalize. + + inserted = 0 + for (idx, defaults) in sym.configdefaults: + for d in defaults: + # Add the defaults to the node, with the requirement that + # direct dependencies are respected. The original order + # of the default statements between nodes is preserved. + default = (d[0], self._make_and(sym.direct_dep, d[1])) + sym.defaults.insert(inserted + idx, default) + inserted += 1 def _finalize_node(self, node, visible_if): # Finalizes a menu node and its children: @@ -3697,6 +3727,14 @@ def _add_props_to_sym(self, node): sym = node.item + if node.is_configdefault: + # Store any defaults for later application after the complete tree + # is known. The current length of of the default array is stored so + # the configdefaults can be inserted in the order they originally + # appeared. + sym.configdefaults.append((len(sym.defaults), node.defaults)) + return + # See the Symbol class docstring sym.direct_dep = self._make_or(sym.direct_dep, node.dep) @@ -4249,6 +4287,7 @@ class Symbol(object): "_write_to_conf", "choice", "defaults", + "configdefaults", "direct_dep", "env_var", "implies", @@ -4307,7 +4346,7 @@ def str_value(self): # function call (property magic) vis = self.visibility - self._write_to_conf = (vis != 0) + self._write_to_conf = vis != 0 if self.orig_type in _INT_HEX: # The C implementation checks the user value against the range in a @@ -4445,7 +4484,7 @@ def tri_value(self): # Warning: See Symbol._rec_invalidate(), and note that this is a hidden # function call (property magic) vis = self.visibility - self._write_to_conf = (vis != 0) + self._write_to_conf = vis != 0 val = 0 @@ -5613,6 +5652,7 @@ class MenuNode(object): "help", "include_path", "is_menuconfig", + "is_configdefault", "item", "kconfig", "linenr", @@ -5814,8 +5854,13 @@ def indent_add_cond(s, cond): sc = self.item if sc.__class__ is Symbol: - lines = [("menuconfig " if self.is_menuconfig else "config ") - + sc.name] + if self.is_menuconfig: + t = "menuconfig " + elif self.is_configdefault: + t = "configdefault " + else: + t = "config " + lines = [t + sc.name] else: lines = ["choice " + sc.name if sc.name else "choice"] @@ -6860,6 +6905,7 @@ def _shell_fn(kconf, _, command): _T_CLOSE_PAREN, _T_COMMENT, _T_CONFIG, + _T_CONFIGDEFAULT, _T_DEFAULT, _T_DEFCONFIG_LIST, _T_DEF_BOOL, @@ -6903,7 +6949,7 @@ def _shell_fn(kconf, _, command): _T_TRISTATE, _T_UNEQUAL, _T_VISIBLE, -) = range(1, 51) +) = range(1, 52) # Keyword to token map, with the get() method assigned directly as a small # optimization @@ -6915,6 +6961,7 @@ def _shell_fn(kconf, _, command): "choice": _T_CHOICE, "comment": _T_COMMENT, "config": _T_CONFIG, + "configdefault": _T_CONFIGDEFAULT, "def_bool": _T_DEF_BOOL, "def_hex": _T_DEF_HEX, "def_int": _T_DEF_INT, diff --git a/scripts/logging/dictionary/database_gen.py b/scripts/logging/dictionary/database_gen.py index 1737186793d8002..663adb3a3659ebd 100755 --- a/scripts/logging/dictionary/database_gen.py +++ b/scripts/logging/dictionary/database_gen.py @@ -49,6 +49,11 @@ 'pinned.rodata', ] +# Sections that contains static strings but are not part of the binary (allocable). +REMOVED_STRING_SECTIONS = [ + 'log_strings' +] + # Regulation expression to match DWARF location DT_LOCATION_REGEX = re.compile(r"\(DW_OP_addr: ([0-9a-f]+)") @@ -94,7 +99,7 @@ def parse_args(): return argparser.parse_args() -def extract_elf_code_data_sections(elf): +def extract_elf_code_data_sections(elf, wildcards = None): """Find all sections in ELF file""" sections = {} @@ -103,9 +108,9 @@ def extract_elf_code_data_sections(elf): # since they actually have code/data. # # On contrary, BSS is allocated but NOBITS. - if ( - (sect['sh_flags'] & SH_FLAGS.SHF_ALLOC) == SH_FLAGS.SHF_ALLOC - and sect['sh_type'] == 'SHT_PROGBITS' + if (((wildcards is not None) and (sect.name in wildcards)) or + ((sect['sh_flags'] & SH_FLAGS.SHF_ALLOC) == SH_FLAGS.SHF_ALLOC + and sect['sh_type'] == 'SHT_PROGBITS') ): sections[sect.name] = { 'name' : sect.name, @@ -453,7 +458,7 @@ def extract_static_strings(elf, database, section_extraction=False): """ string_mappings = {} - elf_sections = extract_elf_code_data_sections(elf) + elf_sections = extract_elf_code_data_sections(elf, REMOVED_STRING_SECTIONS) # Extract strings using ELF DWARF information str_vars = extract_string_variables(elf) diff --git a/scripts/logging/dictionary/dictionary_parser/mipi_syst.py b/scripts/logging/dictionary/dictionary_parser/mipi_syst.py index 467e74400c16a53..046a120d2fc6595 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 e74b1c7bc69feea..a60218f45e9ef09 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 7c7df5cd0c65377..2289fcc7bd442e9 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 f7f7dce877df898..5262a5a6909e552 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 e5b4c64f3b8b746..edff33da8e17dea 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 83ba8cac4330ccf..33508edb7fe9953 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 f41fdf9ddc8de1e..996ad635409187f 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 ffe1d3b93d19437..9b5c566fae0635c 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 3feb8482c913d55..093a66d53ca6c6e 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 60cf06167c456bc..c936961bd0ff99a 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/common/src/nsi_internal.h b/scripts/native_simulator/common/src/nsi_internal.h index 00e6389799637ee..ebe8289b17831b4 100644 --- a/scripts/native_simulator/common/src/nsi_internal.h +++ b/scripts/native_simulator/common/src/nsi_internal.h @@ -14,7 +14,6 @@ extern "C" { #endif /** - * * @brief find least significant bit set in a 32-bit word * * This routine finds the first bit set starting from the least significant bit @@ -30,6 +29,22 @@ static inline unsigned int nsi_find_lsb_set(uint32_t op) return __builtin_ffs(op); } +/** + * @brief find least significant bit set in a 64-bit word + * + * This routine finds the first bit set starting from the least significant bit + * in the argument passed in and returns the index of that bit. Bits are + * numbered starting at 1 from the least significant bit. A return value of + * zero indicates that the value passed is zero. + * + * @return least significant bit set, 0 if @a op is 0 + */ + +static inline unsigned int nsi_find_lsb_set64(uint64_t op) +{ + return __builtin_ffsll(op); +} + #ifdef __cplusplus } #endif diff --git a/scripts/native_simulator/native/src/hw_counter.c b/scripts/native_simulator/native/src/hw_counter.c index fc0770dc6a24b13..2429a57f07697b1 100644 --- a/scripts/native_simulator/native/src/hw_counter.c +++ b/scripts/native_simulator/native/src/hw_counter.c @@ -17,6 +17,7 @@ static bool counter_running; static uint64_t counter_value; static uint64_t counter_target; static uint64_t counter_period; +static uint64_t counter_wrap; /** * Initialize the counter with prescaler of HW @@ -28,6 +29,7 @@ static void hw_counter_init(void) counter_value = 0; counter_running = false; counter_period = NSI_NEVER; + counter_wrap = NSI_NEVER; } NSI_TASK(hw_counter_init, HW_INIT, 10); @@ -40,7 +42,7 @@ static void hw_counter_triggered(void) } hw_counter_timer = nsi_hws_get_time() + counter_period; - counter_value = counter_value + 1; + counter_value = (counter_value + 1) % counter_wrap; if (counter_value == counter_target) { hw_irq_ctrl_set_irq(COUNTER_EVENT_IRQ); @@ -58,6 +60,16 @@ void hw_counter_set_period(uint64_t period) counter_period = period; } +/* + * Set the count value at which the counter will wrap + * The counter will count up to (counter_wrap-1), i.e.: + * 0, 1, 2,.., (counter_wrap - 1), 0 + */ +void hw_counter_set_wrap_value(uint64_t wrap_value) +{ + counter_wrap = wrap_value; +} + /** * Starts the counter. It must be previously configured with * hw_counter_set_period() and hw_counter_set_target(). @@ -86,6 +98,11 @@ void hw_counter_stop(void) nsi_hws_find_next_event(); } +bool hw_counter_is_started(void) +{ + return counter_running; +} + /** * Returns the current counter value. */ @@ -94,6 +111,14 @@ uint64_t hw_counter_get_value(void) return counter_value; } +/** + * Resets the counter value. + */ +void hw_counter_reset(void) +{ + counter_value = 0; +} + /** * Configures the counter to generate an interrupt * when its count value reaches target. diff --git a/scripts/native_simulator/native/src/include/hw_counter.h b/scripts/native_simulator/native/src/include/hw_counter.h index 766aa8e27c34116..9230f930bdf1e94 100644 --- a/scripts/native_simulator/native/src/include/hw_counter.h +++ b/scripts/native_simulator/native/src/include/hw_counter.h @@ -22,9 +22,12 @@ void hw_counter_triggered(void); void hw_counter_set_period(uint64_t period); void hw_counter_set_target(uint64_t counter_target); +void hw_counter_set_wrap_value(uint64_t wrap_value); void hw_counter_start(void); void hw_counter_stop(void); +bool hw_counter_is_started(void); uint64_t hw_counter_get_value(void); +void hw_counter_reset(void); #ifdef __cplusplus } diff --git a/scripts/native_simulator/native/src/irq_ctrl.c b/scripts/native_simulator/native/src/irq_ctrl.c index 40ee28487f01c0c..2c187f776797335 100644 --- a/scripts/native_simulator/native/src/irq_ctrl.c +++ b/scripts/native_simulator/native/src/irq_ctrl.c @@ -95,7 +95,7 @@ int hw_irq_ctrl_get_highest_prio_irq(void) int winner_prio = 256; while (irq_status != 0U) { - int irq_nbr = nsi_find_lsb_set(irq_status) - 1; + int irq_nbr = nsi_find_lsb_set64(irq_status) - 1; irq_status &= ~((uint64_t) 1 << irq_nbr); if ((winner_prio > (int)irq_prio[irq_nbr]) diff --git a/scripts/native_simulator/native/src/nsi_cmdline.c b/scripts/native_simulator/native/src/nsi_cmdline.c index e2fefb677fac149..c2490aa85cbe300 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 de74e6cac939274..a25cc1c5e6e3234 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 11162b30b5e3cbc..85f5d62efc99de0 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/README.rst b/scripts/pylib/pytest-twister-harness/README.rst index 814282fc57b21c4..860b7cd645de027 100644 --- a/scripts/pylib/pytest-twister-harness/README.rst +++ b/scripts/pylib/pytest-twister-harness/README.rst @@ -20,8 +20,8 @@ Run exemplary test shell application by Twister: cd ${ZEPHYR_BASE} - # native_posix & QEMU - ./scripts/twister -p native_posix -p qemu_x86 -T samples/subsys/testsuite/pytest/shell + # native_sim & QEMU + ./scripts/twister -p native_sim -p qemu_x86 -T samples/subsys/testsuite/pytest/shell # hardware ./scripts/twister -p nrf52840dk_nrf52840 --device-testing --device-serial /dev/ttyACM0 -T samples/subsys/testsuite/pytest/shell @@ -34,8 +34,8 @@ or build shell application by west and call pytest directly: cd ${ZEPHYR_BASE}/samples/subsys/testsuite/pytest/shell - # native_posix - west build -p -b native_posix -- -DCONFIG_NATIVE_UART_0_ON_STDINOUT=y + # native_sim + west build -p -b native_sim -- -DCONFIG_NATIVE_UART_0_ON_STDINOUT=y pytest --twister-harness --device-type=native --build-dir=build -p twister_harness.plugin # QEMU 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 59be6c52af9a1e5..b5560650c1b6cf0 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 403978eed9a23ba..4a6967b6372ac76 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 @@ -116,7 +117,6 @@ def _flash_and_run(self) -> None: stdout_decoded = stdout.decode(errors='ignore') with open(self.device_log_path, 'a+') as log_file: log_file.write(stdout_decoded) - logger.debug(f'Flashing output:\n{stdout_decoded}') if self.device_config.post_flash_script: self._run_custom_script(self.device_config.post_flash_script, self.base_timeout) if process is not None and process.returncode == 0: @@ -151,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/device/utils.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/device/utils.py index 5b89d1ad7a851e5..60ee2537bb8d549 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/device/utils.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/device/utils.py @@ -44,7 +44,7 @@ def terminate_process(proc: subprocess.Popen) -> None: for child in psutil.Process(proc.pid).children(recursive=True): try: os.kill(child.pid, signal.SIGTERM) - except ProcessLookupError: + except (ProcessLookupError, psutil.NoSuchProcess): pass proc.terminate() # sleep for a while before attempting to kill 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 e2e82674ada817f..f2b1b53706c94c2 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures.py @@ -36,11 +36,16 @@ def device_object(twister_harness_config: TwisterHarnessConfig) -> Generator[Dev device_object.close() -@pytest.fixture(scope='function') +def determine_scope(fixture_name, config): + if dut_scope := config.getoption("--dut-scope", None): + return dut_scope + return 'function' + + +@pytest.fixture(scope=determine_scope) def dut(request: pytest.FixtureRequest, device_object: DeviceAdapter) -> Generator[DeviceAdapter, None, None]: """Return launched device - with run application.""" - test_name = request.node.name - device_object.initialize_log_files(test_name) + device_object.initialize_log_files(request.node.name) try: device_object.launch() yield device_object @@ -48,7 +53,7 @@ def dut(request: pytest.FixtureRequest, device_object: DeviceAdapter) -> Generat device_object.close() -@pytest.fixture(scope='function') +@pytest.fixture(scope=determine_scope) def shell(dut: DeviceAdapter) -> Shell: """Return ready to use shell interface""" shell = Shell(dut, timeout=20.0) 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 b6cab6475c1067c..038c16a4fc8de15 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 f6eb8074451d5c5..64f1cac63f48362 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 @@ -55,7 +55,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/src/twister_harness/plugin.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/plugin.py index 076d36d4cc9aa83..dbd3465aba19e9d 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/plugin.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/plugin.py @@ -100,6 +100,11 @@ def pytest_addoption(parser: pytest.Parser): metavar='PATH', help='Script executed after closing serial connection.' ) + twister_harness_group.addoption( + '--dut-scope', + choices=('function', 'class', 'module', 'package', 'session'), + help='The scope for which `dut` and `shell` fixtures are shared.' + ) def pytest_configure(config: pytest.Config): 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 f336311143ac7fd..e8aaabe8fe1b38e 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 f431e2d57c2f6b1..843fce51a7cf31c 100644 --- a/scripts/pylib/twister/twisterlib/config_parser.py +++ b/scripts/pylib/twister/twisterlib/config_parser.py @@ -3,6 +3,7 @@ # Copyright (c) 2018-2022 Intel Corporation # SPDX-License-Identifier: Apache-2.0 +import copy import scl import warnings from typing import Union @@ -69,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"}, @@ -176,7 +178,8 @@ def get_scenario(self, name): {"CONF_FILE", "OVERLAY_CONFIG", "DTC_OVERLAY_FILE"}, v ) else: - d[k] = v + # Copy common value to avoid mutating it with test specific values below + d[k] = copy.copy(v) for k, v in self.scenarios[name].items(): if k == "extra_args": diff --git a/scripts/pylib/twister/twisterlib/coverage.py b/scripts/pylib/twister/twisterlib/coverage.py index 067dcfbcca7c4b0..556f5b359baa443 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: @@ -71,6 +78,7 @@ def retrieve_gcov_data(input_file): @staticmethod def create_gcda_files(extracted_coverage_info): + gcda_created = True logger.debug("Generating gcda files") for filename, hexdump_val in extracted_coverage_info.items(): # if kobject_hash is given for coverage gcovr fails @@ -83,19 +91,33 @@ def create_gcda_files(extracted_coverage_info): pass continue - with open(filename, 'wb') as fp: - fp.write(bytes.fromhex(hexdump_val)) + try: + with open(filename, 'wb') as fp: + fp.write(bytes.fromhex(hexdump_val)) + except ValueError: + logger.exception("Unable to convert hex data for file: {}".format(filename)) + gcda_created = False + except FileNotFoundError: + logger.exception("Unable to create gcda file: {}".format(filename)) + gcda_created = False + return gcda_created def generate(self, outdir): + coverage_completed = True for filename in glob.glob("%s/**/handler.log" % outdir, recursive=True): gcov_data = self.__class__.retrieve_gcov_data(filename) capture_complete = gcov_data['complete'] extracted_coverage_info = gcov_data['data'] if capture_complete: - self.__class__.create_gcda_files(extracted_coverage_info) - logger.debug("Gcov data captured: {}".format(filename)) + gcda_created = self.__class__.create_gcda_files(extracted_coverage_info) + if gcda_created: + logger.debug("Gcov data captured: {}".format(filename)) + else: + logger.error("Gcov data invalid for: {}".format(filename)) + coverage_completed = False else: logger.error("Gcov data capture incomplete: {}".format(filename)) + coverage_completed = False with open(os.path.join(outdir, "coverage.log"), "a") as coveragelog: ret = self._generate(outdir, coveragelog) @@ -111,14 +133,35 @@ def generate(self, outdir): } for r in self.output_formats.split(','): logger.info(report_log[r]) + else: + coverage_completed = False + logger.debug("All coverage data processed: {}".format(coverage_completed)) + return coverage_completed 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 + '*') @@ -126,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): @@ -179,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 + '.*') @@ -201,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-executable", - str(self.gcov_tool), "-e", "tests/*"] + excludes + ["--json", - "-o", - coveragefile, - outdir] + cmd = ["gcovr", "-r", self.base_dir, + "--gcov-ignore-parse-errors=negative_hits.warn_once_per_file", + "--gcov-executable", self.gcov_tool, + "-e", "tests/*"] + cmd += excludes + mode_options + ["--json", "-o", coveragefile, outdir] cmd_str = " ".join(cmd) logger.debug(f"Running {cmd_str}...") subprocess.call(cmd, stdout=coveragelog) @@ -214,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] @@ -237,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) @@ -264,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: @@ -280,4 +383,5 @@ def run_coverage(testplan, options): coverage_tool.add_ignore_file('generated') coverage_tool.add_ignore_directory('tests') coverage_tool.add_ignore_directory('samples') - coverage_tool.generate(options.outdir) + coverage_completed = coverage_tool.generate(options.outdir) + return coverage_completed diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index 9c676ceb7336baa..03f6ab7f43026e5 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=[], @@ -216,11 +217,17 @@ def add_parse_arguments(parser = None): and 'fifo_loop' is a name of a function found in main.c without test prefix. """) + parser.add_argument( + "--pytest-args", action="append", + help="""Pass additional arguments to the pytest subprocess. This parameter + will override the pytest_args from the harness_config in YAML file. + """) + valgrind_asan_group.add_argument( "--enable-valgrind", action="store_true", help="""Run binary through valgrind and check for several memory access errors. Valgrind needs to be installed on the host. This option only - works with host binaries such as those generated for the native_posix + works with host binaries such as those generated for the native_sim configuration and is mutual exclusive with --enable-asan. """) @@ -228,7 +235,7 @@ def add_parse_arguments(parser = None): "--enable-asan", action="store_true", help="""Enable address sanitizer to check for several memory access errors. Libasan needs to be installed on the host. This option only - works with host binaries such as those generated for the native_posix + works with host binaries such as those generated for the native_sim configuration and is mutual exclusive with --enable-valgrind. """) @@ -299,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.") @@ -349,7 +358,7 @@ def add_parse_arguments(parser = None): "--enable-lsan", action="store_true", help="""Enable leak sanitizer to check for heap memory leaks. Libasan needs to be installed on the host. This option only - works with host binaries such as those generated for the native_posix + works with host binaries such as those generated for the native_sim configuration and when --enable-asan is given. """) @@ -358,12 +367,17 @@ def add_parse_arguments(parser = None): help="""Enable undefined behavior sanitizer to check for undefined behaviour during program execution. It uses an optional runtime library to provide better error diagnostics. This option only works with host - binaries such as those generated for the native_posix configuration. + binaries such as those generated for the native_sim configuration. """) parser.add_argument("--enable-size-report", action="store_true", help="Enable expensive computation of RAM/ROM segment sizes.") + parser.add_argument("--create-rom-ram-report", action="store_true", + help="Generate detailed ram/rom json reports for " + "each build, via cmake build calls with the " + "`--target footprint` argument") + parser.add_argument( "--filter", choices=['buildable', 'runnable'], default='buildable', @@ -442,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 " @@ -545,12 +568,6 @@ def add_parse_arguments(parser = None): default=True, help="deprecated, left for compatibility") - parser.add_argument("--report-excluded", - action="store_true", - help="""List all tests that are never run based on current scope and - coverage. If you are looking for accurate results, run this with - --all, but this will take a while...""") - parser.add_argument( "--report-name", help="""Create a report with a custom name. @@ -587,7 +604,7 @@ def add_parse_arguments(parser = None): parser.add_argument( "--seed", type=int, - help="Seed for native posix pseudo-random number generator") + help="Seed for native_sim pseudo-random number generator") parser.add_argument( "--short-build-path", @@ -736,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) @@ -836,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 e4a0d9f5a1a208f..3a13b819649e907 100755 --- a/scripts/pylib/twister/twisterlib/handlers.py +++ b/scripts/pylib/twister/twisterlib/handlers.py @@ -56,7 +56,7 @@ def terminate_process(proc): for child in psutil.Process(proc.pid).children(recursive=True): try: os.kill(child.pid, signal.SIGTERM) - except ProcessLookupError: + except (ProcessLookupError, psutil.NoSuchProcess): pass proc.terminate() # sleep for a while before attempting to kill @@ -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) @@ -182,7 +189,7 @@ def try_kill_process_by_pid(self): self.pid_fn = None # clear so we don't try to kill the binary twice try: os.kill(pid, signal.SIGKILL) - except ProcessLookupError: + except (ProcessLookupError, psutil.NoSuchProcess): pass def _output_reader(self, proc): @@ -246,7 +253,7 @@ def _create_command(self, robot_test): "--track-origins=yes", ] + command - # Only valid for native_posix + # Only valid for native_sim if self.seed is not None: command.append(f"--seed={self.seed}") if self.extra_test_args is not None: @@ -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(): @@ -358,10 +361,17 @@ def __init__(self, instance, type_str): """ super().__init__(instance, type_str) + def get_test_timeout(self): + timeout = super().get_test_timeout() + if self.options.enable_coverage: + # wait more for gcov data to be dumped on console + timeout += 120 + return timeout + 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. @@ -798,7 +808,7 @@ def _thread_close_files(fifo_in, fifo_out, pid, out_fp, in_fp, log_out_fp): try: if pid: os.kill(pid, signal.SIGTERM) - except ProcessLookupError: + except (ProcessLookupError, psutil.NoSuchProcess): # Oh well, as long as it's dead! User probably sent Ctrl-C pass @@ -857,6 +867,8 @@ def _thread(handler, timeout, outdir, logfile, fifo_fn, pid_fn, results, if cpu_time < timeout and not out_state: timeout_time = time.time() + (timeout - cpu_time) continue + except psutil.NoSuchProcess: + pass except ProcessLookupError: out_state = "failed" break @@ -979,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) @@ -1010,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 5e90b7c84c6f60a..27bca0071853729 100644 --- a/scripts/pylib/twister/twisterlib/hardwaremap.py +++ b/scripts/pylib/twister/twisterlib/hardwaremap.py @@ -287,7 +287,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 55525076f8ff2c8..bfdcb107ec8f2ff 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -12,7 +12,9 @@ import logging import threading import time +import shutil +from twisterlib.error import ConfigurationError from twisterlib.environment import ZEPHYR_BASE, PYTEST_PLUGIN_INSTALLED from twisterlib.handlers import Handler, terminate_process, SUPPORTED_SIMS_IN_PYTEST from twisterlib.testinstance import TestInstance @@ -54,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 @@ -79,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): @@ -160,8 +174,29 @@ def run_robot_test(self, command, handler): class Console(Harness): + def get_testcase_name(self): + ''' + Get current TestCase name. + + Console Harness id has only TestSuite id without TestCase name suffix. + Only the first TestCase name might be taken if available when a Ztest with + a single test case is configured to use this harness type for simplified + output parsing instead of the Ztest harness as Ztest suite should do. + ''' + if self.instance and len(self.instance.testcases) == 1: + return self.instance.testcases[0].name + return super(Console, self).get_testcase_name() + def configure(self, instance): super(Console, self).configure(instance) + if self.regex is None or len(self.regex) == 0: + self.state = "failed" + tc = self.instance.set_case_status_by_name( + self.get_testcase_name(), + "failed", + f"HARNESS:{self.__class__.__name__}:no regex patterns configured." + ) + raise ConfigurationError(self.instance.name, tc.reason) if self.type == "one_line": self.pattern = re.compile(self.regex[0]) self.patterns_expected = 1 @@ -170,17 +205,29 @@ def configure(self, instance): for r in self.regex: self.patterns.append(re.compile(r)) self.patterns_expected = len(self.patterns) + else: + self.state = "failed" + tc = self.instance.set_case_status_by_name( + self.get_testcase_name(), + "failed", + f"HARNESS:{self.__class__.__name__}:incorrect type={self.type}" + ) + raise ConfigurationError(self.instance.name, tc.reason) + # def handle(self, line): if self.type == "one_line": if self.pattern.search(line): - logger.debug(f"HARNESS:{self.__class__.__name__}:EXPECTED({self.next_pattern}):'{self.pattern.pattern}'") + logger.debug(f"HARNESS:{self.__class__.__name__}:EXPECTED:" + f"'{self.pattern.pattern}'") self.next_pattern += 1 self.state = "passed" elif self.type == "multi_line" and self.ordered: if (self.next_pattern < len(self.patterns) and self.patterns[self.next_pattern].search(line)): - logger.debug(f"HARNESS:{self.__class__.__name__}:EXPECTED({self.next_pattern}):'{self.patterns[self.next_pattern].pattern}'") + logger.debug(f"HARNESS:{self.__class__.__name__}:EXPECTED(" + f"{self.next_pattern + 1}/{self.patterns_expected}):" + f"'{self.patterns[self.next_pattern].pattern}'") self.next_pattern += 1 if self.next_pattern >= len(self.patterns): self.state = "passed" @@ -189,6 +236,9 @@ def handle(self, line): r = self.regex[i] if pattern.search(line) and not r in self.matches: self.matches[r] = line + logger.debug(f"HARNESS:{self.__class__.__name__}:EXPECTED(" + f"{len(self.matches)}/{self.patterns_expected}):" + f"'{pattern.pattern}'") if len(self.matches) == len(self.regex): self.state = "passed" else: @@ -203,34 +253,31 @@ 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' for 'one_line' and - # ordered 'multi_line' patterns when not all of these patterns were + # Reset the resulting test state to 'failed' when not all of the patterns were # found in the output, but just ztest's 'PROJECT EXECUTION SUCCESSFUL'. # It might happen because of the pattern sequence diverged from the # test code, the test platform has console issues, or even some other # test image was executed. - # TODO: Introduce explicit match policy type either to reject - # unexpected console output, or to allow missing patterns. + # TODO: Introduce explicit match policy type to reject + # unexpected console output, allow missing patterns, deny duplicates. if self.state == "passed" and self.ordered and self.next_pattern < self.patterns_expected: - logger.error(f"HARNESS:{self.__class__.__name__}: failed with only {self.next_pattern} matched patterns from expected {self.patterns_expected}") + logger.error(f"HARNESS:{self.__class__.__name__}: failed with" + f" {self.next_pattern} of {self.patterns_expected}" + f" expected ordered patterns.") + self.state = "failed" + if self.state == "passed" and not self.ordered and len(self.matches) < self.patterns_expected: + logger.error(f"HARNESS:{self.__class__.__name__}: failed with" + f" {len(self.matches)} of {self.patterns_expected}" + f" expected unordered patterns.") self.state = "failed" - tc = self.instance.get_case_or_create(self.id) + tc = self.instance.get_case_or_create(self.get_testcase_name()) if self.state == "passed": tc.status = "passed" else: @@ -266,8 +313,10 @@ def pytest_run(self, timeout): def generate_command(self): config = self.instance.testsuite.harness_config + handler: Handler = self.instance.handler pytest_root = config.get('pytest_root', ['pytest']) if config else ['pytest'] - pytest_args = config.get('pytest_args', []) if config else [] + pytest_args_yaml = config.get('pytest_args', []) if config else [] + pytest_dut_scope = config.get('pytest_dut_scope', None) if config else None command = [ 'pytest', '--twister-harness', @@ -280,9 +329,9 @@ def generate_command(self): ] command.extend([os.path.normpath(os.path.join( self.source_dir, os.path.expanduser(os.path.expandvars(src)))) for src in pytest_root]) - command.extend(pytest_args) - handler: Handler = self.instance.handler + if pytest_dut_scope: + command.append(f'--dut-scope={pytest_dut_scope}') if handler.options.verbose > 1: command.extend([ @@ -300,6 +349,16 @@ def generate_command(self): command.append('--device-type=custom') else: raise PytestHarnessException(f'Handling of handler {handler.type_str} not implemented yet') + + if handler.options.pytest_args: + command.extend(handler.options.pytest_args) + if pytest_args_yaml: + logger.warning(f'The pytest_args ({handler.options.pytest_args}) specified ' + 'in the command line will override the pytest_args defined ' + f'in the YAML file {pytest_args_yaml}') + else: + command.extend(pytest_args_yaml) + return command def _generate_parameters_for_hardware(self, handler: Handler): @@ -418,8 +477,10 @@ def _parse_report_file(self, report): if elem_ts := root.find('testsuite'): if elem_ts.get('failures') != '0': self.state = 'failed' + self.instance.reason = f"{elem_ts.get('failures')}/{elem_ts.get('tests')} pytest scenario(s) failed" elif elem_ts.get('errors') != '0': self.state = 'error' + self.instance.reason = 'Error during pytest execution' elif elem_ts.get('skipped') == elem_ts.get('tests'): self.state = 'skipped' else: @@ -427,7 +488,7 @@ def _parse_report_file(self, report): self.instance.execution_time = float(elem_ts.get('time')) for elem_tc in elem_ts.findall('testcase'): - tc = self.instance.get_case_or_create(f"{self.id}.{elem_tc.get('name')}") + tc = self.instance.add_testcase(f"{self.id}.{elem_tc.get('name')}") tc.duration = float(elem_tc.get('time')) elem = elem_tc.find('*') if elem is None: @@ -441,21 +502,30 @@ def _parse_report_file(self, report): tc.status = 'error' tc.reason = elem.get('message') tc.output = elem.text + else: + self.state = 'skipped' + self.instance.reason = 'No tests collected' class Gtest(Harness): ANSI_ESCAPE = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') - TEST_START_PATTERN = r"\[ RUN \] (?P.*)\.(?P.*)$" - TEST_PASS_PATTERN = r"\[ OK \] (?P.*)\.(?P.*)$" - TEST_FAIL_PATTERN = r"\[ FAILED \] (?P.*)\.(?P.*)$" - FINISHED_PATTERN = r"\[==========\] Done running all tests\.$" - has_failures = False - tc = None + TEST_START_PATTERN = r".*\[ RUN \] (?P.*)\.(?P.*)$" + TEST_PASS_PATTERN = r".*\[ OK \] (?P.*)\.(?P.*)$" + TEST_FAIL_PATTERN = r".*\[ FAILED \] (?P.*)\.(?P.*)$" + FINISHED_PATTERN = r".*\[==========\] Done running all tests\.$" + + def __init__(self): + super().__init__() + self.tc = None + self.has_failures = False def handle(self, line): # Strip the ANSI characters, they mess up the patterns non_ansi_line = self.ANSI_ESCAPE.sub('', line) + if self.state: + return + # Check if we started running a new test test_start_match = re.search(self.TEST_START_PATTERN, non_ansi_line) if test_start_match: @@ -584,13 +654,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 c1f160caad9d43e..3d4b155fa9ddcde 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,8 +244,11 @@ 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") build_log = os.path.join(instance.build_dir, "build.log") device_log = os.path.join(instance.build_dir, "device.log") @@ -284,7 +287,9 @@ def json_report(self, filename, version="NA"): suite['status'] = instance.status suite["reason"] = instance.reason # FIXME - if os.path.exists(handler_log): + if os.path.exists(pytest_log): + suite["log"] = self.process_log(pytest_log) + elif os.path.exists(handler_log): suite["log"] = self.process_log(handler_log) elif os.path.exists(device_log): suite["log"] = self.process_log(device_log) @@ -301,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 = [] @@ -341,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 @@ -539,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 25e96a3603836cf..9ef53b386c9c7da 100644 --- a/scripts/pylib/twister/twisterlib/runner.py +++ b/scripts/pylib/twister/twisterlib/runner.py @@ -25,7 +25,7 @@ from domains import Domains from twisterlib.cmakecache import CMakeCache from twisterlib.environment import canonical_zephyr_base -from twisterlib.error import BuildError +from twisterlib.error import BuildError, ConfigurationError import elftools from elftools.elf.elffile import ELFFile @@ -40,6 +40,9 @@ from twisterlib.log_helper import log_command from twisterlib.testinstance import TestInstance +from twisterlib.environment import TwisterEnv +from twisterlib.testsuite import TestSuite +from twisterlib.platform import Platform from twisterlib.testplan import change_skip_to_error_if_integration from twisterlib.harness import HarnessImporter, Pytest @@ -220,7 +223,7 @@ class CMake: config_re = re.compile('(CONFIG_[A-Za-z0-9_]+)[=]\"?([^\"]*)\"?$') dt_re = re.compile('([A-Za-z0-9_]+)[=]\"?([^\"]*)\"?$') - def __init__(self, testsuite, platform, source_dir, build_dir, jobserver): + def __init__(self, testsuite: TestSuite, platform: Platform, source_dir, build_dir, jobserver): self.cwd = None self.capture_output = True @@ -260,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: @@ -307,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=[]): @@ -381,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" @@ -401,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) @@ -409,12 +421,12 @@ 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): - def __init__(self, testsuite, platform, source_dir, build_dir, jobserver): + def __init__(self, testsuite: TestSuite, platform: Platform, source_dir, build_dir, jobserver): super().__init__(testsuite, platform, source_dir, build_dir, jobserver) self.log = "config-twister.log" @@ -499,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} @@ -517,7 +529,7 @@ def parse_generated(self, filter_stages=[]): class ProjectBuilder(FilterBuilder): - def __init__(self, instance, env, jobserver, **kwargs): + def __init__(self, instance: TestInstance, env: TwisterEnv, jobserver, **kwargs): super().__init__(instance.testsuite, instance.platform, instance.testsuite.source_dir, instance.build_dir, jobserver) self.log = "build.log" @@ -527,8 +539,7 @@ def __init__(self, instance, env, jobserver, **kwargs): self.env = env self.duts = None - @staticmethod - def log_info(filename, inline_logs): + def log_info(self, filename, inline_logs, log_testcases=False): filename = os.path.abspath(os.path.realpath(filename)) if inline_logs: logger.info("{:-^100}".format(filename)) @@ -542,6 +553,17 @@ def log_info(filename, inline_logs): logger.error(data) logger.info("{:-^100}".format(filename)) + + if log_testcases: + for tc in self.instance.testcases: + if not tc.reason: + continue + logger.info( + f"\n{str(tc.name).center(100, '_')}\n" + f"{tc.reason}\n" + f"{100*'_'}\n" + f"{tc.output}" + ) else: logger.error("see: " + Fore.YELLOW + filename + Fore.RESET) @@ -551,9 +573,12 @@ def log_info_file(self, inline_logs): b_log = "{}/build.log".format(build_dir) v_log = "{}/valgrind.log".format(build_dir) d_log = "{}/device.log".format(build_dir) + pytest_log = "{}/twister_harness.log".format(build_dir) if os.path.exists(v_log) and "Valgrind" in self.instance.reason: self.log_info("{}".format(v_log), inline_logs) + elif os.path.exists(pytest_log) and os.path.getsize(pytest_log) > 0: + self.log_info("{}".format(pytest_log), inline_logs, log_testcases=True) elif os.path.exists(h_log) and os.path.getsize(h_log) > 0: self.log_info("{}".format(h_log), inline_logs) elif os.path.exists(d_log) and os.path.getsize(d_log) > 0: @@ -568,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" @@ -584,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: @@ -594,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" @@ -606,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}) @@ -618,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: @@ -1024,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): @@ -1043,7 +1076,7 @@ def run(self): if instance.handler.type_str == "device": instance.handler.duts = self.duts - if(self.options.seed is not None and instance.platform.name.startswith("native_posix")): + if(self.options.seed is not None and instance.platform.name.startswith("native_")): self.parse_generated() if('CONFIG_FAKE_ENTROPY_NATIVE_POSIX' in self.defconfig and self.defconfig['CONFIG_FAKE_ENTROPY_NATIVE_POSIX'] == 'y'): @@ -1053,7 +1086,14 @@ def run(self): instance.handler.extra_test_args = self.options.extra_test_args harness = HarnessImporter.get_harness(instance.testsuite.harness.capitalize()) - harness.configure(instance) + try: + harness.configure(instance) + except ConfigurationError as error: + instance.status = "error" + instance.reason = str(error) + logger.error(instance.reason) + return + # if isinstance(harness, Pytest): harness.pytest_run(instance.handler.get_test_timeout()) else: @@ -1062,6 +1102,8 @@ def run(self): sys.stdout.flush() def gather_metrics(self, instance: TestInstance): + if self.options.create_rom_ram_report: + self.run_build(['--build', self.build_dir, "--target", "footprint"]) if self.options.enable_size_report and not self.options.cmake_only: self.calc_size(instance=instance, from_buildlog=self.options.footprint_from_buildlog) else: @@ -1219,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): @@ -1264,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/size_calc.py b/scripts/pylib/twister/twisterlib/size_calc.py index 8a98c447eba6b7c..f449d26ac991a50 100644 --- a/scripts/pylib/twister/twisterlib/size_calc.py +++ b/scripts/pylib/twister/twisterlib/size_calc.py @@ -78,7 +78,7 @@ class SizeCalculator: "ctors", "init_array", "reset", - "z_object_assignment_area", + "k_object_assignment_area", "rodata", "net_l2", "vector", diff --git a/scripts/pylib/twister/twisterlib/testinstance.py b/scripts/pylib/twister/twisterlib/testinstance.py index 958019b411a344c..3b307e41cf2867f 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 4607544efa76af8..f62aedab8cff045 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. @@ -385,36 +387,6 @@ def report_test_list(self): print("{} total.".format(cnt)) - - def report_excluded_tests(self): - all_tests = self.get_all_tests() - to_be_run = set() - for _, p in self.instances.items(): - to_be_run.update(p.testsuite.cases) - - if all_tests - to_be_run: - print("Tests that never build or run:") - for not_run in all_tests - to_be_run: - print("- {}".format(not_run)) - - def report_platform_tests(self, platforms=[]): - if len(platforms) > 1: - raise TwisterRuntimeError("When exporting tests, only one platform " - "should be specified.") - - for p in platforms: - inst = self.get_platform_instances(p) - count = 0 - for i in inst.values(): - for c in i.testsuite.cases: - print(f"- {c}") - count += 1 - print(f"Tests found: {count}") - - def get_platform_instances(self, platform): - filtered_dict = {k:v for k,v in self.instances.items() if k.startswith(platform + os.sep)} - return filtered_dict - def config(self): logger.info("coverage platform: {}".format(self.coverage_platform)) @@ -446,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', []): @@ -748,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) @@ -835,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']: @@ -849,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 @@ -872,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. @@ -1018,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) @@ -1032,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/pylib/twister/twisterlib/testsuite.py b/scripts/pylib/twister/twisterlib/testsuite.py index ecb7c8b40007155..419d0f3959682e7 100644 --- a/scripts/pylib/twister/twisterlib/testsuite.py +++ b/scripts/pylib/twister/twisterlib/testsuite.py @@ -450,7 +450,7 @@ def get_unique(testsuite_root, workdir, name): relative_ts_root = "" # workdir can be "." - unique = os.path.normpath(os.path.join(relative_ts_root, workdir, name)) + unique = os.path.normpath(os.path.join(relative_ts_root, workdir, name)).replace(os.sep, '/') return unique @staticmethod diff --git a/scripts/pylib/twister/twisterlib/twister_main.py b/scripts/pylib/twister/twisterlib/twister_main.py index 336c95f36092874..30656544b94faa7 100644 --- a/scripts/pylib/twister/twisterlib/twister_main.py +++ b/scripts/pylib/twister/twisterlib/twister_main.py @@ -131,10 +131,6 @@ def main(options): logger.error(f"{e}") return 1 - if options.list_tests and options.platform: - tplan.report_platform_tests(options.platform) - return 0 - if VERBOSE > 1: # if we are using command line platform filter, no need to list every # other platform as excluded, we know that already. @@ -155,10 +151,6 @@ def main(options): ) ) - if options.report_excluded: - tplan.report_excluded_tests() - return 0 - report = Reporting(tplan, env) plan_file = os.path.join(options.outdir, "testplan.json") if not os.path.exists(plan_file): @@ -207,9 +199,10 @@ def main(options): report.summary(runner.results, options.disable_unrecognized_section_test, duration) + coverage_completed = True if options.coverage: if not options.build_only: - run_coverage(tplan, options) + coverage_completed = run_coverage(tplan, options) else: logger.info("Skipping coverage report generation due to --build-only.") @@ -235,6 +228,7 @@ def main(options): runner.results.failed or runner.results.error or (tplan.warnings and options.warnings_as_errors) + or (options.coverage and not coverage_completed) ): return 1 diff --git a/scripts/requirements-build-test.txt b/scripts/requirements-build-test.txt index 79309a179cdf804..c0f808880fbadc7 100644 --- a/scripts/requirements-build-test.txt +++ b/scripts/requirements-build-test.txt @@ -10,7 +10,7 @@ colorama ply>=3.10 # used for code coverage -gcovr>=4.2 +gcovr>=6.0 coverage # used for west-command testing diff --git a/scripts/requirements-extras.txt b/scripts/requirements-extras.txt index f210f069de9b042..99fa4f16cf4609d 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 96a121767a5b953..454959fc608abdd 100644 --- a/scripts/schemas/twister/testsuite-schema.yaml +++ b/scripts/schemas/twister/testsuite-schema.yaml @@ -8,174 +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 - "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 @@ -199,175 +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 - "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 fb1987cd9b97f0e..17199ec52e60ec3 100755 --- a/scripts/set_assignees.py +++ b/scripts/set_assignees.py @@ -64,88 +64,98 @@ def process_pr(gh, maintainer_file, number): labels = set() area_counter = defaultdict(int) - maint = defaultdict(int) + found_maintainers = defaultdict(int) num_files = 0 all_areas = set() fn = list(pr.get_files()) + + manifest_change = False + for changed_file in fn: + if changed_file.filename in ['west.yml','submanifests/optional.yaml']: + manifest_change = True + break + + # one liner PRs should be trivial + if pr.commits == 1 and (pr.additions <= 1 and pr.deletions <= 1) and not manifest_change: + labels = {'Trivial'} + if len(fn) > 500: log(f"Too many files changed ({len(fn)}), skipping....") return - for f in pr.get_files(): + + for changed_file in fn: num_files += 1 - log(f"file: {f.filename}") - areas = maintainer_file.path2areas(f.filename) - - if areas: - all_areas.update(areas) - for a in areas: - area_counter[a.name] += 1 - labels.update(a.labels) - for p in a.maintainers: - maint[p] += 1 - - ac = dict(sorted(area_counter.items(), key=lambda item: item[1], reverse=True)) - log(f"Area matches: {ac}") + log(f"file: {changed_file.filename}") + areas = maintainer_file.path2areas(changed_file.filename) + + if not areas: + continue + + all_areas.update(areas) + is_instance = False + sorted_areas = sorted(areas, key=lambda x: 'Platform' in x.name, reverse=True) + for area in sorted_areas: + c = 1 if not is_instance else 0 + + area_counter[area] += c + labels.update(area.labels) + # FIXME: Here we count the same file multiple times if it exists in + # multiple areas with same maintainer + for area_maintainer in area.maintainers: + found_maintainers[area_maintainer] += c + + if 'Platform' in area.name: + is_instance = True + + area_counter = dict(sorted(area_counter.items(), key=lambda item: item[1], reverse=True)) + log(f"Area matches: {area_counter}") log(f"labels: {labels}") # Create a list of collaborators ordered by the area match collab = list() - for a in ac: - collab += maintainer_file.areas[a].maintainers - collab += maintainer_file.areas[a].collaborators + for area in area_counter: + collab += maintainer_file.areas[area.name].maintainers + collab += maintainer_file.areas[area.name].collaborators collab = list(dict.fromkeys(collab)) log(f"collab: {collab}") - sm = dict(sorted(maint.items(), key=lambda item: item[1], reverse=True)) + _all_maintainers = dict(sorted(found_maintainers.items(), key=lambda item: item[1], reverse=True)) log(f"Submitted by: {pr.user.login}") - log(f"candidate maintainers: {sm}") - - maintainer = "None" - maintainers = list(sm.keys()) - - prop = 0 - if maintainers: - maintainer = maintainers[0] - - if len(ac) > 1 and list(ac.values())[0] == list(ac.values())[1]: - for aa in ac: - if 'Documentation' in aa: - log("++ With multiple areas of same weight including docs, take something else other than Documentation as the maintainer") - for a in all_areas: - if (a.name == aa and - a.maintainers and a.maintainers[0] == maintainer and - len(maintainers) > 1): - maintainer = maintainers[1] - elif 'Platform' in aa: - log("++ Platform takes precedence over subsystem...") - log(f"Set maintainer of area {aa}") - for a in all_areas: - if a.name == aa: - if a.maintainers: - maintainer = a.maintainers[0] - break - - - # if the submitter is the same as the maintainer, check if we have - # multiple maintainers - if pr.user.login == maintainer: - log("Submitter is same as Assignee, trying to find another assignee...") - aff = list(ac.keys())[0] - for a in all_areas: - if a.name == aff: - if len(a.maintainers) > 1: - maintainer = a.maintainers[1] - else: - log(f"This area has only one maintainer, keeping assignee as {maintainer}") - - prop = (maint[maintainer] / num_files) * 100 - if prop < 20: - maintainer = "None" - - log(f"Picked maintainer: {maintainer} ({prop:.2f}% ownership)") - log("+++++++++++++++++++++++++") + log(f"candidate maintainers: {_all_maintainers}") + + maintainers = list(_all_maintainers.keys()) + assignee = None + + # we start with areas with most files changed and pick the maintainer from the first one. + # if the first area is an implementation, i.e. driver or platform, we + # continue searching for any other areas + for area, count in area_counter.items(): + if count == 0: + continue + if len(area.maintainers) > 0: + assignee = area.maintainers[0] + + if 'Platform' not in area.name: + break + + # if the submitter is the same as the maintainer, check if we have + # multiple maintainers + if len(maintainers) > 1 and pr.user.login == assignee: + log("Submitter is same as Assignee, trying to find another assignee...") + aff = list(area_counter.keys())[0] + for area in all_areas: + if area == aff: + if len(area.maintainers) > 1: + assignee = area.maintainers[1] + else: + log(f"This area has only one maintainer, keeping assignee as {assignee}") + + if assignee: + prop = (found_maintainers[assignee] / num_files) * 100 + log(f"Picked assignee: {assignee} ({prop:.2f}% ownership)") + log("+++++++++++++++++++++++++") # Set labels if labels: @@ -171,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) @@ -197,9 +214,9 @@ def process_pr(gh, maintainer_file, number): ms = [] # assignees - if maintainer != 'None' and not pr.assignee: + if assignee and not pr.assignee: try: - u = gh.get_user(maintainer) + u = gh.get_user(assignee) ms.append(u) except GithubException: log(f"Error: Unknown user") diff --git a/scripts/spelling.txt b/scripts/spelling.txt index fd3c5170303b5d9..ffa9e7cb8e38702 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -9,7 +9,12 @@ # abandonning||abandoning abigious||ambiguous +abitrary||arbitrary abitrate||arbitrate +abnornally||abnormally +abnrormal||abnormal +abord||abort +aboslute||absolute abov||above abreviated||abbreviated absense||absence @@ -17,6 +22,8 @@ absolut||absolute absoulte||absolute acccess||access acceess||access +accelaration||acceleration +accelearion||acceleration acceleratoin||acceleration accelleration||acceleration accesing||accessing @@ -25,6 +32,7 @@ accessable||accessible accesss||access accidentaly||accidentally accidentually||accidentally +acclerated||accelerated accoding||according accomodate||accommodate accomodates||accommodates @@ -34,8 +42,11 @@ accout||account accquire||acquire accquired||acquired accross||across +accumalate||accumulate +accumalator||accumulator acessable||accessible acess||access +acessing||accessing achitecture||architecture acient||ancient acitions||actions @@ -48,24 +59,36 @@ acording||according activete||activate actived||activated actualy||actually +actvie||active acumulating||accumulating +acumulative||accumulative acumulator||accumulator +acutally||actually adapater||adapter +adderted||asserted addional||additional additionaly||additionally +additonal||additional addres||address +adddress||address addreses||addresses addresss||address +addrress||address aditional||additional aditionally||additionally aditionaly||additionally adminstrative||administrative adress||address adresses||addresses +adrresses||addresses +advertisment||advertisement adviced||advised afecting||affecting againt||against agaist||against +aggreataon||aggregation +aggreation||aggregation +ajust||adjust albumns||albums alegorical||allegorical algined||aligned @@ -73,15 +96,19 @@ algorith||algorithm algorithmical||algorithmically algoritm||algorithm algoritms||algorithms +algorithmn||algorithm algorrithm||algorithm algorritm||algorithm aligment||alignment alignement||alignment allign||align alligned||aligned +alllocate||allocate +alloated||allocated allocatote||allocate allocatrd||allocated allocte||allocate +allocted||allocated allpication||application alocate||allocate alogirhtms||algorithms @@ -89,11 +116,17 @@ alogrithm||algorithm alot||a lot alow||allow alows||allows +alreay||already +alredy||already altough||although alue||value ambigious||ambiguous +ambigous||ambiguous amoung||among +amount of times||number of times amout||amount +amplifer||amplifier +amplifyer||amplifier an union||a union an user||a user an userspace||a userspace @@ -122,35 +155,56 @@ aquired||acquired aquisition||acquisition arbitary||arbitrary architechture||architecture +archtecture||architecture arguement||argument arguements||arguments +arithmatic||arithmetic aritmetic||arithmetic arne't||aren't arraival||arrival artifical||artificial artillary||artillery asign||assign +asser||assert assertation||assertion +assertting||asserting +assgined||assigned assiged||assigned assigment||assignment assigments||assignments assistent||assistant +assocaited||associated +assocating||associating assocation||association associcated||associated assotiated||associated +asssert||assert assum||assume assumtpion||assumption asuming||assuming asycronous||asynchronous +asychronous||asynchronous asynchnous||asynchronous +asynchronus||asynchronous +asynchromous||asynchronous +asymetric||asymmetric +asymmeric||asymmetric +atleast||at least atomatically||automatically atomicly||atomically atempt||attempt +atrributes||attributes attachement||attachment +attatch||attach attched||attached +attemp||attempt attemps||attempts +attemping||attempting +attepmpt||attempt +attnetion||attention attruibutes||attributes authentification||authentication +authenicated||authenticated automaticaly||automatically automaticly||automatically automatize||automate @@ -164,10 +218,12 @@ avaible||available availabe||available availabled||available availablity||availability +availaible||available availale||available availavility||availability availble||available availiable||available +availible||available avalable||available avaliable||available aysnc||async @@ -181,6 +237,7 @@ baloons||balloons bandwith||bandwidth banlance||balance batery||battery +battey||battery beacuse||because becasue||because becomming||becoming @@ -192,30 +249,57 @@ beter||better betweeen||between bianries||binaries bitmast||bitmask +bitwiedh||bitwidth boardcast||broadcast borad||board boundry||boundary brievely||briefly +brigde||bridge +broadcase||broadcast broadcat||broadcast +bufer||buffer +bufferred||buffered +bufufer||buffer cacluated||calculated +caculate||calculate caculation||calculation +cadidate||candidate +cahces||caches calender||calendar +calescing||coalescing calle||called callibration||calibration +callled||called +callser||caller calucate||calculate calulate||calculate cancelation||cancellation +cancle||cancel +cant||can't +cant'||can't +canot||cannot +cann't||can't +cannnot||cannot +capabiity||capability capabilites||capabilities +capabilties||capabilities +capabilty||capability capabitilies||capabilities +capablity||capability capatibilities||capabilities +capapbilities||capabilities +caputure||capture carefuly||carefully cariage||carriage +casued||caused catagory||category cehck||check challange||challenge challanges||challenges +chache||cache chanell||channel changable||changeable +chanined||chained channle||channel channnel||channel charachter||character @@ -226,6 +310,7 @@ charaters||characters charcter||character chcek||check chck||check +checksumed||checksummed checksuming||checksumming childern||children childs||children @@ -233,6 +318,7 @@ chiled||child chked||checked chnage||change chnages||changes +chnange||change chnnel||channel choosen||chosen chouse||chose @@ -241,6 +327,9 @@ claread||cleared clared||cleared closeing||closing clustred||clustered +cnfiguration||configuration +coexistance||coexistence +colescing||coalescing collapsable||collapsible colorfull||colorful comand||command @@ -251,14 +340,18 @@ comminucation||communication commited||committed commiting||committing committ||commit +commnunication||communication commoditiy||commodity comsume||consume comsumer||consumer comsuming||consuming +comaptible||compatible compability||compatibility compaibility||compatibility +comparsion||comparison compatability||compatibility compatable||compatible +compatibililty||compatibility compatibiliy||compatibility compatibilty||compatibility compatiblity||compatibility @@ -269,16 +362,29 @@ completition||completion completly||completely complient||compliant componnents||components +compoment||component +comppatible||compatible compres||compress compresion||compression +compresser||compressor comression||compression +comsumed||consumed +comunicate||communicate comunication||communication conbination||combination concurent||concurrent conditionaly||conditionally +conditon||condition +condtion||condition +condtional||conditional conected||connected connecetd||connected +conector||connector +configration||configuration +configred||configured configuartion||configuration +configuation||configuration +configued||configured configuratoin||configuration configuraton||configuration configuretion||configuration @@ -286,6 +392,7 @@ configutation||configuration conider||consider conjuction||conjunction connectinos||connections +connetor||connector connnection||connection connnections||connections consistancy||consistency @@ -295,10 +402,13 @@ containts||contains contaisn||contains contant||contact contence||contents +contiguos||contiguous +continious||continuous continous||continuous continously||continuously continueing||continuing contraints||constraints +contruct||construct contol||control contoller||controller controled||controlled @@ -316,22 +426,35 @@ correponding||corresponding correponds||corresponds correspoding||corresponding cotrol||control +cound||could couter||counter coutner||counter +creationg||creating cryptocraphic||cryptographic +cummulative||cumulative cunter||counter curent||current curently||currently cylic||cyclic dafault||default +deactive||deactivate deafult||default deamon||daemon +debouce||debounce +decendant||descendant +decendants||descendants decompres||decompress +decsribed||described decription||description +dectected||detected defailt||default +deferal||deferral +deffered||deferred defferred||deferred definate||definite definately||definitely +definiation||definition +definiton||definition defintion||definition defintions||definitions defualt||default @@ -345,25 +468,38 @@ delare||declare delares||declares delaring||declaring delemiter||delimiter +delibrately||deliberately +delievered||delivered +demodualtor||demodulator +demension||dimension dependancies||dependencies dependancy||dependency dependant||dependent +dependend||dependent depreacted||deprecated depreacte||deprecate desactivate||deactivate desciptor||descriptor desciptors||descriptors +descripto||descriptor descripton||description descrition||description descritptor||descriptor desctiptor||descriptor desriptor||descriptor desriptors||descriptors +desination||destination +destionation||destination +destoried||destroyed destory||destroy destoryed||destroyed destorys||destroys destroied||destroyed detabase||database +deteced||detected +detecion||detection +detectt||detect +detroyed||destroyed develope||develop developement||development developped||developed @@ -373,43 +509,77 @@ developpment||development deveolpment||development devided||divided deviece||device +devision||division diable||disable +diabled||disabled +dicline||decline dictionnary||dictionary didnt||didn't diferent||different differrence||difference diffrent||different +differenciate||differentiate +diffreential||differential diffrentiate||differentiate difinition||definition +digial||digital +dimention||dimension +dimesions||dimensions +diconnected||disconnected +disabed||disabled +disasembler||disassembler +disgest||digest +disired||desired +dispalying||displaying +dissable||disable diplay||display +directon||direction +direcly||directly direectly||directly +diregard||disregard disassocation||disassociation disapear||disappear disapeared||disappeared disappared||disappeared +disbale||disable +disbaled||disabled disble||disable disbled||disabled disconnet||disconnect discontinous||discontinuous +disharge||discharge +disnabled||disabled dispertion||dispersion dissapears||disappears +dissconect||disconnect distiction||distinction +divisable||divisible +divsiors||divisors +dsiabled||disabled docuentation||documentation documantation||documentation documentaion||documentation documment||document doesnt||doesn't +donwload||download +donwloading||downloading dorp||drop dosen||doesn downlad||download downlads||downloads +droped||dropped +droput||dropout druing||during +dyanmic||dynamic dynmaic||dynamic +eanable||enable +eanble||enable easilly||easily ecspecially||especially edditable||editable editting||editing efective||effective +effectivness||effectiveness efficently||efficiently ehther||ether eigth||eight @@ -417,14 +587,23 @@ elementry||elementary eletronic||electronic embeded||embedded enabledi||enabled +enbale||enable +enble||enable enchanced||enhanced encorporating||incorporating encrupted||encrypted encrypiton||encryption +encryptio||encryption endianess||endianness +enpoint||endpoint enhaced||enhanced enlightnment||enlightenment +enqueing||enqueuing +entires||entries +entites||entities +entrys||entries enocded||encoded +enought||enough enterily||entirely enviroiment||environment enviroment||environment @@ -435,19 +614,37 @@ equiped||equipped equivelant||equivalent equivilant||equivalent eror||error +errorr||error +errror||error estbalishment||establishment etsablishment||establishment etsbalishment||establishment +evalute||evaluate +evalutes||evaluates +evalution||evaluation excecutable||executable +excceed||exceed exceded||exceeded +exceds||exceeds +exceeed||exceed excellant||excellent +exchnage||exchange +execeeded||exceeded +execeeds||exceeds +exeed||exceed +exeeds||exceeds +exeuction||execution existance||existence existant||existent exixt||exist +exsits||exists exlcude||exclude +exlcuding||excluding exlcusive||exclusive +exlusive||exclusive exmaple||example expecially||especially +experies||expires explicite||explicit explicitely||explicitly explict||explicit @@ -456,47 +653,69 @@ explictly||explicitly expresion||expression exprimental||experimental extened||extended +exteneded||extended extensability||extensibility extention||extension +extenstion||extension extracter||extractor -falied||failed +faied||failed +faield||failed faild||failed +failded||failed +failer||failure faill||fail failied||failed faillure||failure failue||failure failuer||failure +failng||failing faireness||fairness falied||failed faliure||failure +fallbck||fallback familar||familiar fatser||faster feauture||feature feautures||features fetaure||feature fetaures||features +fetcing||fetching fileystem||filesystem +fimrware||firmware fimware||firmware +firmare||firmware +firmaware||firmware +firtly||firstly +firware||firmware +firwmare||firmware finanize||finalize findn||find finilizes||finalizes finsih||finish +fliter||filter flusing||flushing folloing||following followign||following followings||following follwing||following +fonud||found forseeable||foreseeable forse||force fortan||fortran forwardig||forwarding +frambuffer||framebuffer framming||framing framwork||framework +frequence||frequency frequncy||frequency +frequancy||frequency frome||from +fronend||frontend fucntion||function fuction||function fuctions||functions +fullill||fulfill +funcation||function funcion||function functionallity||functionality functionaly||functionally @@ -507,41 +726,64 @@ funtions||functions furthur||further futhermore||furthermore futrue||future +gatable||gateable +gateing||gating +gauage||gauge gaurenteed||guaranteed generiously||generously genereate||generate +genereted||generated genric||generic +gerenal||general +geting||getting globel||global grabing||grabbing grahical||graphical grahpical||graphical +granularty||granularity grapic||graphic +grranted||granted guage||gauge guarenteed||guaranteed guarentee||guarantee halfs||halves hander||handler handfull||handful +hanlde||handle hanled||handled happend||happened +hardare||hardware harware||hardware +hardward||hardware +havind||having heirarchically||hierarchically +heirarchy||hierarchy helpfull||helpful +hearbeat||heartbeat +heterogenous||heterogeneous +hexdecimal||hexadecimal +hybernate||hibernate hierachy||hierarchy hierarchie||hierarchy +homogenous||homogeneous howver||however hsould||should hypervior||hypervisor hypter||hyper +idel||idle identidier||identifier iligal||illegal illigal||illegal +illgal||illegal +iomaped||iomapped imblance||imbalance immeadiately||immediately immedaite||immediate +immedate||immediate immediatelly||immediately immediatly||immediately immidiate||immediate +immutible||immutable impelentation||implementation impementated||implemented implemantation||implementation @@ -549,24 +791,34 @@ implemenation||implementation implementaiton||implementation implementated||implemented implemention||implementation +implementd||implemented implemetation||implementation implemntation||implementation implentation||implementation implmentation||implementation implmenting||implementing +incative||inactive incomming||incoming +incompaitiblity||incompatibility incompatabilities||incompatibilities incompatable||incompatible +incompatble||incompatible inconsistant||inconsistent increas||increase +incremeted||incremented incrment||increment +incuding||including +inculde||include indendation||indentation indended||intended independant||independent independantly||independently independed||independent indiate||indicate +indicat||indicate inexpect||inexpected +inferface||interface +infinit||infinite infomation||information informatiom||information informations||information @@ -581,27 +833,41 @@ initalize||initialize initation||initiation initators||initiators initialiazation||initialization +initializationg||initialization initializiation||initialization +initialze||initialize initialzed||initialized +initialzing||initializing initilization||initialization initilize||initialize +initliaze||initialize +initilized||initialized inofficial||unofficial +inrerface||interface insititute||institute +instace||instance instal||install +instanciate||instantiate instanciated||instantiated +instuments||instruments +insufficent||insufficient inteface||interface integreated||integrated integrety||integrity integrey||integrity intendet||intended intented||intended +interal||internal interanl||internal interchangable||interchangeable interferring||interfering interger||integer +intergrated||integrated intermittant||intermittent internel||internal interoprability||interoperability +interuupt||interrupt +interupts||interrupts interrface||interface interrrupt||interrupt interrup||interrupt @@ -609,6 +875,7 @@ interrups||interrupts interruptted||interrupted interupted||interrupted interupt||interrupt +intiailized||initialized intial||initial intialisation||initialisation intialised||initialised @@ -617,24 +884,35 @@ intialization||initialization intialized||initialized intialize||initialize intregral||integral +intrerrupt||interrupt intrrupt||interrupt intterrupt||interrupt intuative||intuitive +inavlid||invalid invaid||invalid +invaild||invalid +invailid||invalid +invald||invalid invalde||invalid invalide||invalid +invalidiate||invalidate invalud||invalid invididual||individual invokation||invocation invokations||invocations +ireelevant||irrelevant irrelevent||irrelevant isnt||isn't isssue||issue +issus||issues +iteraions||iterations iternations||iterations itertation||iteration itslef||itself +ivalid||invalid jave||java jeffies||jiffies +jumpimng||jumping juse||just jus||just kown||known @@ -644,6 +922,7 @@ langauge||language langugage||language lauch||launch layed||laid +legnth||length leightweight||lightweight lengh||length lenght||length @@ -654,40 +933,66 @@ libary||library librairies||libraries libraris||libraries licenceing||licencing +limted||limited +logaritmic||logarithmic loggging||logging loggin||login logile||logfile +loobpack||loopback loosing||losing losted||lost +maangement||management machinary||machinery +maibox||mailbox maintainance||maintenance maintainence||maintenance maintan||maintain makeing||making +mailformed||malformed malplaced||misplaced malplace||misplace managable||manageable +managament||management managment||management mangement||management +manger||manager manoeuvering||maneuvering +manufaucturing||manufacturing mappping||mapping +maping||mapping +matchs||matches mathimatical||mathematical mathimatic||mathematic mathimatics||mathematics +maxmium||maximum +maximium||maximum maxium||maximum mechamism||mechanism +mechanim||mechanism meetign||meeting +memeory||memory +memmber||member +memoery||memory +memroy||memory ment||meant mergable||mergeable mesage||message +mesages||messages messags||messages messgaes||messages messsage||message messsages||messages +metdata||metadata +micropone||microphone microprocesspr||microprocessor +migrateable||migratable +millenium||millennium milliseonds||milliseconds +minimim||minimum minium||minimum minimam||minimum +minimun||minimum +miniumum||minimum minumum||minimum misalinged||misaligned miscelleneous||miscellaneous @@ -695,21 +1000,35 @@ misformed||malformed mispelled||misspelled mispelt||misspelt mising||missing +mismactch||mismatch +missign||missing +missmanaged||mismanaged +missmatch||mismatch +misssing||missing miximum||maximum mmnemonic||mnemonic mnay||many +modfiy||modify +modifer||modifier +modul||module modulues||modules momery||memory +memomry||memory +monitring||monitoring monochorome||monochrome monochromo||monochrome monocrome||monochrome mopdule||module mroe||more mulitplied||multiplied +muliple||multiple +multipler||multiplier multidimensionnal||multidimensional +multipe||multiple multple||multiple mumber||number muticast||multicast +mutilcast||multicast mutiple||multiple mutli||multi nams||names @@ -726,45 +1045,67 @@ negotation||negotiation nerver||never nescessary||necessary nessessary||necessary +none existent||non-existent noticable||noticeable +notication||notification notications||notifications +notifcations||notifications notifed||notified +notity||notify +nubmer||number numebr||number +numer||number numner||number +nunber||number obtaion||obtain +obusing||abusing occassionally||occasionally occationally||occasionally occurance||occurrence occurances||occurrences -occured||occurred +occurd||occurred occurence||occurrence occure||occurred occured||occurred occuring||occurring +ocurrence||occurrence +offser||offset offet||offset +offlaod||offload +offloded||offloaded +offseting||offsetting +oflload||offload omited||omitted omiting||omitting omitt||omit ommiting||omitting ommitted||omitted onself||oneself +onthe||on the ony||only +openning||opening operatione||operation opertaions||operations +opportunies||opportunities optionnal||optional optmizations||optimizations orientatied||orientated orientied||oriented orignal||original +originial||original otherise||otherwise ouput||output oustanding||outstanding overaall||overall overhread||overhead overlaping||overlapping +oveflow||overflow +overflw||overflow +overlfow||overflow overide||override overrided||overridden overriden||overridden +overrrun||overrun overun||overrun overwritting||overwriting overwriten||overwritten @@ -775,8 +1116,10 @@ packege||package packge||package packtes||packets pakage||package +paket||packet pallette||palette paln||plan +palne||plane paramameters||parameters paramaters||parameters paramater||parameter @@ -784,22 +1127,36 @@ parametes||parameters parametised||parametrised paramter||parameter paramters||parameters +parmaters||parameters particuarly||particularly particularily||particularly +partion||partition +partions||partitions partiton||partition pased||passed passin||passing pathes||paths +pattrns||patterns pecularities||peculiarities peformance||performance +peforming||performing peice||piece pendantic||pedantic peprocessor||preprocessor +perfomance||performance perfoming||performing +perfomring||performing +periperal||peripheral +peripherial||peripheral permissons||permissions +permited||permitted peroid||period persistance||persistence persistant||persistent +phoneticly||phonetically +plaform||platform +plalform||platform +platfoem||platform platfrom||platform plattform||platform pleaes||please @@ -811,7 +1168,12 @@ poiter||pointer posible||possible positon||position possibilites||possibilities +potocol||protocol powerfull||powerful +pramater||parameter +preamle||preamble +preample||preamble +preapre||prepare preceeded||preceded preceeding||preceding preceed||precede @@ -820,17 +1182,28 @@ precission||precision preemptable||preemptible prefered||preferred prefferably||preferably +prefitler||prefilter +preform||perform premption||preemption prepaired||prepared +prepate||prepare +preperation||preparation +preprare||prepare pressre||pressure +presuambly||presumably +previosuly||previously +previsously||previously primative||primitive princliple||principle priorty||priority +priting||printing privilaged||privileged privilage||privilege priviledge||privilege priviledges||privileges +privleges||privileges probaly||probably +probabalistic||probabilistic procceed||proceed proccesors||processors procesed||processed @@ -843,12 +1216,17 @@ processsed||processed processsing||processing procteted||protected prodecure||procedure +progamming||programming progams||programs progess||progress +programable||programmable programers||programmers programm||program programms||programs +progres||progress progresss||progress +prohibitted||prohibited +prohibitting||prohibiting promiscous||promiscuous promps||prompts pronnounced||pronounced @@ -858,34 +1236,45 @@ pronunce||pronounce propery||property propigate||propagate propigation||propagation +propogation||propagation propogate||propagate prosess||process protable||portable protcol||protocol protecion||protection +protedcted||protected protocoll||protocol promixity||proximity psudo||pseudo psuedo||pseudo psychadelic||psychedelic +purgable||purgeable pwoer||power +queing||queuing quering||querying +queus||queues +randomally||randomly raoming||roaming reasearcher||researcher reasearchers||researchers reasearch||research +receieve||receive recepient||recipient +recevied||received receving||receiving +recievd||received recieved||received recieve||receive reciever||receiver recieves||receives +recieving||receiving recogniced||recognised recognizeable||recognizable recommanded||recommended recyle||recycle redircet||redirect redirectrion||redirection +redundacy||redundancy reename||rename refcounf||refcount refence||reference @@ -895,8 +1284,12 @@ refering||referring refernces||references refernnce||reference refrence||reference +regiser||register +registed||registered registerd||registered +registeration||registration registeresd||registered +registerred||registered registes||registers registraration||registration regsiter||register @@ -907,6 +1300,7 @@ regulamentations||regulations reigstration||registration releated||related relevent||relevant +reloade||reload remoote||remote remore||remote removeable||removable @@ -917,29 +1311,45 @@ replys||replies reponse||response representaion||representation reqeust||request +reqister||register +requed||requeued requestied||requested requiere||require requirment||requirement requred||required requried||required requst||request +requsted||requested +reregisteration||reregistration reseting||resetting +reseved||reserved +reseverd||reserved resizeable||resizable +resotre||restore +resouce||resource resouces||resources resoures||resources responce||response +resrouce||resource ressizes||resizes ressource||resource ressources||resources +restesting||retesting +resumbmitting||resubmitting retransmited||retransmitted retreived||retrieved retreive||retrieve +retreiving||retrieving retrive||retrieve +retrived||retrieved +retrun||return +retun||return retuned||returned reudce||reduce reuest||request reuqest||request reutnred||returned +revsion||revision rmeoved||removed rmeove||remove rmeoves||removes @@ -948,20 +1358,29 @@ routins||routines rquest||request runing||running runned||ran +runnnig||running runnning||running runtine||runtime sacrifying||sacrificing safly||safely safty||safety +satify||satisfy +satisifed||satisfied savable||saveable +scaleing||scaling scaned||scanned scaning||scanning scarch||search +schdule||schedule seach||search searchs||searches +secion||section secquence||sequence secund||second segement||segment +seleted||selected +semaphone||semaphore +senario||scenario senarios||scenarios sentivite||sensitive separatly||separately @@ -973,11 +1392,19 @@ seperate||separate seperatly||separately seperator||separator sepperate||separate +seqeunce||sequence +seqeuncer||sequencer +seqeuencer||sequencer sequece||sequence +sequemce||sequence sequencial||sequential +serivce||service serveral||several +servive||service setts||sets settting||setting +shapshot||snapshot +shoft||shift shotdown||shutdown shoud||should shouldnt||shouldn't @@ -985,24 +1412,35 @@ shoule||should shrinked||shrunk siginificantly||significantly signabl||signal +significanly||significantly similary||similarly similiar||similar simlar||similar simliar||similar simpified||simplified +simultaneusly||simultaneously +simultanous||simultaneous singaled||signaled singal||signal singed||signed +slect||select sleeped||slept +sliped||slipped +softwade||software softwares||software +soley||solely +souce||source speach||speech specfic||specific +specfield||specified speciefied||specified specifc||specific specifed||specified specificatin||specification specificaton||specification +specificed||specified specifing||specifying +specifiy||specify specifiying||specifying speficied||specified speicify||specify @@ -1019,8 +1457,12 @@ staion||station standardss||standards standartization||standardization standart||standard +standy||standby +stardard||standard staticly||statically +statuss||status stoped||stopped +stoping||stopping stoppped||stopped straming||streaming struc||struct @@ -1032,12 +1474,18 @@ sturcture||structure subdirectoires||subdirectories suble||subtle substract||subtract +submited||submitted +submition||submission +succeded||succeeded +suceed||succeed +succesfuly||successfully succesfully||successfully succesful||successful successed||succeeded successfull||successful successfuly||successfully sucessfully||successfully +sucessful||successful sucess||success superflous||superfluous superseeded||superseded @@ -1046,14 +1494,18 @@ suported||supported suport||support supportet||supported suppored||supported +supporing||supporting supportin||supporting suppoted||supported suppported||supported suppport||support +supprot||support supress||suppress +surpressed||suppressed surpresses||suppresses susbsystem||subsystem suspeneded||suspended +suspsend||suspend suspicously||suspiciously swaping||swapping switchs||switches @@ -1064,9 +1516,14 @@ swithced||switched swithcing||switching swithed||switched swithing||switching +swtich||switch +syfs||sysfs symetric||symmetric synax||syntax synchonized||synchronized +sychronization||synchronization +sychronously||synchronously +synchronuously||synchronously syncronize||synchronize syncronized||synchronized syncronizing||synchronizing @@ -1075,42 +1532,78 @@ syste||system sytem||system sythesis||synthesis taht||that +tained||tainted +tarffic||traffic +tansmit||transmit targetted||targeted targetting||targeting +taskelt||tasklet teh||the +temeprature||temperature temorary||temporary temproarily||temporarily +temperture||temperature +the the||the +theads||threads therfore||therefore thier||their threds||threads +threee||three threshhold||threshold +thresold||threshold throught||through +tansition||transition +trackling||tracking +troughput||throughput +trys||tries thses||these +tiggers||triggers tiggered||triggered tipically||typically +timeing||timing timout||timeout tmis||this +toogle||toggle torerable||tolerable +torlence||tolerance +traget||target +traking||tracking tramsmitted||transmitted tramsmit||transmit +tranasction||transaction +tranceiver||transceiver tranfer||transfer +tranmission||transmission +transcevier||transceiver transciever||transceiver transferd||transferred transfered||transferred transfering||transferring transision||transition +transistioned||transitioned transmittd||transmitted transormed||transformed +trasfer||transfer trasmission||transmission treshold||threshold +triggerd||triggered +trigerred||triggered trigerring||triggering trun||turn +tunning||tuning ture||true tyep||type udpate||update +updtes||updates uesd||used +unknwon||unknown +uknown||unknown +usccess||success uncommited||uncommitted +uncompatible||incompatible unconditionaly||unconditionally +undeflow||underflow +undelying||underlying underun||underrun unecessary||unnecessary unexecpted||unexpected @@ -1121,31 +1614,52 @@ unexpeted||unexpected unexpexted||unexpected unfortunatelly||unfortunately unifiy||unify +uniterrupted||uninterrupted +uninterruptable||uninterruptible unintialized||uninitialized +unitialized||uninitialized unkmown||unknown unknonw||unknown +unknouwn||unknown unknow||unknown unkown||unknown +unamed||unnamed +uneeded||unneeded unneded||unneeded +unneccecary||unnecessary +unneccesary||unnecessary +unneccessary||unnecessary +unnecesary||unnecessary unneedingly||unnecessarily unnsupported||unsupported +unuspported||unsupported unmached||unmatched +unprecise||imprecise +unpriviledged||unprivileged +unpriviliged||unprivileged unregester||unregister unresgister||unregister unrgesiter||unregister unsinged||unsigned unstabel||unstable +unsolicted||unsolicited unsolicitied||unsolicited unsuccessfull||unsuccessful unsuported||unsupported untill||until +ununsed||unused unuseful||useless +unvalid||invalid upate||update +upsupported||unsupported +upto||up to +useable||usable usefule||useful usefull||useful usege||usage usera||users usualy||usually +usupported||unsupported utilites||utilities utillities||utilities utilties||utilities @@ -1160,8 +1674,12 @@ varible||variable varient||variant vaule||value verbse||verbose +veify||verify +verfication||verification +veriosn||version verisons||versions verison||version +veritical||vertical verson||version vicefersa||vice-versa virtal||virtual @@ -1169,7 +1687,12 @@ virtaul||virtual virtiual||virtual visiters||visitors vitual||virtual +vunerable||vulnerable +wakeus||wakeups +was't||wasn't +wathdog||watchdog wating||waiting +wiat||wait wether||whether whataver||whatever whcih||which @@ -1177,12 +1700,15 @@ whenver||whenever wheter||whether whe||when wierd||weird +wihout||without wiil||will wirte||write withing||within wnat||want +wont||won't workarould||workaround writeing||writing writting||writing +wtih||with zombe||zombie zomebie||zombie diff --git a/scripts/tests/twister/pytest_integration/test_harness_pytest.py b/scripts/tests/twister/pytest_integration/test_harness_pytest.py index e1b27a0cf0264c0..befd384be37b144 100644 --- a/scripts/tests/twister/pytest_integration/test_harness_pytest.py +++ b/scripts/tests/twister/pytest_integration/test_harness_pytest.py @@ -25,6 +25,7 @@ def testinstance() -> TestInstance: testinstance.handler = mock.Mock() testinstance.handler.options = mock.Mock() testinstance.handler.options.verbose = 1 + testinstance.handler.options.pytest_args = None testinstance.handler.type_str = 'native' return testinstance @@ -48,6 +49,38 @@ def test_pytest_command(testinstance: TestInstance, device_type): assert c in command +def test_pytest_command_dut_scope(testinstance: TestInstance): + pytest_harness = Pytest() + dut_scope = 'session' + testinstance.testsuite.harness_config['pytest_dut_scope'] = dut_scope + pytest_harness.configure(testinstance) + command = pytest_harness.generate_command() + assert f'--dut-scope={dut_scope}' in command + + +def test_pytest_command_extra_args(testinstance: TestInstance): + pytest_harness = Pytest() + pytest_args = ['-k test1', '-m mark1'] + testinstance.testsuite.harness_config['pytest_args'] = pytest_args + pytest_harness.configure(testinstance) + command = pytest_harness.generate_command() + for c in pytest_args: + assert c in command + + +def test_pytest_command_extra_args_in_options(testinstance: TestInstance): + pytest_harness = Pytest() + pytest_args_from_yaml = '-k test_from_yaml' + pytest_args_from_cmd = ['-k', 'test_from_cmd'] + testinstance.testsuite.harness_config['pytest_args'] = [pytest_args_from_yaml] + testinstance.handler.options.pytest_args = pytest_args_from_cmd + pytest_harness.configure(testinstance) + command = pytest_harness.generate_command() + assert pytest_args_from_cmd[0] in command + assert pytest_args_from_cmd[1] in command + assert pytest_args_from_yaml not in command + + @pytest.mark.parametrize( ('pytest_root', 'expected'), [ @@ -169,6 +202,8 @@ def test_err(): assert tc.status == "failed" assert tc.output assert tc.reason + assert testinstance.reason + assert '2/2' in testinstance.reason def test_if_report_with_skip(pytester, testinstance: TestInstance): @@ -201,3 +236,56 @@ def test_skip_2(): assert len(testinstance.testcases) == 2 for tc in testinstance.testcases: assert tc.status == "skipped" + + +def test_if_report_with_filter(pytester, testinstance: TestInstance): + test_file_content = textwrap.dedent(""" + import pytest + def test_A(): + pass + def test_B(): + pass + """) + test_file = pytester.path / 'test_filter.py' + test_file.write_text(test_file_content) + report_file = pytester.path / 'report.xml' + result = pytester.runpytest( + str(test_file), + '-k', 'test_B', + f'--junit-xml={str(report_file)}' + ) + result.assert_outcomes(passed=1) + assert report_file.is_file() + + pytest_harness = Pytest() + pytest_harness.configure(testinstance) + pytest_harness.report_file = report_file + pytest_harness._update_test_status() + assert pytest_harness.state == "passed" + assert testinstance.status == "passed" + assert len(testinstance.testcases) == 1 + + +def test_if_report_with_no_collected(pytester, testinstance: TestInstance): + test_file_content = textwrap.dedent(""" + import pytest + def test_A(): + pass + """) + test_file = pytester.path / 'test_filter.py' + test_file.write_text(test_file_content) + report_file = pytester.path / 'report.xml' + result = pytester.runpytest( + str(test_file), + '-k', 'test_B', + f'--junit-xml={str(report_file)}' + ) + result.assert_outcomes(passed=0) + assert report_file.is_file() + + pytest_harness = Pytest() + pytest_harness.configure(testinstance) + pytest_harness.report_file = report_file + pytest_harness._update_test_status() + assert pytest_harness.state == "skipped" + assert testinstance.status == "skipped" diff --git a/scripts/tests/twister/test_errors.py b/scripts/tests/twister/test_errors.py new file mode 100644 index 000000000000000..426258f4cb8f023 --- /dev/null +++ b/scripts/tests/twister/test_errors.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Tests for the error classes +""" + +import os +import pytest + +from pathlib import Path +from twisterlib.error import ConfigurationError + +def test_configurationerror(): + cfile = Path('some') / 'path' + message = 'dummy message' + + expected_err = f'{os.path.join("some", "path")}: dummy message' + + with pytest.raises(ConfigurationError, match=expected_err): + raise ConfigurationError(cfile, message) diff --git a/scripts/tests/twister/test_handlers.py b/scripts/tests/twister/test_handlers.py index 6675c4ae4511e12..d2e4b367a79471e 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_hardwaremap.py b/scripts/tests/twister/test_hardwaremap.py new file mode 100644 index 000000000000000..57c028bfea69afc --- /dev/null +++ b/scripts/tests/twister/test_hardwaremap.py @@ -0,0 +1,722 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Tests for hardwaremap.py classes' methods +""" + +import mock +import pytest +import sys + +from pathlib import Path + +from twisterlib.hardwaremap import( + DUT, + HardwareMap +) + + +@pytest.fixture +def mocked_hm(): + duts = [ + DUT(platform='p1', id=1, serial='s1', product='pr1', connected=True), + DUT(platform='p2', id=2, serial='s2', product='pr2', connected=False), + DUT(platform='p3', id=3, serial='s3', product='pr3', connected=True), + DUT(platform='p4', id=4, serial='s4', product='pr4', connected=False), + DUT(platform='p5', id=5, serial='s5', product='pr5', connected=True), + DUT(platform='p6', id=6, serial='s6', product='pr6', connected=False), + DUT(platform='p7', id=7, serial='s7', product='pr7', connected=True), + DUT(platform='p8', id=8, serial='s8', product='pr8', connected=False) + ] + + hm = HardwareMap(env=mock.Mock()) + hm.duts = duts + hm.detected = duts[:5] + + return hm + + +TESTDATA_1 = [ + ( + {}, + {'baud': 115200, 'lock': mock.ANY, 'flash_timeout': 60}, + '' + ), + ( + { + 'id': 'dummy id', + 'serial': 'dummy serial', + 'serial_baud': 4400, + 'platform': 'dummy platform', + 'product': 'dummy product', + 'serial_pty': 'dummy serial pty', + 'connected': True, + 'runner_params': ['dummy', 'runner', 'params'], + 'pre_script': 'dummy pre script', + 'post_script': 'dummy post script', + 'post_flash_script': 'dummy post flash script', + 'runner': 'dummy runner', + 'flash_timeout': 30, + 'flash_with_test': True + }, + { + 'lock': mock.ANY, + 'id': 'dummy id', + 'serial': 'dummy serial', + 'baud': 4400, + 'platform': 'dummy platform', + 'product': 'dummy product', + 'serial_pty': 'dummy serial pty', + 'connected': True, + 'runner_params': ['dummy', 'runner', 'params'], + 'pre_script': 'dummy pre script', + 'post_script': 'dummy post script', + 'post_flash_script': 'dummy post flash script', + 'runner': 'dummy runner', + 'flash_timeout': 30, + 'flash_with_test': True + }, + '' + ), +] + + +@pytest.mark.parametrize( + 'kwargs, expected_dict, expected_repr', + TESTDATA_1, + ids=['no information', 'full information'] +) +def test_dut(kwargs, expected_dict, expected_repr): + d = DUT(**kwargs) + + assert d.available + assert d.counter == 0 + + d.available = False + d.counter = 1 + + assert not d.available + assert d.counter == 1 + + assert d.to_dict() == expected_dict + assert d.__repr__() == expected_repr + + +TESTDATA_2 = [ + ('ghm.yaml', mock.ANY, mock.ANY, [], mock.ANY, mock.ANY, mock.ANY, 0, + True, True, False, False, False, False, []), + (None, False, 'hm.yaml', [], mock.ANY, mock.ANY, mock.ANY, 0, + False, False, True, True, False, False, []), + (None, True, 'hm.yaml', [], mock.ANY, mock.ANY, ['fix'], 1, + False, False, True, False, False, True, ['p1', 'p3', 'p5', 'p7']), + (None, True, 'hm.yaml', ['pX'], mock.ANY, mock.ANY, ['fix'], 1, + False, False, True, False, False, True, ['pX']), + (None, True, None, ['p'], 's', None, ['fix'], 1, + False, False, False, False, True, True, ['p']), + (None, True, None, ['p'], None, 'spty', ['fix'], 1, + False, False, False, False, True, True, ['p']), +] + + +@pytest.mark.parametrize( + 'generate_hardware_map, device_testing, hardware_map, platform,' \ + ' device_serial, device_serial_pty, fixtures,' \ + ' return_code, expect_scan, expect_save, expect_load,' \ + ' expect_dump, expect_add_device, expect_fixtures, expected_platforms', + TESTDATA_2, + ids=['generate hardware map', 'existing hardware map', + 'device testing with hardware map, no platform', + 'device testing with hardware map with platform', + 'device testing with device serial', + 'device testing with device serial pty'] +) +def test_hardwaremap_discover( + caplog, + mocked_hm, + generate_hardware_map, + device_testing, + hardware_map, + platform, + device_serial, + device_serial_pty, + fixtures, + return_code, + expect_scan, + expect_save, + expect_load, + expect_dump, + expect_add_device, + expect_fixtures, + expected_platforms +): + def mock_load(*args): + mocked_hm.platform = platform + + mocked_hm.scan = mock.Mock() + mocked_hm.save = mock.Mock() + mocked_hm.load = mock.Mock(side_effect=mock_load) + mocked_hm.dump = mock.Mock() + mocked_hm.add_device = mock.Mock() + + mocked_hm.options.device_flash_with_test = True + mocked_hm.options.device_flash_timeout = 15 + mocked_hm.options.pre_script = 'dummy pre script' + mocked_hm.options.platform = platform + mocked_hm.options.device_serial = device_serial + mocked_hm.options.device_serial_pty = device_serial_pty + mocked_hm.options.device_testing = device_testing + mocked_hm.options.hardware_map = hardware_map + mocked_hm.options.persistent_hardware_map = mock.Mock() + mocked_hm.options.generate_hardware_map = generate_hardware_map + mocked_hm.options.fixture = fixtures + + returncode = mocked_hm.discover() + + assert returncode == return_code + + if expect_scan: + mocked_hm.scan.assert_called_once_with( + persistent=mocked_hm.options.persistent_hardware_map + ) + if expect_save: + mocked_hm.save.assert_called_once_with( + mocked_hm.options.generate_hardware_map + ) + if expect_load: + mocked_hm.load.assert_called_once_with( + mocked_hm.options.hardware_map + ) + if expect_dump: + mocked_hm.dump.assert_called_once_with( + connected_only=True + ) + if expect_add_device: + mocked_hm.add_device.assert_called_once() + + if expect_fixtures: + assert all( + [all( + [fixture in dut.fixtures for fixture in fixtures] + ) for dut in mocked_hm.duts] + ) + + assert sorted(expected_platforms) == sorted(mocked_hm.options.platform) + + +def test_hardwaremap_summary(capfd, mocked_hm): + selected_platforms = ['p0', 'p1', 'p6', 'p7'] + + mocked_hm.summary(selected_platforms) + + expected = """ +Hardware distribution summary: + +| Board | ID | Counter | +|---------|------|-----------| +| p1 | 1 | 0 | +| p7 | 7 | 0 | +""" + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert expected in out + + +TESTDATA_3 = [ + (True), + (False) +] + + +@pytest.mark.parametrize( + 'is_pty', + TESTDATA_3, + ids=['pty', 'not pty'] +) +def test_hardwaremap_add_device(is_pty): + hm = HardwareMap(env=mock.Mock()) + + serial = 'dummy' + platform = 'p0' + pre_script = 'dummy pre script' + hm.add_device(serial, platform, pre_script, is_pty) + + assert len(hm.duts) == 1 + if is_pty: + assert hm.duts[0].serial_pty == 'dummy' if is_pty else None + assert hm.duts[0].serial is None + else: + assert hm.duts[0].serial_pty is None + assert hm.duts[0].serial == 'dummy' + + +def test_hardwaremap_load(): + map_file = \ +""" +- id: id0 + platform: p0 + product: pr0 + runner: r0 + flash_with_test: True + flash_timeout: 15 + baud: 14400 + fixtures: + - dummy fixture 1 + - dummy fixture 2 + connected: True + serial: 'dummy' +- id: id1 + platform: p1 + product: pr1 + runner: r1 + connected: True + serial_pty: 'dummy' +- id: id2 + platform: p2 + product: pr2 + runner: r2 + connected: True +""" + map_filename = 'map-file.yaml' + + builtin_open = open + + def mock_open(*args, **kwargs): + if args[0] == map_filename: + return mock.mock_open(read_data=map_file)(*args, **kwargs) + return builtin_open(*args, **kwargs) + + hm = HardwareMap(env=mock.Mock()) + hm.options.device_flash_timeout = 30 + hm.options.device_flash_with_test = False + + with mock.patch('builtins.open', mock_open): + hm.load(map_filename) + + expected = { + 'id0': { + 'platform': 'p0', + 'product': 'pr0', + 'runner': 'r0', + 'flash_timeout': 15, + 'flash_with_test': True, + 'baud': 14400, + 'fixtures': ['dummy fixture 1', 'dummy fixture 2'], + 'connected': True, + 'serial': 'dummy', + 'serial_pty': None, + }, + 'id1': { + 'platform': 'p1', + 'product': 'pr1', + 'runner': 'r1', + 'flash_timeout': 30, + 'flash_with_test': False, + 'baud': 115200, + 'fixtures': [], + 'connected': True, + 'serial': None, + 'serial_pty': 'dummy', + }, + } + + for dut in hm.duts: + assert dut.id in expected + assert all([getattr(dut, k) == v for k, v in expected[dut.id].items()]) + + +TESTDATA_4 = [ + ( + True, + 'Linux', + ['', '', '', + '', '', + '', + '', + ''] + ), + ( + True, + 'nt', + ['', '', '', + '', '', + '', + '', + ''] + ), + ( + False, + 'Linux', + ['', '', '', + '', '', + '', + '', + ''] + ) +] + + +@pytest.mark.parametrize( + 'persistent, system, expected_reprs', + TESTDATA_4, + ids=['linux persistent map', 'no map (not linux)', 'no map (nonpersistent)'] +) +def test_hardwaremap_scan( + caplog, + mocked_hm, + persistent, + system, + expected_reprs +): + def mock_resolve(path): + if str(path).endswith('-link'): + return Path(str(path)[:-5]) + return path + + def mock_iterdir(path): + return [ + Path(path / 'basic-file1'), + Path(path / 'basic-file2-link') + ] + + mocked_hm.manufacturer = ['dummy manufacturer', 'Texas Instruments'] + mocked_hm.runner_mapping = { + 'dummy runner': ['product[0-9]+',], + 'other runner': ['other TI product', 'TI product'] + } + + comports_mock = [ + mock.Mock( + manufacturer='wrong manufacturer', + location='wrong location', + serial_number='wrong number', + product='wrong product', + device='wrong device' + ), + mock.Mock( + manufacturer='dummy manufacturer', + location='dummy location', + serial_number='dummy number', + product=None, + device='/dev/serial/by-id/basic-file2' + ), + mock.Mock( + manufacturer='dummy manufacturer', + location='dummy location', + serial_number='dummy number', + product='product123', + device='dummy device' + ), + mock.Mock( + manufacturer='Texas Instruments', + location='serial1', + serial_number='TI1', + product='TI product', + device='TI device1' + ), + mock.Mock( + manufacturer='Texas Instruments', + location='serial0', + serial_number='TI0', + product='TI product', + device='/dev/serial/by-id/basic-file1' + ), + ] + + with mock.patch('platform.system', return_value=system), \ + mock.patch('serial.tools.list_ports.comports', + return_value=comports_mock), \ + mock.patch('twisterlib.hardwaremap.Path.resolve', + autospec=True, side_effect=mock_resolve), \ + mock.patch('twisterlib.hardwaremap.Path.iterdir', + autospec=True, side_effect=mock_iterdir): + mocked_hm.scan(persistent) + + assert sorted([d.__repr__() for d in mocked_hm.detected]) == \ + sorted(expected_reprs) + + assert 'Scanning connected hardware...' in caplog.text + assert 'Unsupported device (wrong manufacturer): %s' % comports_mock[0] \ + in caplog.text + + +TESTDATA_5 = [ + ( + None, + [{ + 'platform': 'p1', + 'id': 1, + 'runner': mock.ANY, + 'serial': 's1', + 'product': 'pr1', + 'connected': True + }, + { + 'platform': 'p2', + 'id': 2, + 'runner': mock.ANY, + 'serial': 's2', + 'product': 'pr2', + 'connected': False + }, + { + 'platform': 'p3', + 'id': 3, + 'runner': mock.ANY, + 'serial': 's3', + 'product': 'pr3', + 'connected': True + }, + { + 'platform': 'p4', + 'id': 4, + 'runner': mock.ANY, + 'serial': 's4', + 'product': 'pr4', + 'connected': False + }, + { + 'platform': 'p5', + 'id': 5, + 'runner': mock.ANY, + 'serial': 's5', + 'product': 'pr5', + 'connected': True + }] + ), + ( + '', + [{ + 'serial': 's1', + 'baud': 115200, + 'platform': 'p1', + 'connected': True, + 'id': 1, + 'product': 'pr1', + 'lock': mock.ANY, + 'flash_timeout': 60 + }, + { + 'serial': 's2', + 'baud': 115200, + 'platform': 'p2', + 'id': 2, + 'product': 'pr2', + 'lock': mock.ANY, + 'flash_timeout': 60 + }, + { + 'serial': 's3', + 'baud': 115200, + 'platform': 'p3', + 'connected': True, + 'id': 3, + 'product': 'pr3', + 'lock': mock.ANY, + 'flash_timeout': 60 + }, + { + 'serial': 's4', + 'baud': 115200, + 'platform': 'p4', + 'id': 4, + 'product': 'pr4', + 'lock': mock.ANY, + 'flash_timeout': 60 + }, + { + 'serial': 's5', + 'baud': 115200, + 'platform': 'p5', + 'connected': True, + 'id': 5, + 'product': 'pr5', + 'lock': mock.ANY, + 'flash_timeout': 60 + }] + ), + ( +""" +- id: 4 + platform: p4 + product: pr4 + connected: True + serial: s4 +- id: 0 + platform: p0 + product: pr0 + connected: True + serial: s0 +- id: 10 + platform: p10 + product: pr10 + connected: False + serial: s10 +- id: 5 + platform: p5-5 + product: pr5-5 + connected: True + serial: s5-5 +""", + [{ + 'id': 0, + 'platform': 'p0', + 'product': 'pr0', + 'connected': False, + 'serial': None + }, + { + 'id': 4, + 'platform': 'p4', + 'product': 'pr4', + 'connected': True, + 'serial': 's4' + }, + { + 'id': 5, + 'platform': 'p5-5', + 'product': 'pr5-5', + 'connected': False, + 'serial': None + }, + { + 'id': 10, + 'platform': 'p10', + 'product': 'pr10', + 'connected': False, + 'serial': None + }, + { + 'serial': 's1', + 'baud': 115200, + 'platform': 'p1', + 'connected': True, + 'id': 1, + 'product': 'pr1', + 'lock': mock.ANY, + 'flash_timeout': 60 + }, + { + 'serial': 's2', + 'baud': 115200, + 'platform': 'p2', + 'id': 2, + 'product': 'pr2', + 'lock': mock.ANY, + 'flash_timeout': 60 + }, + { + 'serial': 's3', + 'baud': 115200, + 'platform': 'p3', + 'connected': True, + 'id': 3, + 'product': 'pr3', + 'lock': mock.ANY, + 'flash_timeout': 60 + }, + { + 'serial': 's5', + 'baud': 115200, + 'platform': 'p5', + 'connected': True, + 'id': 5, + 'product': 'pr5', + 'lock': mock.ANY, + 'flash_timeout': 60 + }] + ), +] + + +@pytest.mark.parametrize( + 'hwm, expected_dump', + TESTDATA_5, + ids=['no map', 'empty map', 'map exists'] +) +def test_hardwaremap_save(mocked_hm, hwm, expected_dump): + read_mock = mock.mock_open(read_data=hwm) + write_mock = mock.mock_open() + + def mock_open(filename, mode): + if mode == 'r': + return read_mock() + elif mode == 'w': + return write_mock() + + + mocked_hm.load = mock.Mock() + mocked_hm.dump = mock.Mock() + + open_mock = mock.Mock(side_effect=mock_open) + dump_mock = mock.Mock() + + with mock.patch('os.path.exists', return_value=hwm is not None), \ + mock.patch('builtins.open', open_mock), \ + mock.patch('twisterlib.hardwaremap.yaml.dump', dump_mock): + mocked_hm.save('hwm.yaml') + + dump_mock.assert_called_once_with(expected_dump, mock.ANY, Dumper=mock.ANY, + default_flow_style=mock.ANY) + + +TESTDATA_6 = [ + ( + ['p1', 'p3', 'p5', 'p7'], + [], + True, + True, +""" +| Platform | ID | Serial device | +|------------|------|-----------------| +| p1 | 1 | s1 | +| p3 | 3 | s3 | +| p5 | 5 | s5 | +""" + ), + ( + [], + ['?', '??', '???'], + False, + False, +""" +| ? | ?? | ??? | +|-----|------|-------| +| p1 | 1 | s1 | +| p2 | 2 | s2 | +| p3 | 3 | s3 | +| p4 | 4 | s4 | +| p5 | 5 | s5 | +| p6 | 6 | s6 | +| p7 | 7 | s7 | +| p8 | 8 | s8 | +""" + ), +] + + +@pytest.mark.parametrize( + 'filtered, header, connected_only, detected, expected_out', + TESTDATA_6, + ids=['detected no header', 'all with header'] +) +def test_hardwaremap_dump( + capfd, + mocked_hm, + filtered, + header, + connected_only, + detected, + expected_out +): + mocked_hm.dump(filtered, header, connected_only, detected) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert out.strip() == expected_out.strip() diff --git a/scripts/tests/twister/test_harness.py b/scripts/tests/twister/test_harness.py index 1da2aed3f46c805..925a738b8bc4f95 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_jobserver.py b/scripts/tests/twister/test_jobserver.py new file mode 100644 index 000000000000000..c97e93204479b2e --- /dev/null +++ b/scripts/tests/twister/test_jobserver.py @@ -0,0 +1,457 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Tests for jobserver.py classes' methods +""" + +import functools +import mock +import os +import pytest +import sys + +from contextlib import nullcontext +from errno import ENOENT +from fcntl import F_GETFL +from selectors import EVENT_READ + +from twisterlib.jobserver import ( + JobHandle, + JobClient, + GNUMakeJobClient, + GNUMakeJobServer +) + + +def test_jobhandle(capfd): + def f(a, b, c=None, d=None): + print(f'{a}, {b}, {c}, {d}') + + def exiter(): + with JobHandle(f, 1, 2, c='three', d=4): + return + + exiter() + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert '1, 2, three, 4' in out + + +def test_jobclient_get_job(): + jc = JobClient() + + job = jc.get_job() + + assert isinstance(job, JobHandle) + assert job.release_func is None + + +def test_jobclient_env(): + env = JobClient.env() + + assert env == {} + + +def test_jobclient_pass_fds(): + fds = JobClient.pass_fds() + + assert fds == [] + + +TESTDATA_1 = [ + ({}, {'env': {'k': 'v'}, 'pass_fds': []}), + ({'env': {}, 'pass_fds': ['fd']}, {'env': {}, 'pass_fds': ['fd']}), +] + +@pytest.mark.parametrize( + 'kwargs, expected_kwargs', + TESTDATA_1, + ids=['no values', 'preexisting values'] +) +def test_jobclient_popen(kwargs, expected_kwargs): + jc = JobClient() + + argv = ['cmd', 'and', 'some', 'args'] + proc_mock = mock.Mock() + popen_mock = mock.Mock(return_value=proc_mock) + env_mock = {'k': 'v'} + + with mock.patch('subprocess.Popen', popen_mock), \ + mock.patch('os.environ', env_mock): + proc = jc.popen(argv, **kwargs) + + popen_mock.assert_called_once_with(argv, **expected_kwargs) + assert proc == proc_mock + + +TESTDATA_2 = [ + (False, 0), + (True, 0), + (False, 4), + (True, 16), +] + + +@pytest.mark.parametrize( + 'inheritable, internal_jobs', + TESTDATA_2, + ids=['no inheritable, no internal', 'inheritable, no internal', + 'no inheritable, internal', 'inheritable, internal'] +) +def test_gnumakejobclient_dunders(inheritable, internal_jobs): + inherit_read_fd = mock.Mock() + inherit_write_fd = mock.Mock() + inheritable_pipe = (inherit_read_fd, inherit_write_fd) if inheritable else \ + None + + internal_read_fd = mock.Mock() + internal_write_fd = mock.Mock() + + def mock_pipe(): + return (internal_read_fd, internal_write_fd) + + close_mock = mock.Mock() + write_mock = mock.Mock() + set_blocking_mock = mock.Mock() + selector_mock = mock.Mock() + + def deleter(): + jobs = mock.Mock() + makeflags = mock.Mock() + + gmjc = GNUMakeJobClient( + inheritable_pipe, + jobs, + internal_jobs=internal_jobs, + makeflags=makeflags + ) + + assert gmjc.jobs == jobs + if internal_jobs: + write_mock.assert_called_once_with(internal_write_fd, + b'+' * internal_jobs) + set_blocking_mock.assert_any_call(internal_read_fd, False) + selector_mock().register.assert_any_call(internal_read_fd, + EVENT_READ, + internal_write_fd) + if inheritable: + set_blocking_mock.assert_any_call(inherit_read_fd, False) + selector_mock().register.assert_any_call(inherit_read_fd, + EVENT_READ, + inherit_write_fd) + + with mock.patch('os.close', close_mock), \ + mock.patch('os.write', write_mock), \ + mock.patch('os.set_blocking', set_blocking_mock), \ + mock.patch('os.pipe', mock_pipe), \ + mock.patch('selectors.DefaultSelector', selector_mock): + deleter() + + if internal_jobs: + close_mock.assert_any_call(internal_read_fd) + close_mock.assert_any_call(internal_write_fd) + if inheritable: + close_mock.assert_any_call(inherit_read_fd) + close_mock.assert_any_call(inherit_write_fd) + + +TESTDATA_3 = [ + ( + {'MAKEFLAGS': '-j1'}, + 0, + (False, False), + ['Running in sequential mode (-j1)'], + None, + [None, 1], + {'internal_jobs': 1, 'makeflags': '-j1'} + ), + ( + {'MAKEFLAGS': 'n--jobserver-auth=0,1'}, + 1, + (True, True), + [ + '-jN forced on command line; ignoring GNU make jobserver', + 'MAKEFLAGS contained dry-run flag' + ], + 0, + None, + None + ), + ( + {'MAKEFLAGS': '--jobserver-auth=0,1'}, + 0, + (True, True), + ['using GNU make jobserver'], + None, + [[0, 1], 0], + {'internal_jobs': 1, 'makeflags': '--jobserver-auth=0,1'} + ), + ( + {'MAKEFLAGS': '--jobserver-auth=123,321'}, + 0, + (False, False), + ['No file descriptors; ignoring GNU make jobserver'], + None, + [None, 0], + {'internal_jobs': 1, 'makeflags': '--jobserver-auth=123,321'} + ), + ( + {'MAKEFLAGS': '--jobserver-auth=0,1'}, + 0, + (False, True), + [f'FD 0 is not readable (flags=2); ignoring GNU make jobserver'], + None, + [None, 0], + {'internal_jobs': 1, 'makeflags': '--jobserver-auth=0,1'} + ), + ( + {'MAKEFLAGS': '--jobserver-auth=0,1'}, + 0, + (True, False), + [f'FD 1 is not writable (flags=2); ignoring GNU make jobserver'], + None, + [None, 0], + {'internal_jobs': 1, 'makeflags': '--jobserver-auth=0,1'} + ), + (None, 0, (False, False), [], None, None, None), +] + +@pytest.mark.parametrize( + 'env, jobs, fcntl_ok_per_pipe, expected_logs,' \ + ' exit_code, expected_args, expected_kwargs', + TESTDATA_3, + ids=['env, no jobserver-auth', 'env, jobs, dry run', 'env, no jobs', + 'env, no jobs, oserror', 'env, no jobs, wrong read pipe', + 'env, no jobs, wrong write pipe', 'environ, no makeflags'] +) +def test_gnumakejobclient_from_environ( + caplog, + env, + jobs, + fcntl_ok_per_pipe, + expected_logs, + exit_code, + expected_args, + expected_kwargs +): + def mock_fcntl(fd, flag): + if flag == F_GETFL: + if fd == 0: + if fcntl_ok_per_pipe[0]: + return os.O_RDONLY + else: + return 2 + elif fd == 1: + if fcntl_ok_per_pipe[1]: + return os.O_WRONLY + else: + return 2 + raise OSError(ENOENT, 'dummy error') + + gmjc_init_mock = mock.Mock(return_value=None) + + with mock.patch('fcntl.fcntl', mock_fcntl), \ + mock.patch('os.close', mock.Mock()), \ + mock.patch('twisterlib.jobserver.GNUMakeJobClient.__init__', + gmjc_init_mock), \ + pytest.raises(SystemExit) if exit_code is not None else \ + nullcontext() as se: + gmjc = GNUMakeJobClient.from_environ(env=env, jobs=jobs) + + # As patching __del__ is hard to do, we'll instead + # cover possible exceptions and mock os calls + if gmjc: + gmjc._inheritable_pipe = getattr(gmjc, '_inheritable_pipe', None) + if gmjc: + gmjc._internal_pipe = getattr(gmjc, '_internal_pipe', None) + + assert all([log in caplog.text for log in expected_logs]) + + if se: + assert str(se.value) == str(exit_code) + return + + if expected_args is None and expected_kwargs is None: + assert gmjc is None + else: + gmjc_init_mock.assert_called_once_with(*expected_args, + **expected_kwargs) + + +def test_gnumakejobclient_get_job(): + inherit_read_fd = mock.Mock() + inherit_write_fd = mock.Mock() + inheritable_pipe = (inherit_read_fd, inherit_write_fd) + + internal_read_fd = mock.Mock() + internal_write_fd = mock.Mock() + + def mock_pipe(): + return (internal_read_fd, internal_write_fd) + + selected = [[mock.Mock(fd=0, data=1)], [mock.Mock(fd=1, data=0)]] + + def mock_select(): + nonlocal selected + return selected + + def mock_read(fd, length): + nonlocal selected + if fd == 0: + selected = selected[1:] + raise BlockingIOError + return b'?' * length + + close_mock = mock.Mock() + write_mock = mock.Mock() + set_blocking_mock = mock.Mock() + selector_mock = mock.Mock() + selector_mock().select = mock.Mock(side_effect=mock_select) + + def deleter(): + jobs = mock.Mock() + + gmjc = GNUMakeJobClient( + inheritable_pipe, + jobs + ) + + with mock.patch('os.read', side_effect=mock_read): + job = gmjc.get_job() + with job: + expected_func = functools.partial(os.write, 0, b'?') + + assert job.release_func.func == expected_func.func + assert job.release_func.args == expected_func.args + assert job.release_func.keywords == expected_func.keywords + + with mock.patch('os.close', close_mock), \ + mock.patch('os.write', write_mock), \ + mock.patch('os.set_blocking', set_blocking_mock), \ + mock.patch('os.pipe', mock_pipe), \ + mock.patch('selectors.DefaultSelector', selector_mock): + deleter() + + write_mock.assert_any_call(0, b'?') + + +TESTDATA_4 = [ + ('dummy makeflags', mock.ANY, mock.ANY, {'MAKEFLAGS': 'dummy makeflags'}), + (None, 0, False, {'MAKEFLAGS': ''}), + (None, 1, True, {'MAKEFLAGS': ' -j1'}), + (None, 2, True, {'MAKEFLAGS': ' -j2 --jobserver-auth=0,1'}), + (None, 0, True, {'MAKEFLAGS': ' --jobserver-auth=0,1'}), +] + +@pytest.mark.parametrize( + 'makeflags, jobs, use_inheritable_pipe, expected_makeflags', + TESTDATA_4, + ids=['preexisting makeflags', 'no jobs, no pipe', 'one job', + ' multiple jobs', 'no jobs'] +) +def test_gnumakejobclient_env( + makeflags, + jobs, + use_inheritable_pipe, + expected_makeflags +): + inheritable_pipe = (0, 1) if use_inheritable_pipe else None + + selector_mock = mock.Mock() + + env = None + + def deleter(): + gmjc = GNUMakeJobClient(None, None) + gmjc.jobs = jobs + gmjc._makeflags = makeflags + gmjc._inheritable_pipe = inheritable_pipe + + nonlocal env + env = gmjc.env() + + with mock.patch.object(GNUMakeJobClient, '__del__', mock.Mock()), \ + mock.patch('selectors.DefaultSelector', selector_mock): + deleter() + + assert env == expected_makeflags + + +TESTDATA_5 = [ + (2, False, []), + (1, True, []), + (2, True, (0, 1)), + (0, True, (0, 1)), +] + +@pytest.mark.parametrize( + 'jobs, use_inheritable_pipe, expected_fds', + TESTDATA_5, + ids=['no pipe', 'one job', ' multiple jobs', 'no jobs'] +) +def test_gnumakejobclient_pass_fds(jobs, use_inheritable_pipe, expected_fds): + inheritable_pipe = (0, 1) if use_inheritable_pipe else None + + selector_mock = mock.Mock() + + fds = None + + def deleter(): + gmjc = GNUMakeJobClient(None, None) + gmjc.jobs = jobs + gmjc._inheritable_pipe = inheritable_pipe + + nonlocal fds + fds = gmjc.pass_fds() + + with mock.patch('twisterlib.jobserver.GNUMakeJobClient.__del__', + mock.Mock()), \ + mock.patch('selectors.DefaultSelector', selector_mock): + deleter() + + assert fds == expected_fds + + +TESTDATA_6 = [ + (0, 8), + (32, 16), + (4, 4), +] + +@pytest.mark.parametrize( + 'jobs, expected_jobs', + TESTDATA_6, + ids=['no jobs', 'too many jobs', 'valid jobs'] +) +def test_gnumakejobserver(jobs, expected_jobs): + def mock_init(self, p, j): + self._inheritable_pipe = p + self._internal_pipe = None + self.jobs = j + + pipe = (0, 1) + cpu_count = 8 + pipe_buf = 16 + + selector_mock = mock.Mock() + write_mock = mock.Mock() + del_mock = mock.Mock() + + def deleter(): + GNUMakeJobServer(jobs=jobs) + + with mock.patch.object(GNUMakeJobClient, '__del__', del_mock), \ + mock.patch.object(GNUMakeJobClient, '__init__', mock_init), \ + mock.patch('os.pipe', return_value=pipe), \ + mock.patch('os.write', write_mock), \ + mock.patch('multiprocessing.cpu_count', return_value=cpu_count), \ + mock.patch('select.PIPE_BUF', pipe_buf), \ + mock.patch('selectors.DefaultSelector', selector_mock): + deleter() + + write_mock.assert_called_once_with(pipe[1], b'+' * expected_jobs) diff --git a/scripts/tests/twister/test_platform.py b/scripts/tests/twister/test_platform.py new file mode 100644 index 000000000000000..c40a10a9b781099 --- /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 37c02b6d17be77a..fcf6ccd2a0193e2 100644 --- a/scripts/tests/twister/test_runner.py +++ b/scripts/tests/twister/test_runner.py @@ -6,19 +6,34 @@ Tests for runner.py classes """ +import errno import mock import os +import pathlib import pytest +import queue +import re +import subprocess import sys import yaml +from contextlib import nullcontext +from elftools.elf.sections import SymbolTableSection from typing import List ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) -from twisterlib.runner import ProjectBuilder +from twisterlib.error import BuildError +from twisterlib.harness import Pytest +from twisterlib.runner import ( + CMake, + ExecutionCounter, + FilterBuilder, + ProjectBuilder, + TwisterRunner +) @pytest.fixture def mocked_instance(tmp_path): @@ -78,7 +93,7 @@ def runners(project_builder: ProjectBuilder) -> dict: @mock.patch("os.path.exists") -def test_projectbuilder_cmake_assemble_args(m): +def test_projectbuilder_cmake_assemble_args_single(m): # Causes the additional_overlay_path to be appended m.return_value = True @@ -164,3 +179,2489 @@ def test_if_zephyr_base_is_sanitized_properly(project_builder: ProjectBuilder): with open(cmakecache_file_path, 'r') as file: sanitized_path = file.read() assert sanitized_path == sanitized_path_expected + + +def test_executioncounter(capfd): + ec = ExecutionCounter(total=12) + + ec.cases = 25 + ec.skipped_cases = 6 + ec.error = 2 + ec.iteration = 2 + ec.done = 9 + ec.passed = 6 + ec.skipped_configs = 3 + ec.skipped_runtime = 1 + ec.skipped_filter = 2 + ec.failed = 1 + + ec.summary() + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert ( + f'--------------------------------\n' + f'Total test suites: 12\n' + f'Total test cases: 25\n' + f'Executed test cases: 19\n' + f'Skipped test cases: 6\n' + f'Completed test suites: 9\n' + f'Passing test suites: 6\n' + f'Failing test suites: 1\n' + f'Skipped test suites: 3\n' + f'Skipped test suites (runtime): 1\n' + f'Skipped test suites (filter): 2\n' + f'Errors: 2\n' + f'--------------------------------' + ) in out + + assert ec.cases == 25 + assert ec.skipped_cases == 6 + assert ec.error == 2 + assert ec.iteration == 2 + assert ec.done == 9 + assert ec.passed == 6 + assert ec.skipped_configs == 3 + assert ec.skipped_runtime == 1 + assert ec.skipped_filter == 2 + assert ec.failed == 1 + + +def test_cmake_parse_generated(mocked_jobserver): + testsuite_mock = mock.Mock() + platform_mock = mock.Mock() + source_dir = os.path.join('source', 'dir') + build_dir = os.path.join('build', 'dir') + + cmake = CMake(testsuite_mock, platform_mock, source_dir, build_dir, + mocked_jobserver) + + result = cmake.parse_generated() + + assert cmake.defconfig == {} + assert result == {} + + +TESTDATA_1_1 = [ + ('linux'), + ('nt') +] +TESTDATA_1_2 = [ + (0, False, 'dummy out', + True, True, 'passed', None, False, True), + (0, True, '', + False, False, 'passed', None, False, False), + (1, True, 'ERROR: region `FLASH\' overflowed by 123 MB', + True, True, 'skipped', 'FLASH overflow', True, False), + (1, True, 'Error: Image size (99 B) + trailer (1 B) exceeds requested size', + True, True, 'skipped', 'imgtool overflow', True, False), + (1, True, 'mock.ANY', + True, True, 'error', 'Build failure', False, False) +] + +@pytest.mark.parametrize( + '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', + 'error - region overflow', 'error - image size exceed', 'error'] +) +@pytest.mark.parametrize('sys_platform', TESTDATA_1_1) +def test_cmake_run_build( + sys_platform, + return_code, + is_instance_run, + p_out, + expect_returncode, + expect_writes, + expected_status, + expected_reason, + expected_change_skip, + expected_add_missing +): + process_mock = mock.Mock( + returncode=return_code, + communicate=mock.Mock( + return_value=(p_out.encode(sys.getdefaultencoding()), None) + ) + ) + + def mock_popen(*args, **kwargs): + return process_mock + + testsuite_mock = mock.Mock() + platform_mock = mock.Mock() + platform_mock.name = '' + source_dir = os.path.join('source', 'dir') + build_dir = os.path.join('build', 'dir') + jobserver_mock = mock.Mock( + 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 + + cmake = CMake(testsuite_mock, platform_mock, source_dir, build_dir, + jobserver_mock) + cmake.cwd = os.path.join('dummy', 'working', 'dir') + cmake.instance = instance_mock + cmake.options = mock.Mock() + cmake.options.overflow_as_errors = False + + cmake_path = os.path.join('dummy', 'cmake') + + popen_mock = mock.Mock(side_effect=mock_popen) + change_mock = mock.Mock() + + with mock.patch('sys.platform', sys_platform), \ + mock.patch('shutil.which', return_value=cmake_path), \ + mock.patch('twisterlib.runner.change_skip_to_error_if_integration', + change_mock), \ + mock.patch('builtins.open', mock.mock_open()), \ + mock.patch('subprocess.Popen', popen_mock): + result = cmake.run_build(args=['arg1', 'arg2']) + + expected_results = {} + if expect_returncode: + expected_results['returncode'] = return_code + if expected_results == {}: + expected_results = None + + assert expected_results == result + + popen_caller = cmake.jobserver.popen if sys_platform == 'linux' else \ + popen_mock + popen_caller.assert_called_once_with( + [os.path.join('dummy', 'cmake'), 'arg1', 'arg2'], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + cwd=os.path.join('dummy', 'working', 'dir') + ) + + assert cmake.instance.status == expected_status + assert cmake.instance.reason == expected_reason + + if expected_change_skip: + change_mock.assert_called_once() + + if expected_add_missing: + cmake.instance.add_missing_case_status.assert_called_once_with( + 'skipped', 'Test was built only' + ) + + +TESTDATA_2_1 = [ + ('linux'), + ('nt') +] +TESTDATA_2_2 = [ + (True, ['dummy_stage_1', 'ds2'], + 0, False, '', + True, True, False, + None, None, + [os.path.join('dummy', 'cmake'), + '-B' + os.path.join('build', 'dir'), '-DTC_RUNID=1', + '-DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y', + '-DEXTRA_GEN_DEFINES_ARGS=--edtlib-Werror', '-Gdummy_generator', + '-S' + os.path.join('source', 'dir'), + 'arg1', 'arg2', + '-DBOARD=', + '-DSNIPPET=dummy snippet 1;ds2', + '-DMODULES=dummy_stage_1,ds2', + '-Pzephyr_base/cmake/package_helper.cmake']), + (False, [], + 1, True, 'ERROR: region `FLASH\' overflowed by 123 MB', + True, False, True, + 'error', 'Cmake build failure', + [os.path.join('dummy', 'cmake'), + '-B' + os.path.join('build', 'dir'), '-DTC_RUNID=1', + '-DCONFIG_COMPILER_WARNINGS_AS_ERRORS=n', + '-DEXTRA_GEN_DEFINES_ARGS=', '-Gdummy_generator', + '-Szephyr_base/share/sysbuild', + '-DAPP_DIR=' + os.path.join('source', 'dir'), + 'arg1', 'arg2', + '-DBOARD=', + '-DSNIPPET=dummy snippet 1;ds2']), +] + +@pytest.mark.parametrize( + 'error_warns, f_stages,' \ + ' return_code, is_instance_run, p_out, expect_returncode,' \ + ' expect_filter, expect_writes, expected_status, expected_reason,' \ + ' expected_cmd', + TESTDATA_2_2, + ids=['filter_stages with success', 'no stages with error'] +) +@pytest.mark.parametrize('sys_platform', TESTDATA_2_1) +def test_cmake_run_cmake( + sys_platform, + error_warns, + f_stages, + return_code, + is_instance_run, + p_out, + expect_returncode, + expect_filter, + expect_writes, + expected_status, + expected_reason, + expected_cmd +): + process_mock = mock.Mock( + returncode=return_code, + communicate=mock.Mock( + return_value=(p_out.encode(sys.getdefaultencoding()), None) + ) + ) + + def mock_popen(*args, **kwargs): + return process_mock + + testsuite_mock = mock.Mock() + testsuite_mock.sysbuild = True + platform_mock = mock.Mock() + platform_mock.name = '' + source_dir = os.path.join('source', 'dir') + build_dir = os.path.join('build', 'dir') + jobserver_mock = mock.Mock( + popen=mock.Mock(side_effect=mock_popen) + ) + 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() + instance_mock.testsuite.required_snippets = ['dummy snippet 1', 'ds2'] + instance_mock.testcases = [mock.Mock(), mock.Mock()] + instance_mock.testcases[0].status = None + instance_mock.testcases[1].status = None + + cmake = CMake(testsuite_mock, platform_mock, source_dir, build_dir, + jobserver_mock) + cmake.cwd = os.path.join('dummy', 'working', 'dir') + cmake.instance = instance_mock + cmake.options = mock.Mock() + cmake.options.disable_warnings_as_errors = not error_warns + cmake.options.overflow_as_errors = False + cmake.env = mock.Mock() + cmake.env.generator = 'dummy_generator' + + cmake_path = os.path.join('dummy', 'cmake') + + popen_mock = mock.Mock(side_effect=mock_popen) + change_mock = mock.Mock() + + with mock.patch('sys.platform', sys_platform), \ + mock.patch('shutil.which', return_value=cmake_path), \ + mock.patch('twisterlib.runner.change_skip_to_error_if_integration', + change_mock), \ + mock.patch('twisterlib.runner.canonical_zephyr_base', + 'zephyr_base'), \ + mock.patch('builtins.open', mock.mock_open()), \ + mock.patch('subprocess.Popen', popen_mock): + result = cmake.run_cmake(args=['arg1', 'arg2'], filter_stages=f_stages) + + expected_results = {} + if expect_returncode: + expected_results['returncode'] = return_code + if expect_filter: + expected_results['filter'] = {} + if expected_results == {}: + expected_results = None + + assert expected_results == result + + popen_caller = cmake.jobserver.popen if sys_platform == 'linux' else \ + popen_mock + popen_caller.assert_called_once_with( + expected_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + cwd=os.path.join('dummy', 'working', 'dir') + ) + + assert cmake.instance.status == expected_status + assert cmake.instance.reason == expected_reason + + for tc in cmake.instance.testcases: + assert tc.status == cmake.instance.status + + +TESTDATA_3 = [ + ('unit_testing', [], False, True, None, True, None, True, + None, None, {}, {}, None, None, [], {}), + ( + 'other', [], True, + True, ['dummy', 'west', 'options'], True, + None, True, + os.path.join('domain', 'build', 'dir', 'zephyr', '.config'), + os.path.join('domain', 'build', 'dir', 'zephyr', 'edt.pickle'), + {'CONFIG_FOO': 'no'}, + {'dummy cache elem': 1}, + {'ARCH': 'dummy arch', 'PLATFORM': 'other', 'env_dummy': True, + 'CONFIG_FOO': 'no', 'dummy cache elem': 1}, + b'dummy edt pickle contents', + [f'Loaded sysbuild domain data from' \ + f' {os.path.join("build", "dir", "domains.yaml")}'], + {os.path.join('other', 'dummy.testsuite.name'): True} + ), + ( + 'other', ['kconfig'], True, + True, ['dummy', 'west', 'options'], True, + 'Dummy parse results', True, + os.path.join('build', 'dir', 'zephyr', '.config'), + os.path.join('build', 'dir', 'zephyr', 'edt.pickle'), + {'CONFIG_FOO': 'no'}, + {'dummy cache elem': 1}, + {'ARCH': 'dummy arch', 'PLATFORM': 'other', 'env_dummy': True, + 'CONFIG_FOO': 'no', 'dummy cache elem': 1}, + b'dummy edt pickle contents', + [], + {os.path.join('other', 'dummy.testsuite.name'): False} + ), + ( + 'other', ['other'], False, + False, None, True, + 'Dummy parse results', True, + None, + os.path.join('build', 'dir', 'zephyr', 'edt.pickle'), + {}, + {}, + {'ARCH': 'dummy arch', 'PLATFORM': 'other', 'env_dummy': True}, + b'dummy edt pickle contents', + [], + {os.path.join('other', 'dummy.testsuite.name'): False} + ), + ( + 'other', ['other'], True, + False, None, True, + 'Dummy parse results', True, + None, + None, + {}, + {}, + {}, + None, + ['Sysbuild test will be skipped. West must be used for flashing.'], + {os.path.join('other', 'dummy.testsuite.name'): True} + ), + ( + 'other', ['other'], True, + False, ['--erase'], True, + 'Dummy parse results', True, + None, + None, + {}, + {}, + None, + b'dummy edt pickle contents', + ['Sysbuild test will be skipped,' \ + ' --erase is not supported with --west-flash'], + {os.path.join('other', 'dummy.testsuite.name'): True} + ), + ( + 'other', ['other'], False, + True, None, False, + 'Dummy parse results', True, + None, + None, + {}, + {'dummy cache elem': 1}, + {'ARCH': 'dummy arch', 'PLATFORM': 'other', 'env_dummy': True, + 'dummy cache elem': 1}, + None, + [], + {os.path.join('other', 'dummy.testsuite.name'): False} + ), + ( + 'other', ['other'], False, + True, None, True, + 'Dummy parse results', True, + None, + os.path.join('build', 'dir', 'zephyr', 'edt.pickle'), + {}, + {'dummy cache elem': 1}, + {'ARCH': 'dummy arch', 'PLATFORM': 'other', 'env_dummy': True, + 'dummy cache elem': 1}, + b'dummy edt pickle contents', + [], + {os.path.join('other', 'dummy.testsuite.name'): False} + ), + ( + 'other', ['other'], False, + True, None, True, + None, True, + None, + os.path.join('build', 'dir', 'zephyr', 'edt.pickle'), + {}, + {'dummy cache elem': 1}, + {'ARCH': 'dummy arch', 'PLATFORM': 'other', 'env_dummy': True, + 'dummy cache elem': 1}, + b'dummy edt pickle contents', + [], + {os.path.join('other', 'dummy.testsuite.name'): True} + ), + ( + 'other', ['other'], False, + True, None, True, + 'Dummy parse results', False, + None, + os.path.join('build', 'dir', 'zephyr', 'edt.pickle'), + {}, + {'dummy cache elem': 1}, + {'ARCH': 'dummy arch', 'PLATFORM': 'other', 'env_dummy': True, + 'dummy cache elem': 1}, + b'dummy edt pickle contents', + [], + {'ARCH': 'dummy arch', 'PLATFORM': 'other', 'env_dummy': True, + 'dummy cache elem': 1} + ), + ( + 'other', ['other'], False, + True, None, True, + SyntaxError, True, + None, + os.path.join('build', 'dir', 'zephyr', 'edt.pickle'), + {}, + {'dummy cache elem': 1}, + {'ARCH': 'dummy arch', 'PLATFORM': 'other', 'env_dummy': True, + 'dummy cache elem': 1}, + b'dummy edt pickle contents', + ['Failed processing testsuite.yaml'], + SyntaxError + ), +] + +@pytest.mark.parametrize( + 'platform_name, filter_stages, sysbuild,' \ + ' do_find_cache, west_flash_options, edt_exists,' \ + ' parse_results, testsuite_filter,' \ + ' expected_defconfig_path, expected_edt_pickle_path,' \ + ' expected_defconfig, expected_cmakecache, expected_filter_data,' \ + ' expected_edt,' \ + ' expected_logs, expected_return', + TESTDATA_3, + ids=['unit testing', 'domain', 'kconfig', 'no cache', + 'no west options', 'erase west flash option', 'no edt', + 'parse result', 'no parse result', 'no testsuite filter', 'parse err'] +) +def test_filterbuilder_parse_generated( + caplog, + mocked_jobserver, + platform_name, + filter_stages, + sysbuild, + do_find_cache, + west_flash_options, + edt_exists, + parse_results, + testsuite_filter, + expected_defconfig_path, + expected_edt_pickle_path, + expected_defconfig, + expected_cmakecache, + expected_filter_data, + expected_edt, + expected_logs, + expected_return +): + def mock_domains_from_file(*args, **kwargs): + dom = mock.Mock() + dom.build_dir = os.path.join('domain', 'build', 'dir') + res = mock.Mock(get_default_domain=mock.Mock(return_value=dom)) + return res + + def mock_cmakecache_from_file(*args, **kwargs): + if not do_find_cache: + raise FileNotFoundError(errno.ENOENT, 'Cache not found') + cache_elem = mock.Mock() + cache_elem.name = 'dummy cache elem' + cache_elem.value = 1 + cache = [cache_elem] + return cache + + def mock_open(filepath, type, *args, **kwargs): + if filepath == expected_defconfig_path: + rd = 'I am not a proper line\n' \ + 'CONFIG_FOO="no"' + elif filepath == expected_edt_pickle_path: + rd = b'dummy edt pickle contents' + else: + raise FileNotFoundError(errno.ENOENT, + f'File {filepath} not mocked.') + return mock.mock_open(read_data=rd)() + + def mock_parser(filter, filter_data, edt): + assert filter_data == expected_filter_data + if isinstance(parse_results, type) and \ + issubclass(parse_results, Exception): + raise parse_results + return parse_results + + def mock_pickle(datafile): + assert datafile.read() == expected_edt + return mock.Mock() + + testsuite_mock = mock.Mock() + testsuite_mock.sysbuild = 'sysbuild' if sysbuild else None + testsuite_mock.name = 'dummy.testsuite.name' + testsuite_mock.filter = testsuite_filter + platform_mock = mock.Mock() + platform_mock.name = platform_name + platform_mock.arch = 'dummy arch' + source_dir = os.path.join('source', 'dir') + build_dir = os.path.join('build', 'dir') + + fb = FilterBuilder(testsuite_mock, platform_mock, source_dir, build_dir, + mocked_jobserver) + instance_mock = mock.Mock() + fb.instance = instance_mock + fb.env = mock.Mock() + fb.env.options = mock.Mock() + fb.env.options.west_flash = west_flash_options + fb.env.options.device_testing = True + + environ_mock = {'env_dummy': True} + + with mock.patch('twisterlib.runner.Domains.from_file', + mock_domains_from_file), \ + mock.patch('twisterlib.runner.CMakeCache.from_file', + mock_cmakecache_from_file), \ + mock.patch('builtins.open', mock_open), \ + mock.patch('expr_parser.parse', mock_parser), \ + mock.patch('pickle.load', mock_pickle), \ + mock.patch('os.path.exists', return_value=edt_exists), \ + mock.patch('os.environ', environ_mock), \ + pytest.raises(expected_return) if \ + isinstance(parse_results, type) and \ + issubclass(parse_results, Exception) else nullcontext() as err: + result = fb.parse_generated(filter_stages) + + if err: + assert True + return + + assert all([log in caplog.text for log in expected_logs]) + + assert fb.defconfig == expected_defconfig + + assert fb.cmake_cache == expected_cmakecache + + assert result == expected_return + + +TESTDATA_4 = [ + (False, False, [f"see: {os.path.join('dummy', 'path', 'dummy_file.log')}"]), + (True, False, [os.path.join('dummy', 'path', 'dummy_file.log'), + 'file contents', + os.path.join('dummy', 'path', 'dummy_file.log')]), + (True, True, [os.path.join('dummy', 'path', 'dummy_file.log'), + 'Unable to read log data ([Errno 2] ERROR: dummy_file.log)', + os.path.join('dummy', 'path', 'dummy_file.log')]), +] + +@pytest.mark.parametrize( + 'inline_logs, read_exception, expected_logs', + TESTDATA_4, + ids=['basic', 'inline logs', 'inline logs+read_exception'] +) +def test_projectbuilder_log_info( + caplog, + mocked_jobserver, + inline_logs, + read_exception, + expected_logs +): + def mock_open(filename, *args, **kwargs): + if read_exception: + raise OSError(errno.ENOENT, f'ERROR: {os.path.basename(filename)}') + return mock.mock_open(read_data='file contents')() + + def mock_realpath(filename, *args, **kwargs): + return os.path.join('path', filename) + + def mock_abspath(filename, *args, **kwargs): + return os.path.join('dummy', filename) + + filename = 'dummy_file.log' + + env_mock = mock.Mock() + instance_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + with mock.patch('builtins.open', mock_open), \ + mock.patch('os.path.realpath', mock_realpath), \ + mock.patch('os.path.abspath', mock_abspath): + pb.log_info(filename, inline_logs) + + assert all([log in caplog.text for log in expected_logs]) + + +TESTDATA_5 = [ + (True, False, False, "Valgrind error", 0, 0, 'build_dir/valgrind.log'), + (True, False, False, "Error", 0, 0, 'build_dir/build.log'), + (False, True, False, None, 1024, 0, 'build_dir/handler.log'), + (False, True, False, None, 0, 0, 'build_dir/build.log'), + (False, False, True, None, 0, 1024, 'build_dir/device.log'), + (False, False, True, None, 0, 0, 'build_dir/build.log'), + (False, False, False, None, 0, 0, 'build_dir/build.log'), +] + +@pytest.mark.parametrize( + 'valgrind_log_exists, handler_log_exists, device_log_exists,' \ + ' instance_reason, handler_log_getsize, device_log_getsize, expected_log', + TESTDATA_5, + ids=['valgrind log', 'valgrind log unused', + 'handler log', 'handler log unused', + 'device log', 'device log unused', + 'no logs'] +) +def test_projectbuilder_log_info_file( + caplog, + mocked_jobserver, + valgrind_log_exists, + handler_log_exists, + device_log_exists, + instance_reason, + handler_log_getsize, + device_log_getsize, + expected_log +): + def mock_exists(filename, *args, **kwargs): + if filename == 'build_dir/handler.log': + return handler_log_exists + if filename == 'build_dir/valgrind.log': + return valgrind_log_exists + if filename == 'build_dir/device.log': + return device_log_exists + return False + + def mock_getsize(filename, *args, **kwargs): + if filename == 'build_dir/handler.log': + return handler_log_getsize + if filename == 'build_dir/device.log': + return device_log_getsize + return 0 + + env_mock = mock.Mock() + instance_mock = mock.Mock() + instance_mock.reason = instance_reason + instance_mock.build_dir = 'build_dir' + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + + log_info_mock = mock.Mock() + + with mock.patch('os.path.exists', mock_exists), \ + mock.patch('os.path.getsize', mock_getsize), \ + mock.patch('twisterlib.runner.ProjectBuilder.log_info', log_info_mock): + pb.log_info_file(None) + + log_info_mock.assert_called_with(expected_log, mock.ANY) + + +TESTDATA_6 = [ + ( + {'op': 'filter'}, + 'failed', + 'Failed', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + [], + {'op': 'report', 'test': mock.ANY}, + 'failed', + 'Failed', + 0, + None + ), + ( + {'op': 'filter'}, + 'passed', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + {'filter': { 'dummy instance name': True }}, + mock.ANY, + mock.ANY, + mock.ANY, + ['filtering dummy instance name'], + {'op': 'report', 'test': mock.ANY}, + 'filtered', + 'runtime filter', + 1, + ('skipped',) + ), + ( + {'op': 'filter'}, + 'passed', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + {'filter': { 'another dummy instance name': True }}, + mock.ANY, + mock.ANY, + mock.ANY, + [], + {'op': 'cmake', 'test': mock.ANY}, + 'passed', + mock.ANY, + 0, + None + ), + ( + {'op': 'cmake'}, + 'error', + 'dummy error', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + [], + {'op': 'report', 'test': mock.ANY}, + 'error', + 'dummy error', + 0, + None + ), + ( + {'op': 'cmake'}, + None, + mock.ANY, + mock.ANY, + mock.ANY, + True, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + [], + {'op': 'report', 'test': mock.ANY}, + 'passed', + mock.ANY, + 0, + None + ), + ( + {'op': 'cmake'}, + 'success', + mock.ANY, + mock.ANY, + mock.ANY, + True, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + [], + {'op': 'report', 'test': mock.ANY}, + 'success', + mock.ANY, + 0, + None + ), + ( + {'op': 'cmake'}, + 'success', + mock.ANY, + mock.ANY, + mock.ANY, + False, + mock.ANY, + mock.ANY, + mock.ANY, + {'filter': {'dummy instance name': True}}, + mock.ANY, + mock.ANY, + mock.ANY, + ['filtering dummy instance name'], + {'op': 'report', 'test': mock.ANY}, + 'filtered', + 'runtime filter', + 1, + ('skipped',) + ), + ( + {'op': 'cmake'}, + 'success', + mock.ANY, + mock.ANY, + mock.ANY, + False, + mock.ANY, + mock.ANY, + mock.ANY, + {'filter': {}}, + mock.ANY, + mock.ANY, + mock.ANY, + [], + {'op': 'build', 'test': mock.ANY}, + 'success', + mock.ANY, + 0, + None + ), + ( + {'op': 'build'}, + mock.ANY, + None, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + None, + mock.ANY, + mock.ANY, + ['build test: dummy instance name'], + {'op': 'report', 'test': mock.ANY}, + 'error', + 'Build Failure', + 0, + None + ), + ( + {'op': 'build'}, + 'skipped', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + {'returncode': 0}, + mock.ANY, + mock.ANY, + ['build test: dummy instance name', + 'Determine test cases for test instance: dummy instance name'], + {'op': 'gather_metrics', 'test': mock.ANY}, + mock.ANY, + mock.ANY, + 1, + ('skipped', mock.ANY) + ), + ( + {'op': 'build'}, + 'passed', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + {'dummy': 'dummy'}, + mock.ANY, + mock.ANY, + ['build test: dummy instance name'], + {'op': 'report', 'test': mock.ANY}, + 'passed', + mock.ANY, + 0, + ('blocked', mock.ANY) + ), + ( + {'op': 'build'}, + 'success', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + {'returncode': 0}, + mock.ANY, + mock.ANY, + ['build test: dummy instance name', + 'Determine test cases for test instance: dummy instance name'], + {'op': 'gather_metrics', 'test': mock.ANY}, + mock.ANY, + mock.ANY, + 0, + None + ), + ( + {'op': 'build'}, + 'success', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + {'returncode': 0}, + mock.ANY, + BuildError, + ['build test: dummy instance name', + 'Determine test cases for test instance: dummy instance name'], + {'op': 'report', 'test': mock.ANY}, + 'error', + 'Determine Testcases Error!', + 0, + None + ), + ( + {'op': 'gather_metrics'}, + mock.ANY, + mock.ANY, + True, + True, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + [], + {'op': 'run', 'test': mock.ANY}, + mock.ANY, + mock.ANY, + 0, + None + ), + ( + {'op': 'gather_metrics'}, + mock.ANY, + mock.ANY, + False, + True, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + [], + {'op': 'report', 'test': mock.ANY}, + mock.ANY, + mock.ANY, + 0, + None + ), + ( + {'op': 'run'}, + 'success', + 'OK', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + None, + mock.ANY, + ['run test: dummy instance name', + 'run status: dummy instance name success'], + {'op': 'report', 'test': mock.ANY, 'status': 'success', 'reason': 'OK'}, + 'success', + 'OK', + 0, + None + ), + ( + {'op': 'run'}, + 'failed', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + RuntimeError, + mock.ANY, + ['run test: dummy instance name', + 'run status: dummy instance name failed', + 'RuntimeError: Pipeline Error!'], + None, + 'failed', + mock.ANY, + 0, + None + ), + ( + {'op': 'report'}, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + False, + True, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + [], + {'op': 'cleanup', 'mode': 'device', 'test': mock.ANY}, + mock.ANY, + mock.ANY, + 0, + None + ), + ( + {'op': 'report'}, + 'passed', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + False, + False, + 'pass', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + [], + {'op': 'cleanup', 'mode': 'passed', 'test': mock.ANY}, + mock.ANY, + mock.ANY, + 0, + None + ), + ( + {'op': 'report'}, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + False, + False, + 'all', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + [], + {'op': 'cleanup', 'mode': 'all', 'test': mock.ANY}, + mock.ANY, + mock.ANY, + 0, + None + ), + ( + {'op': 'report'}, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + False, + False, + 'other', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + [], + None, + mock.ANY, + mock.ANY, + 0, + None + ), + ( + {'op': 'cleanup', 'mode': 'device'}, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + [], + None, + mock.ANY, + mock.ANY, + 0, + None + ), + ( + {'op': 'cleanup', 'mode': 'passed'}, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + [], + None, + mock.ANY, + mock.ANY, + 0, + None + ), + ( + {'op': 'cleanup', 'mode': 'all'}, + mock.ANY, + 'Valgrind error', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + [], + None, + mock.ANY, + mock.ANY, + 0, + None + ), + ( + {'op': 'cleanup', 'mode': 'all'}, + mock.ANY, + 'Cmake build failure', + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + [], + None, + mock.ANY, + mock.ANY, + 0, + None + ), +] + +@pytest.mark.parametrize( + 'message,' \ + ' instance_status, instance_reason, instance_run, instance_handler_ready,' \ + ' options_cmake_only,' \ + ' options_coverage, options_prep_artifacts, options_runtime_artifacts,' \ + ' cmake_res, build_res,' \ + ' pipeline_runtime_error, determine_testcases_build_error,' \ + ' expected_logs, resulting_message,' \ + ' expected_status, expected_reason, expected_skipped, expected_missing', + TESTDATA_6, + ids=[ + 'filter, failed', 'filter, cmake res', 'filter, no cmake res', + 'cmake, failed', 'cmake, cmake_only, no status', 'cmake, cmake_only', + 'cmake, no cmake_only, cmake res', 'cmake, no cmake_only, no cmake res', + 'build, no build res', 'build, skipped', 'build, blocked', + 'build, determine testcases', 'build, determine testcases Error', + 'gather metrics, run and ready handler', 'gather metrics', + 'run', 'run, Pipeline Runtime Error', + 'report, prep artifacts for testing', + 'report, runtime artifact cleanup pass, status passed', + 'report, runtime artifact cleanup all', 'report, no message put', + 'cleanup, device', 'cleanup, mode passed', 'cleanup, mode all', + 'cleanup, mode all, cmake build failure' + ] +) +def test_projectbuilder_process( + caplog, + mocked_jobserver, + message, + instance_status, + instance_reason, + instance_run, + instance_handler_ready, + options_cmake_only, + options_coverage, + options_prep_artifacts, + options_runtime_artifacts, + cmake_res, + build_res, + pipeline_runtime_error, + determine_testcases_build_error, + expected_logs, + resulting_message, + expected_status, + expected_reason, + expected_skipped, + expected_missing +): + def mock_pipeline_put(msg): + if isinstance(pipeline_runtime_error, type) and \ + issubclass(pipeline_runtime_error, Exception): + raise RuntimeError('Pipeline Error!') + + def mock_determine_testcases(res): + if isinstance(determine_testcases_build_error, type) and \ + issubclass(determine_testcases_build_error, Exception): + raise BuildError('Determine Testcases Error!') + + instance_mock = mock.Mock() + instance_mock.name = 'dummy instance name' + instance_mock.status = instance_status + instance_mock.reason = instance_reason + instance_mock.run = instance_run + instance_mock.handler = mock.Mock() + instance_mock.handler.ready = instance_handler_ready + env_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + pb.options = mock.Mock() + pb.options.coverage = options_coverage + pb.options.prep_artifacts_for_testing = options_prep_artifacts + pb.options.runtime_artifact_cleanup = options_runtime_artifacts + pb.options.cmake_only = options_cmake_only + + pb.cmake = mock.Mock(return_value=cmake_res) + pb.build = mock.Mock(return_value=build_res) + pb.determine_testcases = mock.Mock(side_effect=mock_determine_testcases) + + pb.report_out = mock.Mock() + pb.cleanup_artifacts = mock.Mock() + pb.cleanup_device_testing_artifacts = mock.Mock() + pb.run = mock.Mock() + pb.gather_metrics = mock.Mock() + + pipeline_mock = mock.Mock(put=mock.Mock(side_effect=mock_pipeline_put)) + done_mock = mock.Mock() + lock_mock = mock.Mock( + __enter__=mock.Mock(return_value=(mock.Mock(), mock.Mock())), + __exit__=mock.Mock(return_value=None) + ) + results_mock = mock.Mock() + results_mock.skipped_runtime = 0 + + pb.process(pipeline_mock, done_mock, message, lock_mock, results_mock) + + assert all([log in caplog.text for log in expected_logs]) + + if resulting_message: + pipeline_mock.put.assert_called_with(resulting_message) + + assert pb.instance.status == expected_status + assert pb.instance.reason == expected_reason + assert results_mock.skipped_runtime == expected_skipped + + if expected_missing: + pb.instance.add_missing_case_status.assert_called_with(*expected_missing) + + +TESTDATA_7 = [ + ( + [ + 'z_ztest_unit_test__dummy_suite_name__dummy_test_name', + 'z_ztest_unit_test__dummy_suite_name__test_dummy_name', + 'no match' + ], + ['dummy_id.dummy_name', 'dummy_id.dummy_name'] + ), + ( + ['no match'], + [] + ), +] + +@pytest.mark.parametrize( + 'symbols_names, added_tcs', + TESTDATA_7, + ids=['two hits, one miss', 'nothing'] +) +def test_projectbuilder_determine_testcases( + mocked_jobserver, + symbols_names, + added_tcs +): + symbols_mock = [mock.Mock(n=name) for name in symbols_names] + for m in symbols_mock: + m.configure_mock(name=m.n) + + sections_mock = [mock.Mock(spec=SymbolTableSection)] + sections_mock[0].iter_symbols = mock.Mock(return_value=symbols_mock) + + elf_mock = mock.Mock() + elf_mock().iter_sections = mock.Mock(return_value=sections_mock) + + results_mock = mock.Mock() + + instance_mock = mock.Mock() + instance_mock.testcases = [] + instance_mock.testsuite.id = 'dummy_id' + env_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + + with mock.patch('twisterlib.runner.ELFFile', elf_mock), \ + mock.patch('builtins.open', mock.mock_open()): + pb.determine_testcases(results_mock) + + pb.instance.add_testcase.assert_has_calls( + [mock.call(name=x) for x in added_tcs] + ) + pb.instance.testsuite.add_testcase.assert_has_calls( + [mock.call(name=x) for x in added_tcs] + ) + + +TESTDATA_8 = [ + ( + ['addition.al'], + 'dummy', + ['addition.al', '.config', 'zephyr'] + ), + ( + [], + 'all', + ['.config', 'zephyr', 'testsuite_extra.conf', 'twister'] + ), +] + +@pytest.mark.parametrize( + 'additional_keep, runtime_artifact_cleanup, expected_files', + TESTDATA_8, + ids=['additional keep', 'all cleanup'] +) +def test_projectbuilder_cleanup_artifacts( + tmpdir, + mocked_jobserver, + additional_keep, + runtime_artifact_cleanup, + expected_files +): + # tmpdir + # ┣ twister + # ┃ ┗ testsuite_extra.conf + # ┣ dummy_dir + # ┃ ┗ dummy.del + # ┣ dummy_link_dir -> zephyr + # ┣ zephyr + # ┃ ┗ .config + # ┗ addition.al + twister_dir = tmpdir.mkdir('twister') + testsuite_extra_conf = twister_dir.join('testsuite_extra.conf') + testsuite_extra_conf.write_text('dummy', 'utf-8') + + dummy_dir = tmpdir.mkdir('dummy_dir') + dummy_del = dummy_dir.join('dummy.del') + dummy_del.write_text('dummy', 'utf-8') + + zephyr = tmpdir.mkdir('zephyr') + config = zephyr.join('.config') + config.write_text('dummy', 'utf-8') + + dummy_link_dir = tmpdir.join('dummy_link_dir') + os.symlink(zephyr, dummy_link_dir) + + addition_al = tmpdir.join('addition.al') + addition_al.write_text('dummy', 'utf-8') + + instance_mock = mock.Mock() + instance_mock.build_dir = tmpdir + env_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + pb.options = mock.Mock(runtime_artifact_cleanup=runtime_artifact_cleanup) + + pb.cleanup_artifacts(additional_keep) + + files_left = [p.name for p in list(pathlib.Path(tmpdir).glob('**/*'))] + + assert sorted(files_left) == sorted(expected_files) + + +def test_projectbuilder_cleanup_device_testing_artifacts( + caplog, + mocked_jobserver +): + bins = [os.path.join('zephyr', 'file.bin')] + + instance_mock = mock.Mock() + build_dir = os.path.join('build', 'dir') + instance_mock.build_dir = build_dir + env_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + pb._get_binaries = mock.Mock(return_value=bins) + pb.cleanup_artifacts = mock.Mock() + pb._sanitize_files = mock.Mock() + + pb.cleanup_device_testing_artifacts() + + assert f'Cleaning up for Device Testing {build_dir}' in caplog.text + + pb.cleanup_artifacts.assert_called_once_with( + [os.path.join('zephyr', 'file.bin'), + os.path.join('zephyr', 'runners.yaml')] + ) + pb._sanitize_files.assert_called_once() + + +TESTDATA_9 = [ + ( + None, + [], + [os.path.join('zephyr', 'zephyr.hex'), + os.path.join('zephyr', 'zephyr.bin'), + os.path.join('zephyr', 'zephyr.elf'), + os.path.join('zephyr', 'zephyr.exe')] + ), + ( + [os.path.join('dummy.bin'), os.path.join('dummy.hex')], + [os.path.join('dir2', 'dummy.elf')], + [os.path.join('zephyr', 'dummy.bin'), + os.path.join('zephyr', 'dummy.hex'), + os.path.join('dir2', 'dummy.elf')] + ), +] + +@pytest.mark.parametrize( + 'platform_binaries, runner_binaries, expected_binaries', + TESTDATA_9, + ids=['default', 'valid'] +) +def test_projectbuilder_get_binaries( + mocked_jobserver, + platform_binaries, + runner_binaries, + expected_binaries +): + instance_mock = mock.Mock() + instance_mock.platform = mock.Mock() + instance_mock.platform.binaries = platform_binaries + env_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + pb._get_binaries_from_runners = mock.Mock(return_value=runner_binaries) + + bins = pb._get_binaries() + + assert all(bin in expected_binaries for bin in bins) + assert all(bin in bins for bin in expected_binaries) + + +TESTDATA_10 = [ + (None, []), + ({'dummy': 'dummy'}, []), + ( + { + 'config': { + 'elf_file': '/absolute/path/dummy.elf', + 'bin_file': 'path/dummy.bin' + } + }, + ['/absolute/path/dummy.elf', os.path.join('zephyr', 'path/dummy.bin')] + ), +] + +@pytest.mark.parametrize( + 'runners_content, expected_binaries', + TESTDATA_10, + ids=['no file', 'no config', 'valid'] +) +def test_projectbuilder_get_binaries_from_runners( + mocked_jobserver, + runners_content, + expected_binaries +): + def mock_exists(fname): + assert fname == os.path.join('build', 'dir', 'zephyr', 'runners.yaml') + return runners_content is not None + + instance_mock = mock.Mock() + instance_mock.build_dir = os.path.join('build', 'dir') + env_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + + with mock.patch('os.path.exists', mock_exists), \ + mock.patch('builtins.open', mock.mock_open()), \ + mock.patch('yaml.safe_load', return_value=runners_content): + bins = pb._get_binaries_from_runners() + + assert all(bin in expected_binaries for bin in bins) + assert all(bin in bins for bin in expected_binaries) + + +def test_projectbuilder_sanitize_files(mocked_jobserver): + instance_mock = mock.Mock() + env_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + pb._sanitize_runners_file = mock.Mock() + pb._sanitize_zephyr_base_from_files = mock.Mock() + + pb._sanitize_files() + + pb._sanitize_runners_file.assert_called_once() + pb._sanitize_zephyr_base_from_files.assert_called_once() + + + +TESTDATA_11 = [ + (None, None), + ('dummy: []', None), + ( +""" +config: + elf_file: relative/path/dummy.elf + hex_file: /absolute/path/build_dir/zephyr/dummy.hex +""", +""" +config: + elf_file: relative/path/dummy.elf + hex_file: dummy.hex +""" + ), +] + +@pytest.mark.parametrize( + 'runners_text, expected_write_text', + TESTDATA_11, + ids=['no file', 'no config', 'valid'] +) +def test_projectbuilder_sanitize_runners_file( + mocked_jobserver, + runners_text, + expected_write_text +): + def mock_exists(fname): + return runners_text is not None + + instance_mock = mock.Mock() + instance_mock.build_dir = '/absolute/path/build_dir' + env_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + + with mock.patch('os.path.exists', mock_exists), \ + mock.patch('builtins.open', + mock.mock_open(read_data=runners_text)) as f: + pb._sanitize_runners_file() + + if expected_write_text is not None: + f().write.assert_called_with(expected_write_text) + else: + f().write.assert_not_called() + + +TESTDATA_12 = [ + ( + { + 'CMakeCache.txt': mock.mock_open( + read_data='canonical/zephyr/base/dummy.file: ERROR' + ) + }, + { + 'CMakeCache.txt': 'dummy.file: ERROR' + } + ), + ( + { + os.path.join('zephyr', 'runners.yaml'): mock.mock_open( + read_data='There was canonical/zephyr/base/dummy.file here' + ) + }, + { + os.path.join('zephyr', 'runners.yaml'): 'There was dummy.file here' + } + ), +] + +@pytest.mark.parametrize( + 'text_mocks, expected_write_texts', + TESTDATA_12, + ids=['CMakeCache file', 'runners.yaml file'] +) +def test_projectbuilder_sanitize_zephyr_base_from_files( + mocked_jobserver, + text_mocks, + expected_write_texts +): + build_dir_path = 'canonical/zephyr/base/build_dir/' + + def mock_exists(fname): + if not fname.startswith(build_dir_path): + return False + return fname[len(build_dir_path):] in text_mocks + + def mock_open(fname, *args, **kwargs): + if not fname.startswith(build_dir_path): + raise FileNotFoundError(errno.ENOENT, f'File {fname} not found.') + return text_mocks[fname[len(build_dir_path):]]() + + instance_mock = mock.Mock() + instance_mock.build_dir = build_dir_path + env_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + + with mock.patch('os.path.exists', mock_exists), \ + mock.patch('builtins.open', mock_open), \ + mock.patch('twisterlib.runner.canonical_zephyr_base', + 'canonical/zephyr/base'): + pb._sanitize_zephyr_base_from_files() + + for fname, fhandler in text_mocks.items(): + fhandler().write.assert_called_with(expected_write_texts[fname]) + + +TESTDATA_13 = [ + ( + 'error', True, True, False, + ['INFO 20/25 dummy platform' \ + ' dummy.testsuite.name' \ + ' ERROR dummy reason (cmake)'], + None + ), + ( + 'failed', False, False, False, + ['ERROR dummy platform' \ + ' dummy.testsuite.name' \ + ' FAILED : dummy reason'], + 'INFO - Total complete: 20/ 25 80% skipped: 3,' \ + ' failed: 3, error: 1' + ), + ( + 'skipped', True, False, False, + ['INFO 20/25 dummy platform' \ + ' dummy.testsuite.name' \ + ' SKIPPED (dummy reason)'], + None + ), + ( + 'filtered', False, False, False, + [], + 'INFO - Total complete: 20/ 25 80% skipped: 4,' \ + ' failed: 2, error: 1' + ), + ( + 'passed', True, False, True, + ['INFO 20/25 dummy platform' \ + ' dummy.testsuite.name' \ + ' PASSED' \ + ' (dummy handler type: dummy dut, 60.000s)'], + None + ), + ( + 'passed', True, False, False, + ['INFO 20/25 dummy platform' \ + ' dummy.testsuite.name' \ + ' PASSED (build)'], + None + ), + ( + 'unknown status', False, False, False, + ['Unknown status = unknown status'], + 'INFO - Total complete: 20/ 25 80% skipped: 3,' \ + ' failed: 2, error: 1\r' + ), + ( + 'timeout', True, False, True, + ['INFO 20/25 dummy platform' \ + ' dummy.testsuite.name' \ + ' UNKNOWN' \ + ' (dummy handler type: dummy dut, 60.000s/seed: 123)'], + None + ), +] + +@pytest.mark.parametrize( + 'status, verbose, cmake_only, ready_run, expected_logs, expected_out', + TESTDATA_13, + ids=['verbose error cmake only', 'failed', 'verbose skipped', 'filtered', + 'verbose passed ready run', 'verbose passed', 'unknown status', + 'timeout'] +) +def test_projectbuilder_report_out( + capfd, + caplog, + mocked_jobserver, + status, + verbose, + cmake_only, + ready_run, + expected_logs, + expected_out +): + instance_mock = mock.Mock() + instance_mock.handler.type_str = 'dummy handler type' + instance_mock.handler.seed = 123 + instance_mock.handler.ready = ready_run + instance_mock.run = ready_run + instance_mock.dut = 'dummy dut' + instance_mock.execution_time = 60 + instance_mock.platform.name = 'dummy platform' + instance_mock.status = status + instance_mock.reason = 'dummy reason' + instance_mock.testsuite.name = 'dummy.testsuite.name' + instance_mock.testsuite.testcases = [mock.Mock() for _ in range(25)] + instance_mock.testcases = [mock.Mock() for _ in range(24)] + \ + [mock.Mock(status='skipped')] + env_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + pb.options.verbose = verbose + pb.options.cmake_only = cmake_only + pb.options.seed = 123 + pb.log_info_file = mock.Mock() + + results_mock = mock.Mock() + results_mock.iteration = 1 + results_mock.total = 25 + results_mock.done = 19 + results_mock.passed = 17 + results_mock.skipped_configs = 3 + results_mock.skipped_cases = 4 + results_mock.failed = 2 + results_mock.error = 1 + results_mock.cases = 0 + + pb.report_out(results_mock) + + assert results_mock.cases == 25 + + trim_actual_log = re.sub( + r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])', + '', + caplog.text + ) + trim_actual_log = re.sub(r'twister:runner.py:\d+', '', trim_actual_log) + assert all([log in trim_actual_log for log in expected_logs]) + + if expected_out: + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + # Remove 7b ANSI C1 escape sequences (colours) + out = re.sub( + r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])', + '', + out + ) + + assert expected_out in out + + +def test_projectbuilder_cmake_assemble_args(): + extra_args = ['CONFIG_FOO=y', 'DUMMY_EXTRA="yes"'] + handler = mock.Mock(ready=True, args=['dummy_handler']) + extra_conf_files = ['extrafile1.conf', 'extrafile2.conf'] + extra_overlay_confs = ['extra_overlay_conf'] + extra_dtc_overlay_files = ['overlay1.dtc', 'overlay2.dtc'] + cmake_extra_args = ['CMAKE1="yes"', 'CMAKE2=n'] + build_dir = os.path.join('build', 'dir') + + with mock.patch('os.path.exists', return_value=True): + results = ProjectBuilder.cmake_assemble_args(extra_args, handler, + extra_conf_files, + extra_overlay_confs, + extra_dtc_overlay_files, + cmake_extra_args, + build_dir) + + expected_results = [ + '-DCONFIG_FOO=y', + '-DCMAKE1=\"yes\"', + '-DCMAKE2=n', + '-DDUMMY_EXTRA=yes', + '-Ddummy_handler', + '-DCONF_FILE=extrafile1.conf;extrafile2.conf', + '-DDTC_OVERLAY_FILE=overlay1.dtc;overlay2.dtc', + f'-DOVERLAY_CONFIG=extra_overlay_conf ' \ + f'{os.path.join("build", "dir", "twister", "testsuite_extra.conf")}' + ] + + assert results == expected_results + + +def test_projectbuilder_cmake(): + instance_mock = mock.Mock() + instance_mock.handler = 'dummy handler' + instance_mock.build_dir = os.path.join('build', 'dir') + env_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + pb.build_dir = 'build_dir' + pb.testsuite.extra_args = ['some', 'args'] + pb.testsuite.extra_conf_files = ['some', 'files1'] + pb.testsuite.extra_overlay_confs = ['some', 'files2'] + pb.testsuite.extra_dtc_overlay_files = ['some', 'files3'] + pb.options.extra_args = ['other', 'args'] + pb.cmake_assemble_args = mock.Mock(return_value=['dummy']) + cmake_res_mock = mock.Mock() + pb.run_cmake = mock.Mock(return_value=cmake_res_mock) + + res = pb.cmake(['dummy filter']) + + assert res == cmake_res_mock + pb.cmake_assemble_args.assert_called_once_with( + pb.testsuite.extra_args, + pb.instance.handler, + pb.testsuite.extra_conf_files, + pb.testsuite.extra_overlay_confs, + pb.testsuite.extra_dtc_overlay_files, + pb.options.extra_args, + pb.instance.build_dir + ) + pb.run_cmake.assert_called_once_with(['dummy'], ['dummy filter']) + + +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) + + pb.build_dir = 'build_dir' + pb.run_build = mock.Mock(return_value={'dummy': 'dummy'}) + + res = pb.build() + + pb.run_build.assert_called_once_with(['--build', 'build_dir']) + assert res == {'dummy': 'dummy'} + + +TESTDATA_14 = [ + ( + True, + 'device', + 234, + 'native_sim', + 'posix', + {'CONFIG_FAKE_ENTROPY_NATIVE_POSIX': 'y'}, + 'pytest', + True, + True, + True, + True, + True, + False + ), + ( + True, + 'not device', + None, + 'native_sim', + 'not posix', + {'CONFIG_FAKE_ENTROPY_NATIVE_POSIX': 'y'}, + 'not pytest', + False, + False, + False, + False, + False, + True + ), + ( + False, + 'device', + 234, + 'native_sim', + 'posix', + {'CONFIG_FAKE_ENTROPY_NATIVE_POSIX': 'y'}, + 'pytest', + False, + False, + False, + False, + False, + False + ), +] + +@pytest.mark.parametrize( + 'ready, type_str, seed, platform_name, platform_arch, defconfig, harness,' \ + ' expect_duts, expect_parse_generated, expect_seed,' \ + ' expect_extra_test_args, expect_pytest, expect_handle', + TESTDATA_14, + ids=['pytest full', 'not pytest minimal', 'not ready'] +) +def test_projectbuilder_run( + mocked_jobserver, + ready, + type_str, + seed, + platform_name, + platform_arch, + defconfig, + harness, + expect_duts, + expect_parse_generated, + expect_seed, + expect_extra_test_args, + expect_pytest, + expect_handle +): + pytest_mock = mock.Mock(spec=Pytest) + harness_mock = mock.Mock() + + def mock_harness(name): + if name == 'Pytest': + return pytest_mock + else: + return harness_mock + + instance_mock = mock.Mock() + instance_mock.handler.get_test_timeout = mock.Mock(return_value=60) + instance_mock.handler.seed = 123 + instance_mock.handler.ready = ready + instance_mock.handler.type_str = type_str + instance_mock.handler.duts = [mock.Mock(name='dummy dut')] + instance_mock.platform.name = platform_name + instance_mock.platform.arch = platform_arch + instance_mock.testsuite.harness = harness + env_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + pb.options.extra_test_args = ['dummy_arg1', 'dummy_arg2'] + pb.duts = ['another dut'] + pb.options.seed = seed + pb.defconfig = defconfig + pb.parse_generated = mock.Mock() + + with mock.patch('twisterlib.runner.HarnessImporter.get_harness', + mock_harness): + pb.run() + + if expect_duts: + assert pb.instance.handler.duts == ['another dut'] + + if expect_parse_generated: + pb.parse_generated.assert_called_once() + + if expect_seed: + assert pb.instance.handler.seed == seed + + if expect_extra_test_args: + assert pb.instance.handler.extra_test_args == ['dummy_arg1', + 'dummy_arg2'] + + if expect_pytest: + pytest_mock.pytest_run.assert_called_once_with(60) + + if expect_handle: + pb.instance.handler.handle.assert_called_once_with(harness_mock) + + +TESTDATA_15 = [ + (False, False, False, True), + (True, False, True, False), + (False, True, False, True), + (True, True, False, True), +] + +@pytest.mark.parametrize( + 'enable_size_report, cmake_only, expect_calc_size, expect_zeroes', + TESTDATA_15, + ids=['none', 'size_report', 'cmake', 'size_report+cmake'] +) +def test_projectbuilder_gather_metrics( + mocked_jobserver, + enable_size_report, + cmake_only, + expect_calc_size, + expect_zeroes +): + instance_mock = mock.Mock() + instance_mock.metrics = {} + env_mock = mock.Mock() + + pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) + pb.options.enable_size_report = enable_size_report + pb.options.create_rom_ram_report = False + pb.options.cmake_only = cmake_only + pb.calc_size = mock.Mock() + + pb.gather_metrics(instance_mock) + + if expect_calc_size: + pb.calc_size.assert_called_once() + + if expect_zeroes: + assert instance_mock.metrics['used_ram'] == 0 + assert instance_mock.metrics['used_rom'] == 0 + assert instance_mock.metrics['available_rom'] == 0 + assert instance_mock.metrics['available_ram'] == 0 + assert instance_mock.metrics['unrecognized'] == [] + + +TESTDATA_16 = [ + ('error', mock.ANY, False, False, False), + ('failed', mock.ANY, False, False, False), + ('skipped', mock.ANY, False, False, False), + ('filtered', 'native', False, False, True), + ('passed', 'qemu', False, False, True), + ('filtered', 'unit', False, False, True), + ('filtered', 'mcu', True, True, False), + ('passed', 'frdm_k64f', False, True, False), +] + +@pytest.mark.parametrize( + 'status, platform_type, expect_warnings, expect_calcs, expect_zeroes', + TESTDATA_16, + ids=[x[0] + (', ' + x[1]) if x[1] != mock.ANY else '' for x in TESTDATA_16] +) +def test_projectbuilder_calc_size( + status, + platform_type, + expect_warnings, + expect_calcs, + expect_zeroes +): + size_calc_mock = mock.Mock() + + instance_mock = mock.Mock() + instance_mock.status = status + instance_mock.platform.type = platform_type + instance_mock.metrics = {} + instance_mock.calculate_sizes = mock.Mock(return_value=size_calc_mock) + + from_buildlog = True + + ProjectBuilder.calc_size(instance_mock, from_buildlog) + + if expect_calcs: + instance_mock.calculate_sizes.assert_called_once_with( + from_buildlog=from_buildlog, + generate_warning=expect_warnings + ) + + assert instance_mock.metrics['used_ram'] == \ + size_calc_mock.get_used_ram() + assert instance_mock.metrics['used_rom'] == \ + size_calc_mock.get_used_rom() + assert instance_mock.metrics['available_rom'] == \ + size_calc_mock.get_available_rom() + assert instance_mock.metrics['available_ram'] == \ + size_calc_mock.get_available_ram() + assert instance_mock.metrics['unrecognized'] == \ + size_calc_mock.unrecognized_sections() + + if expect_zeroes: + assert instance_mock.metrics['used_ram'] == 0 + assert instance_mock.metrics['used_rom'] == 0 + assert instance_mock.metrics['available_rom'] == 0 + assert instance_mock.metrics['available_ram'] == 0 + assert instance_mock.metrics['unrecognized'] == [] + + if expect_calcs or expect_zeroes: + assert instance_mock.metrics['handler_time'] == \ + instance_mock.execution_time + else: + assert instance_mock.metrics == {} + + +TESTDATA_17 = [ + ('linux', 'posix', {'jobs': 4}, True, 32, 'GNUMakeJobClient'), + ('linux', 'posix', {'build_only': True}, False, 16, 'GNUMakeJobServer'), + ('linux', '???', {}, False, 8, 'JobClient'), + ('linux', '???', {'jobs': 4}, False, 4, 'JobClient'), +] + +@pytest.mark.parametrize( + 'platform, os_name, options, jobclient_from_environ, expected_jobs,' \ + ' expected_jobserver', + TESTDATA_17, + ids=['GNUMakeJobClient', 'GNUMakeJobServer', + 'JobClient', 'Jobclient+options'] +) +def test_twisterrunner_run( + caplog, + platform, + os_name, + options, + jobclient_from_environ, + expected_jobs, + expected_jobserver +): + def mock_client_from_environ(jobs): + if jobclient_from_environ: + jobclient_mock = mock.Mock(jobs=32) + jobclient_mock.name = 'GNUMakeJobClient' + return jobclient_mock + return None + + instances = {'dummy instance': mock.Mock(metrics={'k': 'v'})} + suites = [mock.Mock()] + env_mock = mock.Mock() + + tr = TwisterRunner(instances, suites, env=env_mock) + tr.options.retry_failed = 2 + tr.options.retry_interval = 10 + tr.options.retry_build_errors = True + tr.options.jobs = None + tr.options.build_only = None + for k, v in options.items(): + setattr(tr.options, k, v) + tr.update_counting_before_pipeline = mock.Mock() + tr.execute = mock.Mock() + tr.show_brief = mock.Mock() + + gnumakejobserver_mock = mock.Mock() + gnumakejobserver_mock().name='GNUMakeJobServer' + jobclient_mock = mock.Mock() + jobclient_mock().name='JobClient' + + pipeline_q = queue.LifoQueue() + done_q = queue.LifoQueue() + done_instance = mock.Mock( + metrics={'k2': 'v2'}, + execution_time=30 + ) + done_instance.name='dummy instance' + done_q.put(done_instance) + manager_mock = mock.Mock() + manager_mock().LifoQueue = mock.Mock( + side_effect=iter([pipeline_q, done_q]) + ) + + results_mock = mock.Mock() + results_mock().error = 1 + results_mock().iteration = 0 + results_mock().failed = 2 + results_mock().total = 9 + + with mock.patch('twisterlib.runner.ExecutionCounter', results_mock), \ + mock.patch('twisterlib.runner.BaseManager', manager_mock), \ + mock.patch('twisterlib.runner.GNUMakeJobClient.from_environ', + mock_client_from_environ), \ + mock.patch('twisterlib.runner.GNUMakeJobServer', + gnumakejobserver_mock), \ + mock.patch('twisterlib.runner.JobClient', jobclient_mock), \ + mock.patch('multiprocessing.cpu_count', return_value=8), \ + mock.patch('sys.platform', platform), \ + mock.patch('time.sleep', mock.Mock()), \ + mock.patch('os.name', os_name): + tr.run() + + assert f'JOBS: {expected_jobs}' in caplog.text + + assert tr.jobserver.name == expected_jobserver + + assert tr.instances['dummy instance'].metrics == { + 'k': 'v', + 'k2': 'v2', + 'handler_time': 30, + 'unrecognized': [] + } + + assert results_mock().error == 0 + + +def test_twisterrunner_update_counting_before_pipeline(): + instances = { + 'dummy1': mock.Mock( + status='filtered', + reason='runtime filter', + testsuite=mock.Mock( + testcases=[mock.Mock()] + ) + ), + 'dummy2': mock.Mock( + status='filtered', + reason='static filter', + testsuite=mock.Mock( + testcases=[mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock()] + ) + ), + 'dummy3': mock.Mock( + status='error', + reason='error', + testsuite=mock.Mock( + testcases=[mock.Mock()] + ) + ), + 'dummy4': mock.Mock( + status='passed', + reason='OK', + testsuite=mock.Mock( + testcases=[mock.Mock()] + ) + ), + 'dummy5': mock.Mock( + status='skipped', + reason=None, + testsuite=mock.Mock( + testcases=[mock.Mock()] + ) + ) + } + suites = [mock.Mock()] + env_mock = mock.Mock() + + tr = TwisterRunner(instances, suites, env=env_mock) + tr.results = mock.Mock( + skipped_filter = 0, + skipped_configs = 0, + skipped_cases = 0, + cases = 0, + error = 0 + ) + + tr.update_counting_before_pipeline() + + assert tr.results.skipped_filter == 1 + assert tr.results.skipped_configs == 1 + assert tr.results.skipped_cases == 4 + assert tr.results.cases == 4 + assert tr.results.error == 1 + + +def test_twisterrunner_show_brief(caplog): + instances = { + 'dummy1': mock.Mock(), + 'dummy2': mock.Mock(), + 'dummy3': mock.Mock(), + 'dummy4': mock.Mock(), + 'dummy5': mock.Mock() + } + suites = [mock.Mock(), mock.Mock()] + env_mock = mock.Mock() + + tr = TwisterRunner(instances, suites, env=env_mock) + tr.results = mock.Mock( + skipped_filter = 3, + skipped_configs = 4, + skipped_cases = 0, + cases = 0, + error = 0 + ) + + tr.show_brief() + + log = '2 test scenarios (5 test instances) selected,' \ + ' 4 configurations skipped (3 by static filter, 1 at runtime).' + + assert log in caplog.text + + +TESTDATA_18 = [ + (False, False, False, [{'op': 'cmake', 'test': mock.ANY}]), + (False, False, True, [{'op': 'filter', 'test': mock.ANY}, + {'op': 'cmake', 'test': mock.ANY}]), + (False, True, True, [{'op': 'run', 'test': mock.ANY}, + {'op': 'run', 'test': mock.ANY}]), + (False, True, False, [{'op': 'run', 'test': mock.ANY}]), + (True, True, False, [{'op': 'cmake', 'test': mock.ANY}]), + (True, True, True, [{'op': 'filter', 'test': mock.ANY}, + {'op': 'cmake', 'test': mock.ANY}]), + (True, False, True, [{'op': 'filter', 'test': mock.ANY}, + {'op': 'cmake', 'test': mock.ANY}]), + (True, False, False, [{'op': 'cmake', 'test': mock.ANY}]), +] + +@pytest.mark.parametrize( + 'build_only, test_only, retry_build_errors, expected_pipeline_elements', + TESTDATA_18, + ids=['none', 'retry', 'test+retry', 'test', 'build+test', + 'build+test+retry', 'build+retry', 'build'] +) +def test_twisterrunner_add_tasks_to_queue( + build_only, + test_only, + retry_build_errors, + expected_pipeline_elements +): + def mock_get_cmake_filter_stages(filter, keys): + return [filter] + + instances = { + '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' + suites = [mock.Mock(), mock.Mock()] + env_mock = mock.Mock() + + tr = TwisterRunner(instances, suites, env=env_mock) + tr.get_cmake_filter_stages = mock.Mock( + side_effect=mock_get_cmake_filter_stages + ) + + pipeline_mock = mock.Mock() + + tr.add_tasks_to_queue( + pipeline_mock, + build_only, + test_only, + retry_build_errors + ) + + assert all( + [build_only != instance.run for instance in instances.values()] + ) + + tr.get_cmake_filter_stages.assert_any_call('full', mock.ANY) + if retry_build_errors: + tr.get_cmake_filter_stages.assert_any_call('some', mock.ANY) + + print(pipeline_mock.put.call_args_list) + print([mock.call(el) for el in expected_pipeline_elements]) + + assert pipeline_mock.put.call_args_list == \ + [mock.call(el) for el in expected_pipeline_elements] + + +TESTDATA_19 = [ + ('linux'), + ('nt') +] + +@pytest.mark.parametrize( + 'platform', + TESTDATA_19, +) +def test_twisterrunner_pipeline_mgr(mocked_jobserver, platform): + counter = 0 + def mock_get_nowait(): + nonlocal counter + counter += 1 + if counter > 5: + raise queue.Empty() + return {'test': 'dummy'} + + instances = {} + suites = [] + env_mock = mock.Mock() + + tr = TwisterRunner(instances, suites, env=env_mock) + tr.jobserver = mock.Mock( + get_job=mock.Mock( + return_value=nullcontext() + ) + ) + + pipeline_mock = mock.Mock() + pipeline_mock.get_nowait = mock.Mock(side_effect=mock_get_nowait) + done_queue_mock = mock.Mock() + lock_mock = mock.Mock() + results_mock = mock.Mock() + + with mock.patch('sys.platform', platform), \ + mock.patch('twisterlib.runner.ProjectBuilder',\ + return_value=mock.Mock()) as pb: + tr.pipeline_mgr(pipeline_mock, done_queue_mock, lock_mock, results_mock) + + assert len(pb().process.call_args_list) == 5 + + if platform == 'linux': + tr.jobserver.get_job.assert_called_once() + + +def test_twisterrunner_execute(caplog): + counter = 0 + def mock_join(): + nonlocal counter + counter += 1 + if counter > 3: + raise KeyboardInterrupt() + + instances = {} + suites = [] + env_mock = mock.Mock() + + tr = TwisterRunner(instances, suites, env=env_mock) + tr.add_tasks_to_queue = mock.Mock() + tr.jobs = 5 + + process_mock = mock.Mock() + process_mock().join = mock.Mock(side_effect=mock_join) + pipeline_mock = mock.Mock() + done_mock = mock.Mock() + + with mock.patch('twisterlib.runner.Process', process_mock): + tr.execute(pipeline_mock, done_mock) + + assert 'Execution interrupted' in caplog.text + + assert len(process_mock().start.call_args_list) == 5 + assert len(process_mock().join.call_args_list) == 4 + assert len(process_mock().terminate.call_args_list) == 5 + + + +TESTDATA_20 = [ + ('', []), + ('not ARCH in ["x86", "arc"]', ['full']), + ('dt_dummy(x, y)', ['dts']), + ('not CONFIG_FOO', ['kconfig']), + ('dt_dummy and CONFIG_FOO', ['dts', 'kconfig']), +] + +@pytest.mark.parametrize( + 'filter, expected_result', + TESTDATA_20, + ids=['none', 'full', 'dts', 'kconfig', 'dts+kconfig'] +) +def test_twisterrunner_get_cmake_filter_stages(filter, expected_result): + result = TwisterRunner.get_cmake_filter_stages(filter, ['not', 'and']) + + assert sorted(result) == sorted(expected_result) diff --git a/scripts/tests/twister/test_testinstance.py b/scripts/tests/twister/test_testinstance.py index 823eaeb3393a402..52c51b2b278e90d 100644 --- a/scripts/tests/twister/test_testinstance.py +++ b/scripts/tests/twister/test_testinstance.py @@ -7,19 +7,23 @@ Tests for testinstance class """ +from contextlib import nullcontext import os import sys import pytest +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)), @@ -28,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, monkeypatch, 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 @@ -51,31 +71,56 @@ def test_check_build_or_run(class_testplan, monkeypatch, all_testsuites_dict, pl _, r = expected assert run == r - monkeypatch.setattr("os.name", "nt") - run = testinstance.check_runnable() - assert not run + with mock.patch('os.name', 'nt'): + 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 @@ -90,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) @@ -98,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 000000000000000..488c39ddf73139b --- /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 f825bc82710cae5..000000000000000 --- 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 f07980a19bce810..517af1a79b78c80 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 000000000000000..d7e4828350cf9a8 --- /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 000000000000000..635c696edf9d526 --- /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/scripts/tests/twister_blackbox/test_data/tests/always_build_error/dummy/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/always_build_error/dummy/prj.conf new file mode 100644 index 000000000000000..9467c2926896dd7 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/always_build_error/dummy/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y 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 000000000000000..6d3d4c636879c6d --- /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 000000000000000..af7ba6f7bd75b02 --- /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 000000000000000..635c696edf9d526 --- /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/scripts/tests/twister_blackbox/test_data/tests/always_fail/dummy/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/always_fail/dummy/prj.conf new file mode 100644 index 000000000000000..9467c2926896dd7 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/always_fail/dummy/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y 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 000000000000000..643b4301550f3c4 --- /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 000000000000000..af7ba6f7bd75b02 --- /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 000000000000000..635c696edf9d526 --- /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 000000000000000..9467c2926896dd7 --- /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 000000000000000..3eab5b76c152841 --- /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 000000000000000..3c758a33b518451 --- /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/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup1/prj.conf index 9228251051ec064..9467c2926896dd7 100644 --- a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup1/prj.conf +++ b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup1/prj.conf @@ -1,2 +1 @@ CONFIG_ZTEST=y -CONFIG_ZTEST_NEW_API=y 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 1e468dc9b97621d..5bd1d3d4b06f1ed 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/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup2/prj.conf index 9228251051ec064..9467c2926896dd7 100644 --- a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup2/prj.conf +++ b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup2/prj.conf @@ -1,2 +1 @@ CONFIG_ZTEST=y -CONFIG_ZTEST_NEW_API=y 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 35f48d68648d640..9bf2f04688522cb 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/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group2/prj.conf index 9228251051ec064..9467c2926896dd7 100644 --- a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group2/prj.conf +++ b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group2/prj.conf @@ -1,2 +1 @@ CONFIG_ZTEST=y -CONFIG_ZTEST_NEW_API=y 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 f0aa17acbde1e08..f53a0d299480fc0 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/dummy/device/group/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/dummy/device/group/prj.conf index 9228251051ec064..9467c2926896dd7 100644 --- a/scripts/tests/twister_blackbox/test_data/tests/dummy/device/group/prj.conf +++ b/scripts/tests/twister_blackbox/test_data/tests/dummy/device/group/prj.conf @@ -1,2 +1 @@ CONFIG_ZTEST=y -CONFIG_ZTEST_NEW_API=y 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 000000000000000..635c696edf9d526 --- /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 000000000000000..9467c2926896dd7 --- /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 000000000000000..3c250486af6590d --- /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 000000000000000..035c275de68f076 --- /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 000000000000000..635c696edf9d526 --- /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 000000000000000..9467c2926896dd7 --- /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 000000000000000..d896f500c9e4548 --- /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 000000000000000..a07e7e23347f358 --- /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 000000000000000..af5d30dddaa5808 --- /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 000000000000000..85cb726a3130cd1 --- /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 new file mode 100644 index 000000000000000..c1f6ff1eaf81053 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_hardwaremap.py @@ -0,0 +1,290 @@ +#!/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 sys + +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")) + +@mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) +class TestHardwaremap: + TESTDATA_1 = [ + ( + [ + 'ARM', + 'SEGGER', + 'MBED' + ], + [ + 'DAPLink CMSIS-DAP', + 'MBED CMSIS-DAP' + ], + [1234, 'abcd'], + 'pyocd' + ), + ( + [ + 'STMicroelectronics', + 'Atmel Corp.' + ], + [ + 'J-Link', + 'J-Link OB' + ], + [1234, 'abcd'], + 'jlink' + ), + ( + [ + 'Silicon Labs', + 'NXP Semiconductors', + 'Microchip Technology Inc.' + ], + [ + 'STM32 STLink', + '^XDS110.*', + 'STLINK-V3' + ], + [1234, 'abcd'], + 'openocd' + ), + ( + [ + 'FTDI', + 'Digilent', + 'Microsoft' + ], + [ + 'TTL232R-3V3', + 'MCP2200 USB Serial Port Emulator' + ], + [1234, 'abcd'], + 'dediprog' + ) + ] + TESTDATA_2 = [ + ( + 'FTDI', + 'DAPLink CMSIS-DAP', + 1234, + 'pyocd' + ) + ] + TESTDATA_3 = [ + ( + 'Texas Instruments', + 'DAPLink CMSIS-DAP', + 'abcd', 'las' + ), + ( + 'Texas Instruments', + 'DAPLink CMSIS-DAP', + 'abcd', 'dse0' + ) + ] + + @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( + ('manufacturer', 'product', 'serial', 'runner'), + TESTDATA_1, + ) + 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 = ['--outdir', out_path, '--generate-hardware-map', file_name] + + if os.path.exists(path): + os.remove(path) + + def mocked_comports(): + return [ + mock.Mock(device='/dev/ttyUSB23', + manufacturer=id_man, + product=id_pro, + serial_number=id_serial + ) + ] + + for id_man in manufacturer: + for id_pro in product: + for id_serial in serial: + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + mock.patch('serial.tools.list_ports.comports', + side_effect=mocked_comports), \ + 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(path) + + expected_data = '- connected: true\n' \ + f' id: {id_serial}\n' \ + ' platform: unknown\n' \ + f' product: {id_pro}\n' \ + f' runner: {runner}\n' \ + ' serial: /dev/ttyUSB23\n' + + load_data = open(path).read() + assert load_data == expected_data + + if os.path.exists(path): + os.remove(path) + + assert str(sys_exit.value) == '0' + clear_log_in_test() + + @pytest.mark.parametrize( + ('manufacturer', 'product', 'serial', 'runner'), + TESTDATA_2, + ) + 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 = ['--outdir', out_path, '--generate-hardware-map', file_name] + + if os.path.exists(path): + os.remove(path) + + def mocked_comports(): + return [ + mock.Mock(device='/dev/ttyUSB23', + manufacturer=manufacturer, + product=product, + serial_number=serial + ), + mock.Mock(device='/dev/ttyUSB24', + manufacturer=manufacturer, + product=product, + serial_number=serial + 1 + ), + mock.Mock(device='/dev/ttyUSB24', + manufacturer=manufacturer, + product=product, + serial_number=serial + 2 + ), + mock.Mock(device='/dev/ttyUSB25', + manufacturer=manufacturer, + product=product, + serial_number=serial + 3 + ) + ] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + mock.patch('serial.tools.list_ports.comports', + side_effect=mocked_comports), \ + 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(path) + + expected_data = '- connected: true\n' \ + f' id: {serial}\n' \ + ' platform: unknown\n' \ + f' product: {product}\n' \ + f' runner: {runner}\n' \ + ' serial: /dev/ttyUSB23\n' \ + '- connected: true\n' \ + f' id: {serial + 1}\n' \ + ' platform: unknown\n' \ + f' product: {product}\n' \ + f' runner: {runner}\n' \ + ' serial: /dev/ttyUSB24\n' \ + '- connected: true\n' \ + f' id: {serial + 2}\n' \ + ' platform: unknown\n' \ + f' product: {product}\n' \ + f' runner: {runner}\n' \ + ' serial: /dev/ttyUSB24\n' \ + '- connected: true\n' \ + f' id: {serial + 3}\n' \ + ' platform: unknown\n' \ + f' product: {product}\n' \ + f' runner: {runner}\n' \ + ' serial: /dev/ttyUSB25\n' + + load_data = open(path).read() + assert load_data == expected_data + + if os.path.exists(path): + os.remove(path) + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + ('manufacturer', 'product', 'serial', 'location'), + TESTDATA_3, + ) + 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 = ['--outdir', out_path, '--generate-hardware-map', file_name] + + if os.path.exists(path): + os.remove(path) + + def mocked_comports(): + return [ + mock.Mock(device='/dev/ttyUSB23', + manufacturer=manufacturer, + product=product, + serial_number=serial, + location=location + ) + ] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + mock.patch('serial.tools.list_ports.comports', + side_effect=mocked_comports), \ + 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(path) + + expected_data = '- connected: true\n' \ + f' id: {serial}\n' \ + ' platform: unknown\n' \ + f' product: {product}\n' \ + ' runner: pyocd\n' \ + ' serial: /dev/ttyUSB23\n' + expected_data2 = '[]\n' + + load_data = open(path).read() + if location.endswith('0'): + assert load_data == expected_data + else: + assert load_data == expected_data2 + if os.path.exists(path): + os.remove(path) + + assert str(sys_exit.value) == '0' diff --git a/scripts/tests/twister_blackbox/test_printouts.py b/scripts/tests/twister_blackbox/test_printouts.py index 333bf2a090a6bcd..a548137595b3638 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 a7f7d1c33ef162d..000000000000000 --- 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 000000000000000..56d1bc3e098b16f --- /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 000000000000000..eea5e70639455f4 --- /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 000000000000000..7316209b1af08d2 --- /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 f41349871ed6c7b..aa075beb7a1fbc1 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 @@ -142,15 +145,6 @@ pairs: not (right associative) all comparison operators (non-associative) - arch_allow, arch_exclude, platform_allow, platform_exclude - are all syntactic sugar for these expressions. For instance - - arch_exclude = x86 arc - - Is the same as: - - filter = not ARCH in ["x86", "arc"] - The ':' operator compiles the string argument as a regular expression, and then returns a true value only if the symbol's value in the environment matches. For example, if CONFIG_SOC="stm32f107xc" then @@ -159,6 +153,22 @@ pairs: Would match it. + Note that arch_allow, arch_exclude, platform_allow, platform_exclude + are not just syntactic sugar for filter expressions. For instance + + arch_exclude = x86 arc + + Can appear at first glance to have a similar effect to + + filter = not ARCH in ["x86", "arc"] + + but unlike "filter", these cause platforms to be filtered already during the testplan + generation. While "filter" does not exclue platforms at the testplan generation, and instead + relies on the result of running the build configuration stage. That is, to evaluate the filter + expression, cmake is run for that target, and then the filter evaluated as a gate for the + build and run steps. + Therefore filtering by using {platform|arch}_{exclude|allow} is much faster. + The set of test cases that actually run depends on directives in the testsuite files and options passed in on the command line. If there is any confusion, running with -v or examining the test plan report (testplan.json) diff --git a/scripts/utils/convert_guidelines.py b/scripts/utils/convert_guidelines.py new file mode 100755 index 000000000000000..a0530b9c7b4e1a7 --- /dev/null +++ b/scripts/utils/convert_guidelines.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2023 Baumer (www.baumer.com) +# SPDX-License-Identifier: Apache-2.0 + +"""This script converting the Zephyr coding guideline rst file to a output file, +or print the output to the console. Which than can be used by a tool which +needs to have that information in a specific format (e.g. for cppcheck). +Or simply use the rule list to generate a filter to suppress all other rules +used by default from such a tool. +""" + +import sys +import re +import argparse +from pathlib import Path + +class RuleFormatter: + """ + Base class for the different output formats + """ + def table_start_print(self, outputfile): + pass + def severity_print(self, outputfile, guideline_number, severity): + pass + def description_print(self, outputfile, guideline_number, description): + pass + def closing_print(self, outputfile): + pass + +class CppCheckFormatter(RuleFormatter): + """ + Formatter class to print the rules in a format which can be used by cppcheck + """ + def table_start_print(self, outputfile): + # Start search by cppcheck misra addon + print('Appendix A Summary of guidelines', file=outputfile) + + def severity_print(self, outputfile, guideline_number, severity): + print('Rule ' + guideline_number + ' ' + severity, file=outputfile) + + def description_print(self, outputfile, guideline_number, description): + print(description + '(Misra rule ' + guideline_number + ')', file=outputfile) + + def closing_print(self, outputfile): + # Make cppcheck happy by starting the appendix + print('Appendix B', file=outputfile) + print('', file=outputfile) + +def convert_guidelines(args): + inputfile = args.input + outputfile = sys.stdout + formatter = None + + # If the output is not empty, open the given file for writing + if args.output is not None: + outputfile = open(args.output, "w") + + try: + file_stream = open(inputfile, 'rt', errors='ignore') + except Exception: + print('Error opening ' + inputfile +'.') + sys.exit() + + # Set formatter according to the used format + if args.format == 'cppcheck': + formatter = CppCheckFormatter() + + # Search for table named Main rules + pattern_table_start = re.compile(r'.*list-table:: Main rules') + # Each Rule is a new table column so start with '[tab]* - Rule' + # Ignore directives here + pattern_new_line = re.compile(r'^ \* - Rule ([0-9]+.[0-9]+).*$') + # Each table column start with '[tab]- ' + pattern_new_col = re.compile(r'^ - (.*)$') + + table_start = False + guideline_number = '' + guideline_state = 0 + guideline_list = [] + + for line in file_stream: + + line = line.replace('\r', '').replace('\n', '') + + # Done if we find the Additional rules table start + if line.find('Additional rules') >= 0: + break + + if len(line) == 0: + continue + + if not table_start: + res = pattern_table_start.match(line) + if res: + table_start = True + formatter.table_start_print(outputfile) + continue + + res = pattern_new_line.match(line) + if res: + guideline_state = "severity" + guideline_number = res.group(1) + guideline_list.append(guideline_number) + continue + elif guideline_number == '': + continue + + res = pattern_new_col.match(line) + if res: + if guideline_state == "severity": + # Severity + formatter.severity_print(outputfile, guideline_number, res.group(1)) + guideline_state = "description" + continue + if guideline_state == "description": + # Description + formatter.description_print(outputfile, guideline_number, res.group(1)) + guideline_state = "None" + # We stop here for now, we do not handle the CERT C col + guideline_number = '' + continue + + formatter.closing_print(outputfile) + +if __name__ == "__main__": + supported_formats = ['cppcheck'] + + parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument( + "-i", "--input", metavar="RST_FILE", type=Path, required=True, + help="Path to rst input source file, where the guidelines are written down." + ) + parser.add_argument( + "-f", "--format", metavar="FORMAT", choices=supported_formats, required=True, + help="Format to convert guidlines to. Supported formats are: " + str(supported_formats) + ) + parser.add_argument( + "-o", "--output", metavar="OUTPUT_FILE", type=Path, required=False, + help="Path to output file, where the converted guidelines are written to. If outputfile is not specified, print to stdout." + ) + args = parser.parse_args() + + convert_guidelines(args) diff --git a/scripts/valgrind.supp b/scripts/valgrind.supp index b161e09fa01e873..330ec51fefd73b6 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/__init__.py b/scripts/west_commands/runners/__init__.py index f4340bc19b0b009..850efcd56686a1e 100644 --- a/scripts/west_commands/runners/__init__.py +++ b/scripts/west_commands/runners/__init__.py @@ -45,6 +45,7 @@ def _import_runner_module(runner_name): 'nrfjprog', 'nrfutil', 'nsim', + 'nxp_s32dbg', 'openocd', 'pyocd', 'qemu', diff --git a/scripts/west_commands/runners/blackmagicprobe.py b/scripts/west_commands/runners/blackmagicprobe.py index 54fc22a7eda3c13..1c2c8fa0d6a2aec 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/core.py b/scripts/west_commands/runners/core.py index fa697fa66cf4f21..9b3ca51d90038b2 100644 --- a/scripts/west_commands/runners/core.py +++ b/scripts/west_commands/runners/core.py @@ -658,24 +658,26 @@ def tool_opt_help(cls) -> str: in the order they appear on the command line.''' @staticmethod - def require(program: str) -> str: + def require(program: str, path: Optional[str] = None) -> str: '''Require that a program is installed before proceeding. :param program: name of the program that is required, or path to a program binary. + :param path: PATH where to search for the program binary. + By default check on the system PATH. If ``program`` is an absolute path to an existing program binary, this call succeeds. Otherwise, try to find the program - by name on the system PATH. + by name on the system PATH or in the given PATH, if provided. If the program can be found, its path is returned. Otherwise, raises MissingProgram.''' - ret = shutil.which(program) + ret = shutil.which(program, path=path) if ret is None: raise MissingProgram(program) return ret - def run_server_and_client(self, server, client): + def run_server_and_client(self, server, client, **kwargs): '''Run a server that ignores SIGINT, and a client that handles it. This routine portably: @@ -684,20 +686,22 @@ def run_server_and_client(self, server, client): SIGINT - runs ``client`` in a subprocess while temporarily ignoring SIGINT - cleans up the server after the client exits. + - the keyword arguments, if any, will be passed down to both server and + client subprocess calls It's useful to e.g. open a GDB server and client.''' - server_proc = self.popen_ignore_int(server) + server_proc = self.popen_ignore_int(server, **kwargs) try: - self.run_client(client) + self.run_client(client, **kwargs) finally: server_proc.terminate() server_proc.wait() - def run_client(self, client): + def run_client(self, client, **kwargs): '''Run a client that handles SIGINT.''' previous = signal.signal(signal.SIGINT, signal.SIG_IGN) try: - self.check_call(client) + self.check_call(client, **kwargs) finally: signal.signal(signal.SIGINT, previous) diff --git a/scripts/west_commands/runners/intel_adsp.py b/scripts/west_commands/runners/intel_adsp.py index 4a0c83c2f2c067a..f7587331dc36cd9 100644 --- a/scripts/west_commands/runners/intel_adsp.py +++ b/scripts/west_commands/runners/intel_adsp.py @@ -2,8 +2,9 @@ # # SPDX-License-Identifier: Apache-2.0 -'''Runner for flashing with the Intel ADSP CAVS boards.''' +'''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, '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,53 +69,24 @@ 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_cavs", self.platform): + if re.search("intel_adsp", self.platform): self.require(self.cavstool) self.flash(**kwargs) else: 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 4fa717206736e67..17d607877459503 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/linkserver.py b/scripts/west_commands/runners/linkserver.py index 5108d780aebd94c..a4ae5c622d448c8 100644 --- a/scripts/west_commands/runners/linkserver.py +++ b/scripts/west_commands/runners/linkserver.py @@ -111,7 +111,7 @@ def linkserver_version_str(self): if not hasattr(self, '_linkserver_version'): linkserver_version_cmd=[self.linkserver, "-v"] ls_output=self.check_output(linkserver_version_cmd) - self.linkserver_version = str(ls_output.split()[1].decode()) + self.linkserver_version = str(ls_output.split()[1].decode()).lower() return self.linkserver_version @@ -214,5 +214,9 @@ def flash(self, **kwargs): self.logger.debug("flash command = " + str(linkserver_cmd)) kwargs = {} if not self.logger.isEnabledFor(logging.DEBUG): - kwargs['stderr'] = subprocess.DEVNULL + if self.linkserver_version_str < "v1.3.15": + kwargs['stderr'] = subprocess.DEVNULL + else: + kwargs['stdout'] = subprocess.DEVNULL + self.check_call(linkserver_cmd, **kwargs) diff --git a/scripts/west_commands/runners/nrf_common.py b/scripts/west_commands/runners/nrf_common.py index 2ff51d7e85d1911..788021c61916925 100644 --- a/scripts/west_commands/runners/nrf_common.py +++ b/scripts/west_commands/runners/nrf_common.py @@ -59,7 +59,7 @@ 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', 'NRF91'], help='''MCU family; still accepted for compatibility only''') parser.add_argument('--softreset', required=False, @@ -161,6 +161,8 @@ 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_NRF91X'): self.family = 'NRF91_FAMILY' else: diff --git a/scripts/west_commands/runners/nrfjprog.py b/scripts/west_commands/runners/nrfjprog.py index 8762ce0e74058b9..a28681ae6a5ab5b 100644 --- a/scripts/west_commands/runners/nrfjprog.py +++ b/scripts/west_commands/runners/nrfjprog.py @@ -46,7 +46,7 @@ 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', 'NRF91_FAMILY': 'NRF91'} cores = {'NRFDL_DEVICE_CORE_APPLICATION': 'CP_APPLICATION', 'NRFDL_DEVICE_CORE_NETWORK': 'CP_NETWORK'} diff --git a/scripts/west_commands/runners/nxp_s32dbg.py b/scripts/west_commands/runners/nxp_s32dbg.py new file mode 100644 index 000000000000000..e2065f3980f99e7 --- /dev/null +++ b/scripts/west_commands/runners/nxp_s32dbg.py @@ -0,0 +1,334 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 +""" +Runner for NXP S32 Debug Probe. +""" + +import argparse +import os +import platform +import re +import shlex +import subprocess +import sys +import tempfile +from dataclasses import dataclass +from pathlib import Path +from typing import Dict, List, Optional, Union + +from runners.core import (BuildConfiguration, RunnerCaps, RunnerConfig, + ZephyrBinaryRunner) + +NXP_S32DBG_USB_CLASS = 'NXP Probes' +NXP_S32DBG_USB_VID = 0x15a2 +NXP_S32DBG_USB_PID = 0x0067 + + +@dataclass +class NXPS32DebugProbeConfig: + """NXP S32 Debug Probe configuration parameters.""" + conn_str: str = 's32dbg' + server_port: int = 45000 + speed: int = 16000 + remote_timeout: int = 30 + reset_type: Optional[str] = 'default' + reset_delay: int = 0 + + +class NXPS32DebugProbeRunner(ZephyrBinaryRunner): + """Runner front-end for NXP S32 Debug Probe.""" + + def __init__(self, + runner_cfg: RunnerConfig, + probe_cfg: NXPS32DebugProbeConfig, + core_name: str, + soc_name: str, + soc_family_name: str, + start_all_cores: bool, + s32ds_path: Optional[str] = None, + tool_opt: Optional[List[str]] = None) -> None: + super(NXPS32DebugProbeRunner, self).__init__(runner_cfg) + self.elf_file: str = runner_cfg.elf_file or '' + self.probe_cfg: NXPS32DebugProbeConfig = probe_cfg + self.core_name: str = core_name + self.soc_name: str = soc_name + self.soc_family_name: str = soc_family_name + self.start_all_cores: bool = start_all_cores + self.s32ds_path_override: Optional[str] = s32ds_path + + self.tool_opt: List[str] = [] + if tool_opt: + for opt in tool_opt: + self.tool_opt.extend(shlex.split(opt)) + + build_cfg = BuildConfiguration(runner_cfg.build_dir) + self.arch = build_cfg.get('CONFIG_ARCH').replace('"', '') + + @classmethod + def name(cls) -> str: + return 'nxp_s32dbg' + + @classmethod + def capabilities(cls) -> RunnerCaps: + return RunnerCaps(commands={'debug', 'debugserver', 'attach'}, + dev_id=True, tool_opt=True) + + @classmethod + def dev_id_help(cls) -> str: + return '''Debug probe connection string as in "s32dbg[:
    ]" + where
    can be the IP address if TAP is available via Ethernet, + the serial ID of the probe or empty if TAP is available via USB.''' + + @classmethod + def tool_opt_help(cls) -> str: + return '''Additional options for GDB client when used with "debug" or "attach" commands + or for GTA server when used with "debugserver" command.''' + + @classmethod + def do_add_parser(cls, parser: argparse.ArgumentParser) -> None: + parser.add_argument('--core-name', + required=True, + help='Core name as supported by the debug probe (e.g. "R52_0_0")') + parser.add_argument('--soc-name', + required=True, + help='SoC name as supported by the debug probe (e.g. "S32Z270")') + parser.add_argument('--soc-family-name', + required=True, + help='SoC family name as supported by the debug probe (e.g. "s32z2e2")') + parser.add_argument('--start-all-cores', + action='store_true', + help='Start all SoC cores and not just the one being debugged. ' + 'Use together with "debug" command.') + parser.add_argument('--s32ds-path', + help='Override the path to NXP S32 Design Studio installation. ' + 'By default, this runner will try to obtain it from the system ' + 'path, if available.') + parser.add_argument('--server-port', + default=NXPS32DebugProbeConfig.server_port, + type=int, + help='GTA server port') + parser.add_argument('--speed', + default=NXPS32DebugProbeConfig.speed, + type=int, + help='JTAG interface speed') + parser.add_argument('--remote-timeout', + default=NXPS32DebugProbeConfig.remote_timeout, + type=int, + help='Number of seconds to wait for the remote target responses') + + @classmethod + def do_create(cls, cfg: RunnerConfig, args: argparse.Namespace) -> 'NXPS32DebugProbeRunner': + probe_cfg = NXPS32DebugProbeConfig(args.dev_id, + server_port=args.server_port, + speed=args.speed, + remote_timeout=args.remote_timeout) + + return NXPS32DebugProbeRunner(cfg, probe_cfg, args.core_name, args.soc_name, + args.soc_family_name, args.start_all_cores, + s32ds_path=args.s32ds_path, tool_opt=args.tool_opt) + + @staticmethod + def find_usb_probes() -> List[str]: + """Return a list of debug probe serial numbers connected via USB to this host.""" + # use system's native commands to enumerate and retrieve the USB serial ID + # to avoid bloating this runner with third-party dependencies that often + # require priviledged permissions to access the device info + macaddr_pattern = r'(?:[0-9a-f]{2}[:]){5}[0-9a-f]{2}' + if platform.system() == 'Windows': + cmd = f'pnputil /enum-devices /connected /class "{NXP_S32DBG_USB_CLASS}"' + serialid_pattern = f'instance id: +usb\\\\.*\\\\({macaddr_pattern})' + else: + cmd = f'lsusb -v -d {NXP_S32DBG_USB_VID:x}:{NXP_S32DBG_USB_PID:x}' + serialid_pattern = f'iserial +.*({macaddr_pattern})' + + try: + outb = subprocess.check_output(shlex.split(cmd), stderr=subprocess.DEVNULL) + out = outb.decode('utf-8').strip().lower() + except subprocess.CalledProcessError: + raise RuntimeError('error while looking for debug probes connected') + + devices: List[str] = [] + if out and 'no devices were found' not in out: + devices = re.findall(serialid_pattern, out) + + return sorted(devices) + + @classmethod + def select_probe(cls) -> str: + """ + Find debugger probes connected and return the serial number of the one selected. + + If there are multiple debugger probes connected and this runner is being executed + in a interactive prompt, ask the user to select one of the probes. + """ + probes_snr = cls.find_usb_probes() + if not probes_snr: + raise RuntimeError('there are no debug probes connected') + elif len(probes_snr) == 1: + return probes_snr[0] + else: + if not sys.stdin.isatty(): + raise RuntimeError( + f'refusing to guess which of {len(probes_snr)} connected probes to use ' + '(Interactive prompts disabled since standard input is not a terminal). ' + 'Please specify a device ID on the command line.') + + print('There are multiple debug probes connected') + for i, probe in enumerate(probes_snr, 1): + print(f'{i}. {probe}') + + prompt = f'Please select one with desired serial number (1-{len(probes_snr)}): ' + while True: + try: + value: int = int(input(prompt)) + except EOFError: + sys.exit(0) + except ValueError: + continue + if 1 <= value <= len(probes_snr): + break + return probes_snr[value - 1] + + @property + def runtime_environment(self) -> Optional[Dict[str, str]]: + """Execution environment used for the client process.""" + if platform.system() == 'Windows': + python_lib = (self.s32ds_path / 'S32DS' / 'build_tools' / 'msys32' + / 'mingw32' / 'lib' / 'python2.7') + return { + **os.environ, + 'PYTHONPATH': f'{python_lib}{os.pathsep}{python_lib / "site-packages"}' + } + + return None + + @property + def script_globals(self) -> Dict[str, Optional[Union[str, int]]]: + """Global variables required by the debugger scripts.""" + return { + '_PROBE_IP': self.probe_cfg.conn_str, + '_JTAG_SPEED': self.probe_cfg.speed, + '_GDB_SERVER_PORT': self.probe_cfg.server_port, + '_RESET_TYPE': self.probe_cfg.reset_type, + '_RESET_DELAY': self.probe_cfg.reset_delay, + '_REMOTE_TIMEOUT': self.probe_cfg.remote_timeout, + '_CORE_NAME': f'{self.soc_name}_{self.core_name}', + '_SOC_NAME': self.soc_name, + '_IS_LOGGING_ENABLED': False, + '_FLASH_NAME': None, # not supported + '_SECURE_TYPE': None, # not supported + '_SECURE_KEY': None, # not supported + } + + def server_commands(self) -> List[str]: + """Get launch commands to start the GTA server.""" + server_exec = str(self.s32ds_path / 'S32DS' / 'tools' / 'S32Debugger' + / 'Debugger' / 'Server' / 'gta' / 'gta') + cmd = [server_exec, '-p', str(self.probe_cfg.server_port)] + return cmd + + def client_commands(self) -> List[str]: + """Get launch commands to start the GDB client.""" + if self.arch == 'arm': + client_exec_name = 'arm-none-eabi-gdb-py' + elif self.arch == 'arm64': + client_exec_name = 'aarch64-none-elf-gdb-py' + else: + raise RuntimeError(f'architecture {self.arch} not supported') + + client_exec = str(self.s32ds_path / 'S32DS' / 'tools' / 'gdb-arm' + / 'arm32-eabi' / 'bin' / client_exec_name) + cmd = [client_exec] + return cmd + + def get_script(self, name: str) -> Path: + """ + Get the file path of a debugger script with the given name. + + :param name: name of the script, without the SoC family name prefix + :returns: path to the script + :raises RuntimeError: if file does not exist + """ + script = (self.s32ds_path / 'S32DS' / 'tools' / 'S32Debugger' / 'Debugger' / 'scripts' + / self.soc_family_name / f'{self.soc_family_name}_{name}.py') + if not script.exists(): + raise RuntimeError(f'script not found: {script}') + return script + + def do_run(self, command: str, **kwargs) -> None: + """ + Execute the given command. + + :param command: command name to execute + :raises RuntimeError: if target architecture or host OS is not supported + :raises MissingProgram: if required tools are not found in the host + """ + if platform.system() not in ('Windows', 'Linux'): + raise RuntimeError(f'runner not supported on {platform.system()} systems') + + if self.arch not in ('arm', 'arm64'): + raise RuntimeError(f'architecture {self.arch} not supported') + + app_name = 's32ds' if platform.system() == 'Windows' else 's32ds.sh' + self.s32ds_path = Path(self.require(app_name, path=self.s32ds_path_override)).parent + + if not self.probe_cfg.conn_str: + self.probe_cfg.conn_str = f's32dbg:{self.select_probe()}' + self.logger.info(f'using debug probe {self.probe_cfg.conn_str}') + + if command in ('attach', 'debug'): + self.ensure_output('elf') + self.do_attach_debug(command, **kwargs) + else: + self.do_debugserver(**kwargs) + + def do_attach_debug(self, command: str, **kwargs) -> None: + """ + Launch the GTA server and GDB client to start a debugging session. + + :param command: command name to execute + """ + gdb_script: List[str] = [] + + # setup global variables required for the scripts before sourcing them + for name, val in self.script_globals.items(): + gdb_script.append(f'py {name} = {repr(val)}') + + # load platform-specific debugger script + if command == 'debug': + if self.start_all_cores: + startup_script = self.get_script('generic_bareboard_all_cores') + else: + startup_script = self.get_script('generic_bareboard') + else: + startup_script = self.get_script('attach') + gdb_script.append(f'source {startup_script}') + + # executes the SoC and board initialization sequence + if command == 'debug': + gdb_script.append('py board_init()') + + # initializes the debugger connection to the core specified + gdb_script.append('py core_init()') + + gdb_script.append(f'file {Path(self.elf_file).as_posix()}') + if command == 'debug': + gdb_script.append('load') + + with tempfile.TemporaryDirectory(suffix='nxp_s32dbg') as tmpdir: + gdb_cmds = Path(tmpdir) / 'runner.nxp_s32dbg' + gdb_cmds.write_text('\n'.join(gdb_script), encoding='utf-8') + self.logger.debug(gdb_cmds.read_text(encoding='utf-8')) + + server_cmd = self.server_commands() + client_cmd = self.client_commands() + client_cmd.extend(['-x', gdb_cmds.as_posix()]) + client_cmd.extend(self.tool_opt) + + self.run_server_and_client(server_cmd, client_cmd, env=self.runtime_environment) + + def do_debugserver(self, **kwargs) -> None: + """Start the GTA server on a given port with the given extra parameters from cli.""" + server_cmd = self.server_commands() + server_cmd.extend(self.tool_opt) + self.check_call(server_cmd) diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index 2c2692c55d244aa..fb1de57097412c1 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 / '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) @@ -517,6 +548,13 @@ def sign(self, command, build_dir, build_conf, formats): else: no_manifest = False + # Non-SOF build does not have extended manifest data for + # rimage to process, which might result in rimage error. + # So skip it when not doing SOF builds. + is_sof_build = build_conf.getboolean('CONFIG_SOF') + if not is_sof_build: + no_manifest = True + if no_manifest: extra_ri_args = [ ] else: @@ -524,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 @@ -538,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 @@ -547,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/tests/test_dfu_util.py b/scripts/west_commands/tests/test_dfu_util.py index 9ae4b1ce99b9470..a28522cd81b37d6 100644 --- a/scripts/west_commands/tests/test_dfu_util.py +++ b/scripts/west_commands/tests/test_dfu_util.py @@ -86,7 +86,7 @@ def test_dfu_util_init(cc, req, find_device, tc, runner_config): with patch('os.path.isfile', side_effect=os_path_isfile_patch): runner.run('flash') assert find_device.called - assert req.called_with(exe) + assert req.call_args_list == [call(exe)] assert cc.call_args_list == [call(EXPECTED_COMMAND[tc])] def get_flash_address_patch(args, bcfg): @@ -141,5 +141,5 @@ def test_dfu_util_create(cc, req, gfa, find_device, tc, runner_config, tmpdir): cfg = None map_tc = (exe or DFU_UTIL, alt, cfg, img or RC_KERNEL_BIN) assert find_device.called - assert req.called_with(exe) + assert req.call_args_list == [call(exe or DFU_UTIL)] assert cc.call_args_list == [call(EXPECTED_COMMAND[map_tc])] diff --git a/scripts/west_commands/tests/test_imports.py b/scripts/west_commands/tests/test_imports.py index 774d4f7d7221d90..274840f8cbf6a43 100644 --- a/scripts/west_commands/tests/test_imports.py +++ b/scripts/west_commands/tests/test_imports.py @@ -35,6 +35,7 @@ def test_runner_imports(): 'nios2', 'nrfjprog', 'nrfutil', + 'nxp_s32dbg', 'openocd', 'pyocd', 'qemu', diff --git a/scripts/west_commands/tests/test_nxp_s32dbg.py b/scripts/west_commands/tests/test_nxp_s32dbg.py new file mode 100644 index 000000000000000..a0d982cdfe8e27c --- /dev/null +++ b/scripts/west_commands/tests/test_nxp_s32dbg.py @@ -0,0 +1,247 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +import argparse +import os +from pathlib import Path +from unittest.mock import patch + +import pytest +from conftest import RC_KERNEL_ELF +from runners.nxp_s32dbg import NXPS32DebugProbeConfig, NXPS32DebugProbeRunner + +TEST_DEVICE = 's32dbg' +TEST_SPEED = 16000 +TEST_SERVER_PORT = 45000 +TEST_REMOTE_TIMEOUT = 30 +TEST_CORE_NAME = 'R52_0_0' +TEST_SOC_NAME = 'S32Z270' +TEST_SOC_FAMILY_NAME = 's32e2z2' +TEST_START_ALL_CORES = True +TEST_S32DS_PATH_OVERRIDE = None +TEST_TOOL_OPT = ['--test-opt-1', '--test-opt-2'] +TEST_RESET_TYPE = 'default' +TEST_RESET_DELAY = 0 + +TEST_S32DS_CMD = 's32ds' +TEST_SERVER_CMD = Path('S32DS') / 'tools' / 'S32Debugger' / 'Debugger' / 'Server' / 'gta' / 'gta' +TEST_ARM_GDB_CMD = Path('S32DS') / 'tools' / 'gdb-arm' / 'arm32-eabi' / 'bin' / 'arm-none-eabi-gdb-py' + +TEST_S32DS_PYTHON_LIB = Path('S32DS') / 'build_tools' / 'msys32' / 'mingw32' / 'lib' / 'python2.7' +TEST_S32DS_RUNTIME_ENV = { + 'PYTHONPATH': f'{TEST_S32DS_PYTHON_LIB}{os.pathsep}{TEST_S32DS_PYTHON_LIB / "site-packages"}' +} + +TEST_ALL_KWARGS = { + 'NXPS32DebugProbeConfig': { + 'conn_str': TEST_DEVICE, + 'server_port': TEST_SERVER_PORT, + 'speed': TEST_SPEED, + 'remote_timeout': TEST_REMOTE_TIMEOUT, + }, + 'NXPS32DebugProbeRunner': { + 'core_name': TEST_CORE_NAME, + 'soc_name': TEST_SOC_NAME, + 'soc_family_name': TEST_SOC_FAMILY_NAME, + 'start_all_cores': TEST_START_ALL_CORES, + 's32ds_path': TEST_S32DS_PATH_OVERRIDE, + 'tool_opt': TEST_TOOL_OPT + } +} + +TEST_ALL_PARAMS = [ + # generic + '--dev-id', TEST_DEVICE, + *[f'--tool-opt={o}' for o in TEST_TOOL_OPT], + # from runner + '--s32ds-path', TEST_S32DS_PATH_OVERRIDE, + '--core-name', TEST_CORE_NAME, + '--soc-name', TEST_SOC_NAME, + '--soc-family-name', TEST_SOC_FAMILY_NAME, + '--server-port', TEST_SERVER_PORT, + '--speed', TEST_SPEED, + '--remote-timeout', TEST_REMOTE_TIMEOUT, + '--start-all-cores', +] + +TEST_ALL_S32DBG_PY_VARS = [ + f'py _PROBE_IP = {repr(TEST_DEVICE)}', + f'py _JTAG_SPEED = {repr(TEST_SPEED)}', + f'py _GDB_SERVER_PORT = {repr(TEST_SERVER_PORT)}', + f"py _RESET_TYPE = {repr(TEST_RESET_TYPE)}", + f'py _RESET_DELAY = {repr(TEST_RESET_DELAY)}', + f'py _REMOTE_TIMEOUT = {repr(TEST_REMOTE_TIMEOUT)}', + f'py _CORE_NAME = {repr(f"{TEST_SOC_NAME}_{TEST_CORE_NAME}")}', + f'py _SOC_NAME = {repr(TEST_SOC_NAME)}', + 'py _IS_LOGGING_ENABLED = False', + 'py _FLASH_NAME = None', + 'py _SECURE_TYPE = None', + 'py _SECURE_KEY = None', +] + +DEBUGSERVER_ALL_EXPECTED_CALL = [ + str(TEST_SERVER_CMD), + '-p', str(TEST_SERVER_PORT), + *TEST_TOOL_OPT, +] + +DEBUG_ALL_EXPECTED_CALL = { + 'client': [ + str(TEST_ARM_GDB_CMD), + '-x', 'TEST_GDB_SCRIPT', + *TEST_TOOL_OPT, + ], + 'server': [ + str(TEST_SERVER_CMD), + '-p', str(TEST_SERVER_PORT), + ], + 'gdb_script': [ + *TEST_ALL_S32DBG_PY_VARS, + f'source generic_bareboard{"_all_cores" if TEST_START_ALL_CORES else ""}.py', + 'py board_init()', + 'py core_init()', + f'file {RC_KERNEL_ELF}', + 'load', + ] +} + +ATTACH_ALL_EXPECTED_CALL = { + **DEBUG_ALL_EXPECTED_CALL, + 'gdb_script': [ + *TEST_ALL_S32DBG_PY_VARS, + f'source attach.py', + 'py core_init()', + f'file {RC_KERNEL_ELF}', + ] +} + + +@pytest.fixture +def s32dbg(runner_config, tmp_path): + '''NXPS32DebugProbeRunner from constructor kwargs or command line parameters''' + def _factory(args): + # create empty files to ensure kernel binaries exist + (tmp_path / RC_KERNEL_ELF).touch() + os.chdir(tmp_path) + + runner_config_patched = fix_up_runner_config(runner_config, tmp_path) + + if isinstance(args, dict): + probe_cfg = NXPS32DebugProbeConfig(**args['NXPS32DebugProbeConfig']) + return NXPS32DebugProbeRunner(runner_config_patched, probe_cfg, + **args['NXPS32DebugProbeRunner']) + elif isinstance(args, list): + parser = argparse.ArgumentParser(allow_abbrev=False) + NXPS32DebugProbeRunner.add_parser(parser) + arg_namespace = parser.parse_args(str(x) for x in args) + return NXPS32DebugProbeRunner.create(runner_config_patched, arg_namespace) + return _factory + + +def fix_up_runner_config(runner_config, tmp_path): + to_replace = {} + + zephyr = tmp_path / 'zephyr' + zephyr.mkdir() + dotconfig = zephyr / '.config' + dotconfig.write_text('CONFIG_ARCH="arm"') + to_replace['build_dir'] = tmp_path + + return runner_config._replace(**to_replace) + + +def require_patch(program, path=None): + assert Path(program).stem == TEST_S32DS_CMD + return program + + +def s32dbg_get_script(name): + return Path(f'{name}.py') + + +@pytest.mark.parametrize('s32dbg_args,expected,osname', [ + (TEST_ALL_KWARGS, DEBUGSERVER_ALL_EXPECTED_CALL, 'Windows'), + (TEST_ALL_PARAMS, DEBUGSERVER_ALL_EXPECTED_CALL, 'Windows'), + (TEST_ALL_KWARGS, DEBUGSERVER_ALL_EXPECTED_CALL, 'Linux'), + (TEST_ALL_PARAMS, DEBUGSERVER_ALL_EXPECTED_CALL, 'Linux'), +]) +@patch('platform.system') +@patch('runners.core.ZephyrBinaryRunner.check_call') +@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) +def test_debugserver(require, check_call, system, + s32dbg_args, expected, osname, s32dbg): + system.return_value = osname + + runner = s32dbg(s32dbg_args) + runner.run('debugserver') + + assert require.called + check_call.assert_called_once_with(expected) + + +@pytest.mark.parametrize('s32dbg_args,expected,osname', [ + (TEST_ALL_KWARGS, DEBUG_ALL_EXPECTED_CALL, 'Windows'), + (TEST_ALL_PARAMS, DEBUG_ALL_EXPECTED_CALL, 'Windows'), + (TEST_ALL_KWARGS, DEBUG_ALL_EXPECTED_CALL, 'Linux'), + (TEST_ALL_PARAMS, DEBUG_ALL_EXPECTED_CALL, 'Linux'), +]) +@patch.dict(os.environ, TEST_S32DS_RUNTIME_ENV, clear=True) +@patch('platform.system') +@patch('tempfile.TemporaryDirectory') +@patch('runners.nxp_s32dbg.NXPS32DebugProbeRunner.get_script', side_effect=s32dbg_get_script) +@patch('runners.core.ZephyrBinaryRunner.popen_ignore_int') +@patch('runners.core.ZephyrBinaryRunner.check_call') +@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) +def test_debug(require, check_call, popen_ignore_int, get_script, temporary_dir, system, + s32dbg_args, expected, osname, s32dbg, tmp_path): + + # mock tempfile.TemporaryDirectory to return `tmp_path` and create gdb init script there + temporary_dir.return_value.__enter__.return_value = tmp_path + gdb_script = tmp_path / 'runner.nxp_s32dbg' + expected_client = [e.replace('TEST_GDB_SCRIPT', gdb_script.as_posix()) + for e in expected['client']] + + system.return_value = osname + expected_env = TEST_S32DS_RUNTIME_ENV if osname == 'Windows' else None + + runner = s32dbg(s32dbg_args) + runner.run('debug') + + assert require.called + assert gdb_script.read_text().splitlines() == expected['gdb_script'] + popen_ignore_int.assert_called_once_with(expected['server'], env=expected_env) + check_call.assert_called_once_with(expected_client, env=expected_env) + + +@pytest.mark.parametrize('s32dbg_args,expected,osname', [ + (TEST_ALL_KWARGS, ATTACH_ALL_EXPECTED_CALL, 'Windows'), + (TEST_ALL_PARAMS, ATTACH_ALL_EXPECTED_CALL, 'Windows'), + (TEST_ALL_KWARGS, ATTACH_ALL_EXPECTED_CALL, 'Linux'), + (TEST_ALL_PARAMS, ATTACH_ALL_EXPECTED_CALL, 'Linux'), +]) +@patch.dict(os.environ, TEST_S32DS_RUNTIME_ENV, clear=True) +@patch('platform.system') +@patch('tempfile.TemporaryDirectory') +@patch('runners.nxp_s32dbg.NXPS32DebugProbeRunner.get_script', side_effect=s32dbg_get_script) +@patch('runners.core.ZephyrBinaryRunner.popen_ignore_int') +@patch('runners.core.ZephyrBinaryRunner.check_call') +@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) +def test_attach(require, check_call, popen_ignore_int, get_script, temporary_dir, system, + s32dbg_args, expected, osname, s32dbg, tmp_path): + + # mock tempfile.TemporaryDirectory to return `tmp_path` and create gdb init script there + temporary_dir.return_value.__enter__.return_value = tmp_path + gdb_script = tmp_path / 'runner.nxp_s32dbg' + expected_client = [e.replace('TEST_GDB_SCRIPT', gdb_script.as_posix()) + for e in expected['client']] + + system.return_value = osname + expected_env = TEST_S32DS_RUNTIME_ENV if osname == 'Windows' else None + + runner = s32dbg(s32dbg_args) + runner.run('attach') + + assert require.called + assert gdb_script.read_text().splitlines() == expected['gdb_script'] + popen_ignore_int.assert_called_once_with(expected['server'], env=expected_env) + check_call.assert_called_once_with(expected_client, env=expected_env) diff --git a/scripts/west_commands/zspdx/walker.py b/scripts/west_commands/zspdx/walker.py index c809ac40318d184..0c6469444eda078 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/scripts/zephyr_module.py b/scripts/zephyr_module.py index db58bcea23c673d..ab27eaa57063dfc 100755 --- a/scripts/zephyr_module.py +++ b/scripts/zephyr_module.py @@ -350,7 +350,10 @@ def process_kconfig(module, meta): return kconfig_snippet(meta, module_path, Path(kconfig_file), blobs=taint_blobs) else: - return "" + name_sanitized = meta['name-sanitized'] + return (f'config ZEPHYR_{name_sanitized.upper()}_MODULE\n' + f' bool\n' + f' default y\n') def process_sysbuildkconfig(module, meta): diff --git a/share/sysbuild/CMakeLists.txt b/share/sysbuild/CMakeLists.txt index 7bbfe1387601b4c..9133fe874ef2d28 100644 --- a/share/sysbuild/CMakeLists.txt +++ b/share/sysbuild/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2021-2023 Nordic Semiconductor +# Copyright (c) 2023 Nordic Semiconductor # # SPDX-License-Identifier: Apache-2.0 @@ -18,7 +18,10 @@ set(APP_DIR ${APP_DIR} CACHE PATH "Main Application Source Directory") list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules) # List of Zephyr and sysbuild CMake modules we need for sysbuild. # Note: sysbuild_kconfig will internally load kconfig CMake module. -set(zephyr_modules extensions sysbuild_extensions python west root zephyr_module boards shields sysbuild_kconfig) +set(zephyr_modules extensions + sysbuild_extensions python west root zephyr_module boards shields + sysbuild_kconfig native_simulator_sb_extensions + ) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE} COMPONENTS ${zephyr_modules}) @@ -35,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/native_simulator_sb_extensions.cmake b/share/sysbuild/cmake/modules/native_simulator_sb_extensions.cmake new file mode 100644 index 000000000000000..3d888d1775ef177 --- /dev/null +++ b/share/sysbuild/cmake/modules/native_simulator_sb_extensions.cmake @@ -0,0 +1,62 @@ +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: Apache-2.0 + +# Usage: +# native_simulator_set_final_executable() +# +# When building for a native_simulator based target (including bsim targets), +# this function adds an extra build target which will copy the executable produced by +# `` to the top level, as zephyr/zephyr.exe +# +# This final image is expected to have been set to assemble other dependent images into +# itself if necessary, by calling native_simulator_set_child_images() +# This will allow other tools, like twister, or the bsim test scripts, as well as users to find +# this final executable in the same place as for non-sysbuild builds. +# +function(native_simulator_set_final_executable final_image) + if(("${BOARD}" MATCHES "native") OR ("${BOARD}" MATCHES "bsim")) + add_custom_target(final_executable + ALL + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/${final_image}/zephyr/zephyr.exe + ${CMAKE_BINARY_DIR}/zephyr/zephyr.exe + DEPENDS ${final_image} + ) + endif() +endfunction() + +# Usage: +# native_simulator_set_child_images( ) +# +# When building for a native_simulator based target (including bsim targets), +# this function sets a `` as dependencies of `` +# and configures the final image to assemble the child images into its final executable. +# +function(native_simulator_set_child_images final_image child_image) + if(("${BOARD}" MATCHES "native") OR ("${BOARD}" MATCHES "bsim")) + add_dependencies(${final_image} ${child_image}) + + set(CHILD_LIBRARY_PATH ${CMAKE_BINARY_DIR}/${child_image}/zephyr/zephyr.elf) + set_property(TARGET ${final_image} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS=\"${CHILD_LIBRARY_PATH}\"\n" + ) + endif() +endfunction() + +# Usage: +# native_simulator_set_primary_mcu_index( [ ...]) +# +# Propagate the SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX setting, +# if it is set, to each given image CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX +# +function(native_simulator_set_primary_mcu_index) + if (NOT ("${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}" STREQUAL "")) + foreach(arg IN LISTS ARGV) + set_property(TARGET ${arg} APPEND_STRING PROPERTY CONFIG + "CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX=${SB_CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}\n" + ) + endforeach() + endif() +endfunction() diff --git a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake index a3838415eee2041..980c54ef7665338 100644 --- a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake +++ b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake @@ -107,6 +107,87 @@ function(sysbuild_get variable) endif() endfunction() +# Usage: +# sysbuild_cache(CREATE APPLICATION [CMAKE_RERUN]) +# +# This function works on the sysbuild cache for sysbuild managed applications. +# +# Arguments: +# CREATE : Create or update existing sysbuild cache file for the application. +# The sysbuild cache is only updated if it contain changes. +# APPLICATION : Name of the application. +# CMAKE_RERUN : Force a CMake rerun for the application during next build +# invocation if the sysbuild cache has changed. It is +# advised to always use this flag. Not using this flag can +# reduce build time, but only do so if application is +# guranteed to be up-to-date. +# +function(sysbuild_cache) + cmake_parse_arguments(SB_CACHE "CREATE;CMAKE_RERUN" "APPLICATION" "" ${ARGN}) + zephyr_check_arguments_required(sysbuild_cache SB_CACHE APPLICATION) + zephyr_check_flags_required(sysbuild_cache SB_CACHE CREATE) + + get_target_property(${SB_CACHE_APPLICATION}_MAIN_APP ${SB_CACHE_APPLICATION} MAIN_APP) + get_cmake_property(sysbuild_cache CACHE_VARIABLES) + + foreach(var_name ${sysbuild_cache}) + if(NOT "${var_name}" MATCHES "^(CMAKE_.*|BOARD)$") + # Perform a dummy read to prevent a false warning about unused variables + # being emitted due to a cmake bug: https://gitlab.kitware.com/cmake/cmake/-/issues/24555 + set(unused_tmp_var ${${var_name}}) + + # We don't want to pass internal CMake variables. + # Required CMake variable to be passed, like CMAKE_BUILD_TYPE must be + # passed using `-D` on command invocation. + get_property(var_type CACHE ${var_name} PROPERTY TYPE) + set(cache_entry "${var_name}:${var_type}=$CACHE{${var_name}}") + string(REPLACE ";" "\;" cache_entry "${cache_entry}") + list(APPEND sysbuild_cache_strings "${cache_entry}\n") + endif() + endforeach() + if(DEFINED BOARD_REVISION) + list(APPEND sysbuild_cache_strings "BOARD:STRING=${BOARD}@${BOARD_REVISION}\n") + else() + list(APPEND sysbuild_cache_strings "BOARD:STRING=${BOARD}\n") + endif() + list(APPEND sysbuild_cache_strings "SYSBUILD_NAME:STRING=${SB_CACHE_APPLICATION}\n") + + if(${SB_CACHE_APPLICATION}_MAIN_APP) + list(APPEND sysbuild_cache_strings "SYSBUILD_MAIN_APP:BOOL=True\n") + endif() + + if(${SB_CACHE_APPLICATION}_BOARD AND NOT DEFINED CACHE{${SB_CACHE_APPLICATION}_BOARD}) + # Only set image specific board if provided. + # The sysbuild BOARD is exported through sysbuild cache, and will be used + # unless _BOARD is defined. + list(APPEND sysbuild_cache_strings + "${SB_CACHE_APPLICATION}_BOARD:STRING=${${SB_CACHE_APPLICATION}_BOARD}\n" + ) + endif() + + get_target_property(${SB_CACHE_APPLICATION}_CACHE_FILE ${SB_CACHE_APPLICATION} CACHE_FILE) + file(WRITE ${${SB_CACHE_APPLICATION}_CACHE_FILE}.tmp ${sysbuild_cache_strings}) + if(SB_CACHE_CMAKE_RERUN) + execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files + ${${SB_CACHE_APPLICATION}_CACHE_FILE}.tmp + ${${SB_CACHE_APPLICATION}_CACHE_FILE} + RESULT_VARIABLE compare_res + ) + if(NOT compare_res EQUAL 0) + zephyr_file_copy(${${SB_CACHE_APPLICATION}_CACHE_FILE}.tmp + ${${SB_CACHE_APPLICATION}_CACHE_FILE} + ) + ExternalProject_Get_Property(${SB_CACHE_APPLICATION} BINARY_DIR) + file(TOUCH_NOCREATE ${BINARY_DIR}/CMakeCache.txt) + endif() + else() + zephyr_file_copy(${${SB_CACHE_APPLICATION}_CACHE_FILE}.tmp + ${${SB_CACHE_APPLICATION}_CACHE_FILE} ONLY_IF_DIFFERENT + ) + endif() + +endfunction() + # Usage: # ExternalZephyrProject_Add(APPLICATION # SOURCE_DIR @@ -372,9 +453,7 @@ function(ExternalZephyrProject_Cmake) ) ExternalProject_Get_Property(${ZCMAKE_APPLICATION} SOURCE_DIR BINARY_DIR CMAKE_ARGS) - get_target_property(${ZCMAKE_APPLICATION}_CACHE_FILE ${ZCMAKE_APPLICATION} CACHE_FILE) get_target_property(${ZCMAKE_APPLICATION}_BOARD ${ZCMAKE_APPLICATION} BOARD) - get_target_property(${ZCMAKE_APPLICATION}_MAIN_APP ${ZCMAKE_APPLICATION} MAIN_APP) get_property(${ZCMAKE_APPLICATION}_CONF_SCRIPT TARGET ${ZCMAKE_APPLICATION} PROPERTY IMAGE_CONF_SCRIPT @@ -390,46 +469,7 @@ function(ExternalZephyrProject_Cmake) endif() endforeach() - get_cmake_property(sysbuild_cache CACHE_VARIABLES) - foreach(var_name ${sysbuild_cache}) - if(NOT "${var_name}" MATCHES "^(CMAKE_.*|BOARD)$") - # Perform a dummy read to prevent a false warning about unused variables - # being emitted due to a cmake bug: https://gitlab.kitware.com/cmake/cmake/-/issues/24555 - set(unused_tmp_var ${${var_name}}) - - # We don't want to pass internal CMake variables. - # Required CMake variable to be passed, like CMAKE_BUILD_TYPE must be - # passed using `-D` on command invocation. - get_property(var_type CACHE ${var_name} PROPERTY TYPE) - set(cache_entry "${var_name}:${var_type}=$CACHE{${var_name}}") - string(REPLACE ";" "\;" cache_entry "${cache_entry}") - list(APPEND sysbuild_cache_strings "${cache_entry}\n") - endif() - endforeach() - if(DEFINED BOARD_REVISION) - list(APPEND sysbuild_cache_strings "BOARD:STRING=${BOARD}@${BOARD_REVISION}\n") - else() - list(APPEND sysbuild_cache_strings "BOARD:STRING=${BOARD}\n") - endif() - list(APPEND sysbuild_cache_strings "SYSBUILD_NAME:STRING=${ZCMAKE_APPLICATION}\n") - - if(${ZCMAKE_APPLICATION}_MAIN_APP) - list(APPEND sysbuild_cache_strings "SYSBUILD_MAIN_APP:BOOL=True\n") - endif() - - if(${ZCMAKE_APPLICATION}_BOARD AND NOT DEFINED CACHE{${ZCMAKE_APPLICATION}_BOARD}) - # Only set image specific board if provided. - # The sysbuild BOARD is exported through sysbuild cache, and will be used - # unless _BOARD is defined. - list(APPEND sysbuild_cache_strings - "${ZCMAKE_APPLICATION}_BOARD:STRING=${${ZCMAKE_APPLICATION}_BOARD}\n" - ) - endif() - - file(WRITE ${${ZCMAKE_APPLICATION}_CACHE_FILE}.tmp ${sysbuild_cache_strings}) - zephyr_file_copy(${${ZCMAKE_APPLICATION}_CACHE_FILE}.tmp - ${${ZCMAKE_APPLICATION}_CACHE_FILE} ONLY_IF_DIFFERENT - ) + sysbuild_cache(CREATE APPLICATION ${ZCMAKE_APPLICATION}) foreach(script ${${ZCMAKE_APPLICATION}_CONF_SCRIPT}) include(${script}) @@ -471,34 +511,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 12ab32e55c2800d..23932d4494f2552 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 5594109668b45b4..0da5a89ce117ce8 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 2a0f12f958d7e9e..c82f0808c66ec28 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 e8c788f72c57550..d8e1bf70d75b20d 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 a9493f683b8e0d2..8d89483ad9dd9a8 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 a0a65b2e090a282..de395c3112f3b7b 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/xen_dom0/xen_dom0.overlay b/snippets/xen_dom0/xen_dom0.overlay index 98fe1e39d673537..74642eb6b822ff6 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/arc/snps_arc_hsdk/CMakeLists.txt b/soc/arc/snps_arc_hsdk/CMakeLists.txt index 1d6a7c6827f657a..c20f41670571770 100644 --- a/soc/arc/snps_arc_hsdk/CMakeLists.txt +++ b/soc/arc/snps_arc_hsdk/CMakeLists.txt @@ -18,3 +18,5 @@ else() zephyr_ld_options(-Hlib=hs38_full) endif() + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arc/snps_arc_hsdk4xd/CMakeLists.txt b/soc/arc/snps_arc_hsdk4xd/CMakeLists.txt index 0e6c51029af6c4c..0c13259ca2b7f29 100644 --- a/soc/arc/snps_arc_hsdk4xd/CMakeLists.txt +++ b/soc/arc/snps_arc_hsdk4xd/CMakeLists.txt @@ -14,3 +14,5 @@ else() zephyr_ld_options(-Hlib=hs48_slc_full) endif() + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arc/snps_arc_hsdk4xd/Kconfig.soc b/soc/arc/snps_arc_hsdk4xd/Kconfig.soc index be4331ad48bfd48..6354c659d30bfdb 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_arc_iot/CMakeLists.txt b/soc/arc/snps_arc_iot/CMakeLists.txt index 4c478bc785c1f35..5a28fe228d88d2d 100644 --- a/soc/arc/snps_arc_iot/CMakeLists.txt +++ b/soc/arc/snps_arc_iot/CMakeLists.txt @@ -6,3 +6,5 @@ zephyr_sources( soc.c sysconf.c ) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arc/snps_emsdp/CMakeLists.txt b/soc/arc/snps_emsdp/CMakeLists.txt index 7a4ba9674fd5fe1..04466b802c02926 100644 --- a/soc/arc/snps_emsdp/CMakeLists.txt +++ b/soc/arc/snps_emsdp/CMakeLists.txt @@ -18,3 +18,5 @@ elseif(CONFIG_SOC_EMSDP_EM11D) zephyr_compile_options(-mmpy-option=6) zephyr_compile_options_ifdef(CONFIG_FPU -mfpu=fpuda_all) endif() + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arc/snps_emsdp/Kconfig.soc b/soc/arc/snps_emsdp/Kconfig.soc index a1358b8ad9d04ef..ed0a2f88e20c403 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/CMakeLists.txt b/soc/arc/snps_emsk/CMakeLists.txt index 53b0f92a9c8a4be..8e8ef5865caabb3 100644 --- a/soc/arc/snps_emsk/CMakeLists.txt +++ b/soc/arc/snps_emsk/CMakeLists.txt @@ -8,3 +8,5 @@ zephyr_compile_options_ifdef(CONFIG_FPU -mfpu=fpuda_all) endif() zephyr_sources(soc_config.c) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arc/snps_emsk/Kconfig.soc b/soc/arc/snps_emsk/Kconfig.soc index 9b6e50abe60767d..d172c4144a7faa2 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/CMakeLists.txt b/soc/arc/snps_nsim/CMakeLists.txt index 965bf79968edf79..094aed08cee63c9 100644 --- a/soc/arc/snps_nsim/CMakeLists.txt +++ b/soc/arc/snps_nsim/CMakeLists.txt @@ -105,3 +105,5 @@ else() zephyr_ld_option_ifdef(CONFIG_SOC_NSIM_HS6X_SMP -Hlib=hs68_full_zephyr) endif() + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arc/snps_nsim/Kconfig b/soc/arc/snps_nsim/Kconfig index 62b74e8a7436de7..cdf2ec69cae16da 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/arc/snps_qemu/CMakeLists.txt b/soc/arc/snps_qemu/CMakeLists.txt index c77f0003c4ce9ef..a05efdfa22d8ce7 100644 --- a/soc/arc/snps_qemu/CMakeLists.txt +++ b/soc/arc/snps_qemu/CMakeLists.txt @@ -19,3 +19,5 @@ else() endif() endif() + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/CMakeLists.txt b/soc/arm/CMakeLists.txt index f854c3b7d1ee695..b826da926caf128 100644 --- a/soc/arm/CMakeLists.txt +++ b/soc/arm/CMakeLists.txt @@ -1,10 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -add_subdirectory_ifdef(CONFIG_CPU_CORTEX_M common/cortex_m) - if(SOC_FAMILY) add_subdirectory(${SOC_FAMILY}) else() add_subdirectory(${SOC_NAME}) endif() - diff --git a/soc/arm/Kconfig b/soc/arm/Kconfig index 443a0031189f59c..461f0b41f84c0f8 100644 --- a/soc/arm/Kconfig +++ b/soc/arm/Kconfig @@ -34,28 +34,12 @@ config CPU_HAS_ARM_SAU config CPU_HAS_NRF_IDAU bool - depends on SOC_SERIES_NRF91X || SOC_NRF5340_CPUAPP select CPU_HAS_TEE help MCU implements the nRF (vendor-specific) Security Attribution Unit. (IDAU: "Implementation-Defined Attribution Unit", in accordance with ARM terminology). -if CPU_HAS_NRF_IDAU -config NRF_SPU_FLASH_REGION_SIZE - hex - default 0x8000 if SOC_SERIES_NRF91X - default 0x4000 if SOC_NRF5340_CPUAPP - help - FLASH region size for the NRF_SPU peripheral - -config NRF_SPU_RAM_REGION_SIZE - hex - default 0x2000 if SOC_SERIES_NRF91X || SOC_NRF5340_CPUAPP - help - RAM region size for the NRF_SPU peripheral -endif - config HAS_SWO bool help diff --git a/soc/arm/ambiq/apollo4x/CMakeLists.txt b/soc/arm/ambiq/apollo4x/CMakeLists.txt index 2d96101cb0bcccf..a82fe0a51f3960f 100644 --- a/soc/arm/ambiq/apollo4x/CMakeLists.txt +++ b/soc/arm/ambiq/apollo4x/CMakeLists.txt @@ -5,3 +5,5 @@ zephyr_sources(soc.c) zephyr_include_directories(${ZEPHYR_BASE}/soc/arm/common/cortex_m) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p b/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p index 2d672184b4b8282..3e465e71ddb8212 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 2d791dd4a469d6c..3a96b8b602204e7 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 b7982d3609e052f..a9e725672064077 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/ambiq/apollo4x/linker.ld b/soc/arm/ambiq/apollo4x/linker.ld deleted file mode 100644 index ab996aa99392712..000000000000000 --- a/soc/arm/ambiq/apollo4x/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2023 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/arm/beetle/CMakeLists.txt b/soc/arm/arm/beetle/CMakeLists.txt index 3fd95157dfc9a30..e911f5faab50671 100644 --- a/soc/arm/arm/beetle/CMakeLists.txt +++ b/soc/arm/arm/beetle/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_sources( soc.c power.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/arm/beetle/linker.ld b/soc/arm/arm/beetle/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/arm/beetle/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/arm/designstart/CMakeLists.txt b/soc/arm/arm/designstart/CMakeLists.txt index 9881313609aae2c..5d2598e239b056c 100644 --- a/soc/arm/arm/designstart/CMakeLists.txt +++ b/soc/arm/arm/designstart/CMakeLists.txt @@ -1 +1,3 @@ # SPDX-License-Identifier: Apache-2.0 + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/arm/designstart/linker.ld b/soc/arm/arm/designstart/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/arm/designstart/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/arm/designstart/soc.h b/soc/arm/arm/designstart/soc.h index ec58467f923c47e..a9bcdb4e9cd139d 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/fvp_aemv8r_aarch32/CMakeLists.txt b/soc/arm/arm/fvp_aemv8r_aarch32/CMakeLists.txt index 01b4ede7dfa5b2a..d9264843fae8574 100644 --- a/soc/arm/arm/fvp_aemv8r_aarch32/CMakeLists.txt +++ b/soc/arm/arm/fvp_aemv8r_aarch32/CMakeLists.txt @@ -3,3 +3,5 @@ zephyr_library_sources_ifdef(CONFIG_ARM_MPU arm_mpu_regions.c) zephyr_library_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/arm/fvp_aemv8r_aarch32/Kconfig.soc b/soc/arm/arm/fvp_aemv8r_aarch32/Kconfig.soc index a7f2131e065eced..6993cfe715abae1 100644 --- a/soc/arm/arm/fvp_aemv8r_aarch32/Kconfig.soc +++ b/soc/arm/arm/fvp_aemv8r_aarch32/Kconfig.soc @@ -10,7 +10,7 @@ config SOC_FVP_AEMV8R_AARCH32 select CPU_CORTEX_R52 select CPU_HAS_ARM_MPU select CPU_HAS_MPU - select VFP_DP_D32_FP16_FMAC + select VFP_DP_D32_FP16_FMAC if !USE_SWITCH select GIC_V3 select GIC_SINGLE_SECURITY_STATE select PLATFORM_SPECIFIC_INIT diff --git a/soc/arm/arm/fvp_aemv8r_aarch32/linker.ld b/soc/arm/arm/fvp_aemv8r_aarch32/linker.ld deleted file mode 100644 index 76b6c7a54501b21..000000000000000 --- a/soc/arm/arm/fvp_aemv8r_aarch32/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* - * linker.ld - Linker command/script file - * - * Copyright (c) 2022 IoT.bzh - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/arm/mps2/CMakeLists.txt b/soc/arm/arm/mps2/CMakeLists.txt index 332416ba43b0fe6..7424bb9f7b9bc80 100644 --- a/soc/arm/arm/mps2/CMakeLists.txt +++ b/soc/arm/arm/mps2/CMakeLists.txt @@ -3,3 +3,5 @@ zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/arm/mps2/linker.ld b/soc/arm/arm/mps2/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/arm/mps2/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/arm/mps2/soc.h b/soc/arm/arm/mps2/soc.h index 594d3d084c1fe85..822c7ee01bd26f7 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/CMakeLists.txt b/soc/arm/arm/mps3/CMakeLists.txt index a2566f7c5303b59..d82e1bc62c5dcd8 100644 --- a/soc/arm/arm/mps3/CMakeLists.txt +++ b/soc/arm/arm/mps3/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/arm/mps3/Kconfig.soc b/soc/arm/arm/mps3/Kconfig.soc index 86970e288cc8d0d..ae577fa549b1b76 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/linker.ld b/soc/arm/arm/mps3/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/arm/mps3/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/arm/mps3/soc.h b/soc/arm/arm/mps3/soc.h index 6a325074cf2d0b0..c3a59da1c0dcea4 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_b1/CMakeLists.txt b/soc/arm/arm/musca_b1/CMakeLists.txt index ae3f7d6c3be51fe..9c8a3b15eb23556 100644 --- a/soc/arm/arm/musca_b1/CMakeLists.txt +++ b/soc/arm/arm/musca_b1/CMakeLists.txt @@ -7,3 +7,5 @@ zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/arm/musca_b1/linker.ld b/soc/arm/arm/musca_b1/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/arm/musca_b1/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/arm/musca_s1/CMakeLists.txt b/soc/arm/arm/musca_s1/CMakeLists.txt index 2ceba388601b8f5..51df24c9b731520 100644 --- a/soc/arm/arm/musca_s1/CMakeLists.txt +++ b/soc/arm/arm/musca_s1/CMakeLists.txt @@ -3,3 +3,5 @@ # # SPDX-License-Identifier: Apache-2.0 # + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/arm/musca_s1/Kconfig.soc b/soc/arm/arm/musca_s1/Kconfig.soc index 9bf02614308bcd1..0c0763fae2a0add 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/arm/musca_s1/linker.ld b/soc/arm/arm/musca_s1/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/arm/musca_s1/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/aspeed/ast10x0/CMakeLists.txt b/soc/arm/aspeed/ast10x0/CMakeLists.txt index fc5628a425e944b..0d73ca4ba3459c6 100644 --- a/soc/arm/aspeed/ast10x0/CMakeLists.txt +++ b/soc/arm/aspeed/ast10x0/CMakeLists.txt @@ -13,3 +13,5 @@ set_property(GLOBAL APPEND PROPERTY extra_post_build_commands ${PROJECT_BINARY_DIR}/${CONFIG_KERNEL_BIN_NAME}.bin ${PROJECT_BINARY_DIR}/uart_${CONFIG_KERNEL_BIN_NAME}.bin ) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/aspeed/ast10x0/soc.h b/soc/arm/aspeed/ast10x0/soc.h index f45df84c12832c9..be1cced5da2886d 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 7b57af36217bc88..3fe8bdd1d6d21ba 100644 --- a/soc/arm/atmel_sam/common/CMakeLists.txt +++ b/soc/arm/atmel_sam/common/CMakeLists.txt @@ -3,6 +3,10 @@ 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) zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_SAM4L soc_sam4l_gpio.c) +zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_SAM4L soc_sam4l_poweroff.c) diff --git a/soc/arm/atmel_sam/common/soc_pmc.h b/soc/arm/atmel_sam/common/soc_pmc.h index 8f31e24dbbe80f1..3be251a3d09fcb8 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 000000000000000..08499b98b102eb8 --- /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/common/soc_poweroff.c b/soc/arm/atmel_sam/common/soc_poweroff.c new file mode 100644 index 000000000000000..7cc17f02018ab3e --- /dev/null +++ b/soc/arm/atmel_sam/common/soc_poweroff.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Bjarki Arge Andreasen + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* + * Poweroff will make the chip enter the backup low-power mode, which + * achieves the lowest possible power consumption. Wakeup from this mode + * requires enabling a wakeup source or input, or power cycling the device. + */ + +static void soc_core_sleepdeep_enable(void) +{ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; +} + +static void soc_core_sleepdeep_wait(void) +{ + __WFE(); + __WFI(); +} + +void z_sys_poweroff(void) +{ + soc_core_sleepdeep_enable(); + soc_supc_core_voltage_regulator_off(); + soc_core_sleepdeep_wait(); + + CODE_UNREACHABLE; +} diff --git a/soc/arm/atmel_sam/common/soc_sam4l_poweroff.c b/soc/arm/atmel_sam/common/soc_sam4l_poweroff.c new file mode 100644 index 000000000000000..ecadfe2d8f07b5e --- /dev/null +++ b/soc/arm/atmel_sam/common/soc_sam4l_poweroff.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Bjarki Arge Andreasen + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* + * Poweroff will make the chip enter the backup low-power mode, which + * achieves the lowest possible power consumption. Wakeup from this mode + * requires enabling a wakeup source or input, or power cycling the device. + */ + +static void soc_core_sleepdeep_enable(void) +{ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; +} + +static void soc_core_sleepdeep_wait(void) +{ + __WFE(); + __WFI(); +} + +void z_sys_poweroff(void) +{ + soc_core_sleepdeep_enable(); + BPM->PMCON |= BPM_PMCON_BKUP; + soc_core_sleepdeep_wait(); + + CODE_UNREACHABLE; +} diff --git a/soc/arm/atmel_sam/common/soc_supc.c b/soc/arm/atmel_sam/common/soc_supc.c new file mode 100644 index 000000000000000..cf6ce80ab2cd141 --- /dev/null +++ b/soc/arm/atmel_sam/common/soc_supc.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Bjarki Arge Andreasen + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define SOC_SUPC_WAKEUP_SOURCE_IDS (3) + +void soc_supc_core_voltage_regulator_off(void) +{ + SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_VROFF_STOP_VREG; +} + +void soc_supc_slow_clock_select_crystal_osc(void) +{ + SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL_CRYSTAL_SEL; + + /* Wait for oscillator to be stabilized. */ + while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) { + } +} + +void soc_supc_enable_wakeup_source(uint32_t wakeup_source_id) +{ + __ASSERT(wakeup_source_id <= SOC_SUPC_WAKEUP_SOURCE_IDS, + "Wakeup source channel is invalid"); + + SUPC->SUPC_WUMR |= 1 << wakeup_source_id; +} diff --git a/soc/arm/atmel_sam/common/soc_supc.h b/soc/arm/atmel_sam/common/soc_supc.h new file mode 100644 index 000000000000000..b925eb5f18cac0f --- /dev/null +++ b/soc/arm/atmel_sam/common/soc_supc.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Bjarki Arge Andreasen + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ATMEL_SAM_SOC_SUPC_H_ +#define _ATMEL_SAM_SOC_SUPC_H_ + +#include + +/** + * @brief Enable the clock of specified peripheral module. + */ +void soc_supc_core_voltage_regulator_off(void); + +/** + * @brief Switch slow clock source to external crystal oscillator + */ +void soc_supc_slow_clock_select_crystal_osc(void); + +/** + * @brief Enable wakeup source + */ +void soc_supc_enable_wakeup_source(uint32_t wakeup_source_id); + +#endif /* _ATMEL_SAM_SOC_SUPC_H_ */ diff --git a/soc/arm/atmel_sam/sam3x/CMakeLists.txt b/soc/arm/atmel_sam/sam3x/CMakeLists.txt index 332416ba43b0fe6..7424bb9f7b9bc80 100644 --- a/soc/arm/atmel_sam/sam3x/CMakeLists.txt +++ b/soc/arm/atmel_sam/sam3x/CMakeLists.txt @@ -3,3 +3,5 @@ zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/atmel_sam/sam3x/Kconfig.series b/soc/arm/atmel_sam/sam3x/Kconfig.series index 911eab6b1cc7a6a..08a3781b6d3ea19 100644 --- a/soc/arm/atmel_sam/sam3x/Kconfig.series +++ b/soc/arm/atmel_sam/sam3x/Kconfig.series @@ -15,6 +15,7 @@ config SOC_SERIES_SAM3X select SOC_FAMILY_SAM select PLATFORM_SPECIFIC_INIT select ASF + select HAS_POWEROFF help Enable support for Atmel SAM3X Cortex-M3 microcontrollers. Part No.: SAM3X8E diff --git a/soc/arm/atmel_sam/sam3x/linker.ld b/soc/arm/atmel_sam/sam3x/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/atmel_sam/sam3x/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam/sam3x/soc.c b/soc/arm/atmel_sam/sam3x/soc.c index 6f85c2c69d7df9b..9a20d5663753178 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/sam3x/soc.h b/soc/arm/atmel_sam/sam3x/soc.h index 0d7842fac1c04a3..3fe78a7e6ba7b0b 100644 --- a/soc/arm/atmel_sam/sam3x/soc.h +++ b/soc/arm/atmel_sam/sam3x/soc.h @@ -38,6 +38,7 @@ #include "../common/soc_pmc.h" #include "../common/soc_gpio.h" +#include "../common/soc_supc.h" #include "../common/atmel_sam_dt.h" /** Processor Clock (HCLK) Frequency */ diff --git a/soc/arm/atmel_sam/sam4e/CMakeLists.txt b/soc/arm/atmel_sam/sam4e/CMakeLists.txt index 332416ba43b0fe6..7424bb9f7b9bc80 100644 --- a/soc/arm/atmel_sam/sam4e/CMakeLists.txt +++ b/soc/arm/atmel_sam/sam4e/CMakeLists.txt @@ -3,3 +3,5 @@ zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/atmel_sam/sam4e/Kconfig.series b/soc/arm/atmel_sam/sam4e/Kconfig.series index 612e1d20bd62e2b..93cc0e20a483652 100644 --- a/soc/arm/atmel_sam/sam4e/Kconfig.series +++ b/soc/arm/atmel_sam/sam4e/Kconfig.series @@ -15,6 +15,7 @@ config SOC_SERIES_SAM4E select SOC_FAMILY_SAM select PLATFORM_SPECIFIC_INIT select ASF + select HAS_POWEROFF help Enable support for Atmel SAM4E Cortex-M4 microcontrollers. Part No.: SAM4E16E, SAM4E16C, SAM4E8E, SAM4E8C diff --git a/soc/arm/atmel_sam/sam4e/linker.ld b/soc/arm/atmel_sam/sam4e/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/atmel_sam/sam4e/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam/sam4e/soc.c b/soc/arm/atmel_sam/sam4e/soc.c index 33a8dd0d25fd5d1..b1c8174fddcf619 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/sam4e/soc.h b/soc/arm/atmel_sam/sam4e/soc.h index 523c5487748f8cf..290653e148ab8d9 100644 --- a/soc/arm/atmel_sam/sam4e/soc.h +++ b/soc/arm/atmel_sam/sam4e/soc.h @@ -38,6 +38,7 @@ #include "../common/soc_pmc.h" #include "../common/soc_gpio.h" +#include "../common/soc_supc.h" #include "../common/atmel_sam_dt.h" /** Processor Clock (HCLK) Frequency */ diff --git a/soc/arm/atmel_sam/sam4l/CMakeLists.txt b/soc/arm/atmel_sam/sam4l/CMakeLists.txt index 332416ba43b0fe6..7424bb9f7b9bc80 100644 --- a/soc/arm/atmel_sam/sam4l/CMakeLists.txt +++ b/soc/arm/atmel_sam/sam4l/CMakeLists.txt @@ -3,3 +3,5 @@ zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/atmel_sam/sam4l/Kconfig.series b/soc/arm/atmel_sam/sam4l/Kconfig.series index 7a41ba2ff246d75..0a8192f5bd9fddb 100644 --- a/soc/arm/atmel_sam/sam4l/Kconfig.series +++ b/soc/arm/atmel_sam/sam4l/Kconfig.series @@ -10,6 +10,7 @@ config SOC_SERIES_SAM4L select SOC_FAMILY_SAM select PLATFORM_SPECIFIC_INIT select ASF + select HAS_POWEROFF help Enable support for Atmel SAM4L Cortex-M4 microcontrollers. Part No.: SAM4LS8C, SAM4LS8B, SAM4LS8A, SAM4LS4C, SAM4LS4B, diff --git a/soc/arm/atmel_sam/sam4l/linker.ld b/soc/arm/atmel_sam/sam4l/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/atmel_sam/sam4l/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam/sam4s/CMakeLists.txt b/soc/arm/atmel_sam/sam4s/CMakeLists.txt index 332416ba43b0fe6..7424bb9f7b9bc80 100644 --- a/soc/arm/atmel_sam/sam4s/CMakeLists.txt +++ b/soc/arm/atmel_sam/sam4s/CMakeLists.txt @@ -3,3 +3,5 @@ zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/atmel_sam/sam4s/Kconfig.series b/soc/arm/atmel_sam/sam4s/Kconfig.series index 34fe0ce55f2789c..f591d96ba88e3a6 100644 --- a/soc/arm/atmel_sam/sam4s/Kconfig.series +++ b/soc/arm/atmel_sam/sam4s/Kconfig.series @@ -14,6 +14,7 @@ config SOC_SERIES_SAM4S select SOC_FAMILY_SAM select PLATFORM_SPECIFIC_INIT select ASF + select HAS_POWEROFF help Enable support for Atmel SAM4S Cortex-M4 microcontrollers. Part No.: SAM4S16C, SAM4S16B, SAM4S8C, SAM4S8B, diff --git a/soc/arm/atmel_sam/sam4s/linker.ld b/soc/arm/atmel_sam/sam4s/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/atmel_sam/sam4s/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam/sam4s/soc.c b/soc/arm/atmel_sam/sam4s/soc.c index e1041f8a2fcf359..5efaa35e894986a 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/sam4s/soc.h b/soc/arm/atmel_sam/sam4s/soc.h index e469c3ac19a72fa..ec3ab20471e87be 100644 --- a/soc/arm/atmel_sam/sam4s/soc.h +++ b/soc/arm/atmel_sam/sam4s/soc.h @@ -52,6 +52,7 @@ #include "../common/soc_pmc.h" #include "../common/soc_gpio.h" +#include "../common/soc_supc.h" #include "../common/atmel_sam_dt.h" /** Processor Clock (HCLK) Frequency */ diff --git a/soc/arm/atmel_sam/same70/CMakeLists.txt b/soc/arm/atmel_sam/same70/CMakeLists.txt index 0ad494174ddcae3..8373266d4ec020a 100644 --- a/soc/arm/atmel_sam/same70/CMakeLists.txt +++ b/soc/arm/atmel_sam/same70/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_sources( soc.c soc_config.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/atmel_sam/same70/Kconfig.series b/soc/arm/atmel_sam/same70/Kconfig.series index f8955bd4a769a50..4e7d6aa396e94db 100644 --- a/soc/arm/atmel_sam/same70/Kconfig.series +++ b/soc/arm/atmel_sam/same70/Kconfig.series @@ -11,11 +11,15 @@ 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 select XIP + select HAS_POWEROFF help Enable support for Atmel SAM E70 ARM Cortex-M7 Microcontrollers. Part No.: SAME70J19, SAME70J20, SAME70J21, SAME70N19, SAME70N20, diff --git a/soc/arm/atmel_sam/same70/linker.ld b/soc/arm/atmel_sam/same70/linker.ld deleted file mode 100644 index cb361723b39be1e..000000000000000 --- a/soc/arm/atmel_sam/same70/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam/same70/soc.c b/soc/arm/atmel_sam/same70/soc.c index 79d7c9fa830ee79..02ebce73c6de904 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/same70/soc.h b/soc/arm/atmel_sam/same70/soc.h index 37f10e2792a0af0..ad72b4d2ef0b698 100644 --- a/soc/arm/atmel_sam/same70/soc.h +++ b/soc/arm/atmel_sam/same70/soc.h @@ -64,6 +64,7 @@ #include "../common/soc_pmc.h" #include "../common/soc_gpio.h" +#include "../common/soc_supc.h" #include "../common/atmel_sam_dt.h" /** Processor Clock (HCLK) Frequency */ diff --git a/soc/arm/atmel_sam/samv71/CMakeLists.txt b/soc/arm/atmel_sam/samv71/CMakeLists.txt index 0ad494174ddcae3..8373266d4ec020a 100644 --- a/soc/arm/atmel_sam/samv71/CMakeLists.txt +++ b/soc/arm/atmel_sam/samv71/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_sources( soc.c soc_config.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/atmel_sam/samv71/Kconfig.series b/soc/arm/atmel_sam/samv71/Kconfig.series index 75072eec1eeee2a..cadee35acb52194 100644 --- a/soc/arm/atmel_sam/samv71/Kconfig.series +++ b/soc/arm/atmel_sam/samv71/Kconfig.series @@ -11,11 +11,15 @@ 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 select XIP + select HAS_POWEROFF help Enable support for Atmel SAM V71 ARM Cortex-M7 Microcontrollers. Part No.: SAMV71J19, SAMV71J20, SAMV71J21, SAMV71N19, SAMV71N20, diff --git a/soc/arm/atmel_sam/samv71/linker.ld b/soc/arm/atmel_sam/samv71/linker.ld deleted file mode 100644 index cb361723b39be1e..000000000000000 --- a/soc/arm/atmel_sam/samv71/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam/samv71/soc.c b/soc/arm/atmel_sam/samv71/soc.c index 7571ce46dc71085..6e82b9fe2f63c6a 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_sam/samv71/soc.h b/soc/arm/atmel_sam/samv71/soc.h index 264f92c5172e62d..4c85be421360752 100644 --- a/soc/arm/atmel_sam/samv71/soc.h +++ b/soc/arm/atmel_sam/samv71/soc.h @@ -65,6 +65,7 @@ #include "../common/soc_pmc.h" #include "../common/soc_gpio.h" +#include "../common/soc_supc.h" #include "../common/atmel_sam_dt.h" /** Processor Clock (HCLK) Frequency */ diff --git a/soc/arm/atmel_sam0/common/CMakeLists.txt b/soc/arm/atmel_sam0/common/CMakeLists.txt index 53f54da8a787ffb..6dd4525f2d2bd88 100644 --- a/soc/arm/atmel_sam0/common/CMakeLists.txt +++ b/soc/arm/atmel_sam0/common/CMakeLists.txt @@ -23,3 +23,5 @@ zephyr_sources_ifdef(CONFIG_SOC_SERIES_SAME53 soc_samd5x.c) zephyr_sources_ifdef(CONFIG_SOC_SERIES_SAME54 soc_samd5x.c) zephyr_include_directories(.) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/atmel_sam0/common/Kconfig.defconfig.series b/soc/arm/atmel_sam0/common/Kconfig.defconfig.series index ef6e1e0ff8304cc..8d9068424fd314d 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 bc488ab724c8727..b15108ead8c0448 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() diff --git a/soc/arm/atmel_sam0/common/soc_saml2x.c b/soc/arm/atmel_sam0/common/soc_saml2x.c index c4c1a659dd668b8..6f29f9c525dc6e7 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/samc20/linker.ld b/soc/arm/atmel_sam0/samc20/linker.ld deleted file mode 100644 index 745c7ad8b2a7e14..000000000000000 --- a/soc/arm/atmel_sam0/samc20/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2017 Google LLC. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam0/samc21/Kconfig.series b/soc/arm/atmel_sam0/samc21/Kconfig.series index 044a7aea229d70a..acb83679e18ea63 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/samc21/linker.ld b/soc/arm/atmel_sam0/samc21/linker.ld deleted file mode 100644 index 745c7ad8b2a7e14..000000000000000 --- a/soc/arm/atmel_sam0/samc21/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2017 Google LLC. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam0/samd20/linker.ld b/soc/arm/atmel_sam0/samd20/linker.ld deleted file mode 100644 index 75ef287b6d9b374..000000000000000 --- a/soc/arm/atmel_sam0/samd20/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2018 Sean Nyekjaer - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam0/samd21/linker.ld b/soc/arm/atmel_sam0/samd21/linker.ld deleted file mode 100644 index 745c7ad8b2a7e14..000000000000000 --- a/soc/arm/atmel_sam0/samd21/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2017 Google LLC. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam0/samd51/linker.ld b/soc/arm/atmel_sam0/samd51/linker.ld deleted file mode 100644 index 745c7ad8b2a7e14..000000000000000 --- a/soc/arm/atmel_sam0/samd51/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2017 Google LLC. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam0/same51/linker.ld b/soc/arm/atmel_sam0/same51/linker.ld deleted file mode 100644 index 745c7ad8b2a7e14..000000000000000 --- a/soc/arm/atmel_sam0/same51/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2017 Google LLC. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam0/same51/soc.h b/soc/arm/atmel_sam0/same51/soc.h index 64550333855beb5..746a001be69ece3 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/same53/linker.ld b/soc/arm/atmel_sam0/same53/linker.ld deleted file mode 100644 index 745c7ad8b2a7e14..000000000000000 --- a/soc/arm/atmel_sam0/same53/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2017 Google LLC. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam0/same54/linker.ld b/soc/arm/atmel_sam0/same54/linker.ld deleted file mode 100644 index 745c7ad8b2a7e14..000000000000000 --- a/soc/arm/atmel_sam0/same54/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2017 Google LLC. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam0/same54/soc.h b/soc/arm/atmel_sam0/same54/soc.h index 4f49e68c31ffd85..b62eead707e488d 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/atmel_sam0/saml21/linker.ld b/soc/arm/atmel_sam0/saml21/linker.ld deleted file mode 100644 index 6b4498f0932273e..000000000000000 --- a/soc/arm/atmel_sam0/saml21/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2021 Argentum Systems Ltd. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam0/samr21/linker.ld b/soc/arm/atmel_sam0/samr21/linker.ld deleted file mode 100644 index 745c7ad8b2a7e14..000000000000000 --- a/soc/arm/atmel_sam0/samr21/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2017 Google LLC. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam0/samr34/linker.ld b/soc/arm/atmel_sam0/samr34/linker.ld deleted file mode 100644 index 6b4498f0932273e..000000000000000 --- a/soc/arm/atmel_sam0/samr34/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2021 Argentum Systems Ltd. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/atmel_sam0/samr35/linker.ld b/soc/arm/atmel_sam0/samr35/linker.ld deleted file mode 100644 index 6b4498f0932273e..000000000000000 --- a/soc/arm/atmel_sam0/samr35/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2021 Argentum Systems Ltd. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/bcm_vk/valkyrie/CMakeLists.txt b/soc/arm/bcm_vk/valkyrie/CMakeLists.txt index f75aec6b3117686..f5ca7d6435ecf2c 100644 --- a/soc/arm/bcm_vk/valkyrie/CMakeLists.txt +++ b/soc/arm/bcm_vk/valkyrie/CMakeLists.txt @@ -1,3 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_include_directories(.) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/bcm_vk/valkyrie/linker.ld b/soc/arm/bcm_vk/valkyrie/linker.ld deleted file mode 100644 index a17ecaeaf3250bb..000000000000000 --- a/soc/arm/bcm_vk/valkyrie/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ -/* - * Copyright 2019 Broadcom. - */ - - -#include diff --git a/soc/arm/bcm_vk/valkyrie/soc.h b/soc/arm/bcm_vk/valkyrie/soc.h index 26863fbfea0f507..c3e21a895815487 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/CMakeLists.txt b/soc/arm/bcm_vk/viper/CMakeLists.txt index 3b465dc7da8992c..b81c75442e12453 100644 --- a/soc/arm/bcm_vk/viper/CMakeLists.txt +++ b/soc/arm/bcm_vk/viper/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_include_directories(.) zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/bcm_vk/viper/linker.ld b/soc/arm/bcm_vk/viper/linker.ld deleted file mode 100644 index c3ea22e3564f919..000000000000000 --- a/soc/arm/bcm_vk/viper/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2020 Broadcom - * - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include diff --git a/soc/arm/bcm_vk/viper/linker_m7.ld b/soc/arm/bcm_vk/viper/linker_m7.ld deleted file mode 100644 index 670bb23c78be880..000000000000000 --- a/soc/arm/bcm_vk/viper/linker_m7.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright 2020 Broadcom - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/bcm_vk/viper/soc.h b/soc/arm/bcm_vk/viper/soc.h index 6695e92ef5cce2b..06bf59fb24dd682 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/common/cortex_m/CMakeLists.txt b/soc/arm/common/cortex_m/CMakeLists.txt deleted file mode 100644 index f60166047268724..000000000000000 --- a/soc/arm/common/cortex_m/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -if(CONFIG_ARM_MPU AND NOT CONFIG_CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS) - - zephyr_library() - - zephyr_library_sources_ifdef(CONFIG_CPU_HAS_ARM_MPU - arm_mpu_regions.c - ) - zephyr_library_sources_ifdef(CONFIG_CPU_HAS_NXP_MPU - nxp_mpu_regions.c - ) -endif() diff --git a/soc/arm/cypress/Kconfig b/soc/arm/cypress/Kconfig index 352c66b4e7616f1..cb76ccb10902502 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/cypress/psoc6/CMakeLists.txt b/soc/arm/cypress/psoc6/CMakeLists.txt index a88416cda13de87..e2ea2eb6ae1e455 100644 --- a/soc/arm/cypress/psoc6/CMakeLists.txt +++ b/soc/arm/cypress/psoc6/CMakeLists.txt @@ -12,3 +12,5 @@ zephyr_sources( zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_PSOC6 NOINIT noinit.ld) zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_PSOC6 RWDATA rwdata.ld) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/cypress/psoc6/linker.ld b/soc/arm/cypress/psoc6/linker.ld deleted file mode 100644 index e0657c31ee5e836..000000000000000 --- a/soc/arm/cypress/psoc6/linker.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2018 Cypress - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images and XIP images. - */ - - -#include 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 000000000000000..69f21b210d08a2f --- /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 000000000000000..b6fae5d43ec6ae9 --- /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 000000000000000..20a2f4c8cb402d3 --- /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/gd_gd32/gd32a50x/CMakeLists.txt b/soc/arm/gd_gd32/gd32a50x/CMakeLists.txt new file mode 100644 index 000000000000000..033272f36193faa --- /dev/null +++ b/soc/arm/gd_gd32/gd32a50x/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2022 YuLong Yao +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) +zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") 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 000000000000000..0b250325c457e20 --- /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 000000000000000..2488c643727dd98 --- /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/gd_gd32/gd32e10x/CMakeLists.txt b/soc/arm/gd_gd32/gd32e10x/CMakeLists.txt new file mode 100644 index 000000000000000..18c19936f9f7bd3 --- /dev/null +++ b/soc/arm/gd_gd32/gd32e10x/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2021 YuLong Yao +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) +zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") 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 000000000000000..f16328e1e70ec60 --- /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/gd_gd32/gd32e50x/CMakeLists.txt b/soc/arm/gd_gd32/gd32e50x/CMakeLists.txt new file mode 100644 index 000000000000000..bcb019aac62560c --- /dev/null +++ b/soc/arm/gd_gd32/gd32e50x/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2022, Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) +zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") 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 000000000000000..f771aea44d912c9 --- /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 000000000000000..546ca45679341cb --- /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/gd_gd32/gd32f3x0/CMakeLists.txt b/soc/arm/gd_gd32/gd32f3x0/CMakeLists.txt new file mode 100644 index 000000000000000..a6856dbe680841c --- /dev/null +++ b/soc/arm/gd_gd32/gd32f3x0/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2021 BrainCo Inc. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) +zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") 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 000000000000000..4852255d255df3b --- /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/gd_gd32/gd32f403/CMakeLists.txt b/soc/arm/gd_gd32/gd32f403/CMakeLists.txt new file mode 100644 index 000000000000000..af30be8f73744b2 --- /dev/null +++ b/soc/arm/gd_gd32/gd32f403/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2021, ATL Electronics +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) +zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") 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 000000000000000..8923e1582a32c7a --- /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/gd_gd32/gd32f4xx/CMakeLists.txt b/soc/arm/gd_gd32/gd32f4xx/CMakeLists.txt new file mode 100644 index 000000000000000..dd55a9bcdb1afa1 --- /dev/null +++ b/soc/arm/gd_gd32/gd32f4xx/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2021, Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) +zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") 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 000000000000000..a4ccaed4e802f21 --- /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/gd_gd32/gd32l23x/CMakeLists.txt b/soc/arm/gd_gd32/gd32l23x/CMakeLists.txt new file mode 100644 index 000000000000000..217e69409261234 --- /dev/null +++ b/soc/arm/gd_gd32/gd32l23x/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2022 BrainCo Inc. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) +zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") 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 000000000000000..36a6476dbfbc6ac --- /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 000000000000000..d6125ca4152fedf --- /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 1facd4ceeda4e73..000000000000000 --- 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 1aa259661639713..000000000000000 --- 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 897238ff3fbec0e..000000000000000 --- 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/CMakeLists.txt b/soc/arm/gigadevice/gd32a50x/CMakeLists.txt deleted file mode 100644 index 6691c4896483983..000000000000000 --- a/soc/arm/gigadevice/gd32a50x/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2022 YuLong Yao -# SPDX-License-Identifier: Apache-2.0 - -zephyr_include_directories(.) -zephyr_sources(soc.c) diff --git a/soc/arm/gigadevice/gd32a50x/Kconfig.defconfig.series b/soc/arm/gigadevice/gd32a50x/Kconfig.defconfig.series deleted file mode 100644 index d9e48ae18c2faed..000000000000000 --- 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 96fc8c1d0af7143..000000000000000 --- 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/gd32a50x/linker.ld b/soc/arm/gigadevice/gd32a50x/linker.ld deleted file mode 100644 index 34a8f747bdc1ec5..000000000000000 --- a/soc/arm/gigadevice/gd32a50x/linker.ld +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright (c) 2021 Teslabs Engineering S.L. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/gigadevice/gd32e10x/CMakeLists.txt b/soc/arm/gigadevice/gd32e10x/CMakeLists.txt deleted file mode 100644 index 58df401dc74f3dd..000000000000000 --- a/soc/arm/gigadevice/gd32e10x/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2021 YuLong Yao -# SPDX-License-Identifier: Apache-2.0 - -zephyr_include_directories(.) -zephyr_sources(soc.c) diff --git a/soc/arm/gigadevice/gd32e10x/Kconfig.defconfig.series b/soc/arm/gigadevice/gd32e10x/Kconfig.defconfig.series deleted file mode 100644 index 5a17c08d864710b..000000000000000 --- 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/gd32e10x/linker.ld b/soc/arm/gigadevice/gd32e10x/linker.ld deleted file mode 100644 index 1223f99d9293efe..000000000000000 --- a/soc/arm/gigadevice/gd32e10x/linker.ld +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright (c) 2021 YuLong Yao - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/gigadevice/gd32e50x/CMakeLists.txt b/soc/arm/gigadevice/gd32e50x/CMakeLists.txt deleted file mode 100644 index d320b8ec86eef3e..000000000000000 --- a/soc/arm/gigadevice/gd32e50x/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2022, Teslabs Engineering S.L. -# SPDX-License-Identifier: Apache-2.0 - -zephyr_include_directories(.) -zephyr_sources(soc.c) diff --git a/soc/arm/gigadevice/gd32e50x/Kconfig.defconfig.series b/soc/arm/gigadevice/gd32e50x/Kconfig.defconfig.series deleted file mode 100644 index 3a05359fd4a2ae9..000000000000000 --- 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 8bc3f71118ecc49..000000000000000 --- 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/gd32e50x/linker.ld b/soc/arm/gigadevice/gd32e50x/linker.ld deleted file mode 100644 index 34a8f747bdc1ec5..000000000000000 --- a/soc/arm/gigadevice/gd32e50x/linker.ld +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright (c) 2021 Teslabs Engineering S.L. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/gigadevice/gd32f3x0/CMakeLists.txt b/soc/arm/gigadevice/gd32f3x0/CMakeLists.txt deleted file mode 100644 index 012b6cddc94a8ad..000000000000000 --- a/soc/arm/gigadevice/gd32f3x0/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2021 BrainCo Inc. -# SPDX-License-Identifier: Apache-2.0 - -zephyr_include_directories(.) -zephyr_sources(soc.c) diff --git a/soc/arm/gigadevice/gd32f3x0/Kconfig.defconfig.series b/soc/arm/gigadevice/gd32f3x0/Kconfig.defconfig.series deleted file mode 100644 index dc9607f11499670..000000000000000 --- 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/gd32f3x0/linker.ld b/soc/arm/gigadevice/gd32f3x0/linker.ld deleted file mode 100644 index 67650d4eb8dfb8c..000000000000000 --- a/soc/arm/gigadevice/gd32f3x0/linker.ld +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright (c) 2021 BrainCo Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/gigadevice/gd32f403/CMakeLists.txt b/soc/arm/gigadevice/gd32f403/CMakeLists.txt deleted file mode 100644 index 0003b5a9de275f8..000000000000000 --- a/soc/arm/gigadevice/gd32f403/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2021, ATL Electronics -# SPDX-License-Identifier: Apache-2.0 - -zephyr_include_directories(.) -zephyr_sources(soc.c) diff --git a/soc/arm/gigadevice/gd32f403/Kconfig.defconfig.series b/soc/arm/gigadevice/gd32f403/Kconfig.defconfig.series deleted file mode 100644 index dbec480c29968ca..000000000000000 --- 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/gd32f403/linker.ld b/soc/arm/gigadevice/gd32f403/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/gigadevice/gd32f403/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/gigadevice/gd32f4xx/CMakeLists.txt b/soc/arm/gigadevice/gd32f4xx/CMakeLists.txt deleted file mode 100644 index 9d80226466cf0fe..000000000000000 --- a/soc/arm/gigadevice/gd32f4xx/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2021, Teslabs Engineering S.L. -# SPDX-License-Identifier: Apache-2.0 - -zephyr_include_directories(.) -zephyr_sources(soc.c) diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.series b/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.series deleted file mode 100644 index f5ef03cd2765fbc..000000000000000 --- 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/gd32f4xx/linker.ld b/soc/arm/gigadevice/gd32f4xx/linker.ld deleted file mode 100644 index 34a8f747bdc1ec5..000000000000000 --- a/soc/arm/gigadevice/gd32f4xx/linker.ld +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright (c) 2021 Teslabs Engineering S.L. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/gigadevice/gd32l23x/CMakeLists.txt b/soc/arm/gigadevice/gd32l23x/CMakeLists.txt deleted file mode 100644 index 21581379afa2856..000000000000000 --- a/soc/arm/gigadevice/gd32l23x/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2022 BrainCo Inc. -# SPDX-License-Identifier: Apache-2.0 - -zephyr_include_directories(.) -zephyr_sources(soc.c) diff --git a/soc/arm/gigadevice/gd32l23x/Kconfig.defconfig.series b/soc/arm/gigadevice/gd32l23x/Kconfig.defconfig.series deleted file mode 100644 index da16d8f287ce216..000000000000000 --- 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 5bdb0dba7d3a3a8..000000000000000 --- 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/gigadevice/gd32l23x/linker.ld b/soc/arm/gigadevice/gd32l23x/linker.ld deleted file mode 100644 index 520d4ee69f0aad5..000000000000000 --- a/soc/arm/gigadevice/gd32l23x/linker.ld +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright (c) 2022 BrainCo Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/infineon_cat1/psoc6/CMakeLists.txt b/soc/arm/infineon_cat1/psoc6/CMakeLists.txt index e047fc704bb21d3..26c9fb8cd9c175a 100644 --- a/soc/arm/infineon_cat1/psoc6/CMakeLists.txt +++ b/soc/arm/infineon_cat1/psoc6/CMakeLists.txt @@ -17,3 +17,5 @@ zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1A RAM_SECTIONS SORT_K zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1A RAMFUNC_SECTION SORT_KEY 0 ram_func.ld) zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1 RODATA SORT_KEY 0 rom.ld) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/infineon_cat1/psoc6/linker.ld b/soc/arm/infineon_cat1/psoc6/linker.ld deleted file mode 100644 index 9af77e1c523176b..000000000000000 --- a/soc/arm/infineon_cat1/psoc6/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company) or - * an affiliate of Cypress Semiconductor Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/infineon_xmc/4xxx/CMakeLists.txt b/soc/arm/infineon_xmc/4xxx/CMakeLists.txt index 124571032e1e554..8216f9a09ee8be9 100644 --- a/soc/arm/infineon_xmc/4xxx/CMakeLists.txt +++ b/soc/arm/infineon_xmc/4xxx/CMakeLists.txt @@ -5,3 +5,5 @@ zephyr_sources(soc.c) zephyr_linker_sources(NOINIT noinit.ld) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/infineon_xmc/4xxx/Kconfig.series b/soc/arm/infineon_xmc/4xxx/Kconfig.series index 5bfdb994fe43bc5..7c7f9a85496fd36 100644 --- a/soc/arm/infineon_xmc/4xxx/Kconfig.series +++ b/soc/arm/infineon_xmc/4xxx/Kconfig.series @@ -20,5 +20,8 @@ config SOC_SERIES_XMC_4XXX select HAS_XMCLIB_SPI 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/linker.ld b/soc/arm/infineon_xmc/4xxx/linker.ld deleted file mode 100644 index 7a1df7beaa5248c..000000000000000 --- a/soc/arm/infineon_xmc/4xxx/linker.ld +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images and XIP images. - */ - -#include diff --git a/soc/arm/infineon_xmc/4xxx/soc.c b/soc/arm/infineon_xmc/4xxx/soc.c index 0d4060568a33b9a..44e83a63c6f4dd9 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/CMakeLists.txt b/soc/arm/intel_socfpga_std/cyclonev/CMakeLists.txt index 68f5199d81c1dda..4b94d9047e48317 100644 --- a/soc/arm/intel_socfpga_std/cyclonev/CMakeLists.txt +++ b/soc/arm/intel_socfpga_std/cyclonev/CMakeLists.txt @@ -5,3 +5,5 @@ zephyr_include_directories(.) zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/intel_socfpga_std/cyclonev/Kconfig.series b/soc/arm/intel_socfpga_std/cyclonev/Kconfig.series index cb0dc6984e391e2..e9fba7bdba24e86 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/intel_socfpga_std/cyclonev/linker.ld b/soc/arm/intel_socfpga_std/cyclonev/linker.ld deleted file mode 100644 index ef4c62338b44e62..000000000000000 --- a/soc/arm/intel_socfpga_std/cyclonev/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright (c) 2022 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - * Description: - * Adding support for Cyclone V SoC FPGA, using arm32 linker - */ - -#include diff --git a/soc/arm/microchip_mec/mec1501/CMakeLists.txt b/soc/arm/microchip_mec/mec1501/CMakeLists.txt index 70889bc982b9295..e92250a69891580 100644 --- a/soc/arm/microchip_mec/mec1501/CMakeLists.txt +++ b/soc/arm/microchip_mec/mec1501/CMakeLists.txt @@ -21,3 +21,5 @@ if(CONFIG_SOC_HAS_TIMING_FUNCTIONS AND NOT CONFIG_BOARD_HAS_TIMING_FUNCTIONS) 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/microchip_mec/mec1501/Kconfig.series b/soc/arm/microchip_mec/mec1501/Kconfig.series index d3b679bb557d8fc..92dc6f3f8f9f8fa 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/mec1501/linker.ld b/soc/arm/microchip_mec/mec1501/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/microchip_mec/mec1501/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/microchip_mec/mec172x/CMakeLists.txt b/soc/arm/microchip_mec/mec172x/CMakeLists.txt index 3581ce69b400edc..59f3b5e4d2bca76 100644 --- a/soc/arm/microchip_mec/mec172x/CMakeLists.txt +++ b/soc/arm/microchip_mec/mec172x/CMakeLists.txt @@ -21,3 +21,5 @@ if(CONFIG_SOC_HAS_TIMING_FUNCTIONS AND NOT CONFIG_BOARD_HAS_TIMING_FUNCTIONS) 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/microchip_mec/mec172x/Kconfig.defconfig.series b/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series index afee2b8a59b1620..d23de11262d1522 100644 --- a/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series +++ b/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series @@ -33,10 +33,4 @@ config PS2_XEC default y depends on PS2 -config PM - default y if SYS_CLOCK_EXISTS - -config PM_DEVICE - default n - endif # SOC_SERIES_MEC172X diff --git a/soc/arm/microchip_mec/mec172x/linker.ld b/soc/arm/microchip_mec/mec172x/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/microchip_mec/mec172x/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/microchip_mec/mec172x/soc.h b/soc/arm/microchip_mec/mec172x/soc.h index 3bf4f533fdb7754..19afc4e920a9685 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 4cfc162f7fdd760..3b097d73569f290 100644 --- a/soc/arm/nordic_nrf/CMakeLists.txt +++ b/soc/arm/nordic_nrf/CMakeLists.txt @@ -21,4 +21,12 @@ if(CONFIG_BUILD_WITH_TFM) set_property(TARGET zephyr_property_target APPEND PROPERTY TFM_CMAKE_OPTIONS -DHAL_NORDIC_PATH=${ZEPHYR_HAL_NORDIC_MODULE_DIR} ) + + set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS -DZEPHYR_BASE=${ZEPHYR_BASE} + ) + + set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS -DNRF_NS_STORAGE=${CONFIG_TFM_NRF_NS_STORAGE} + ) endif() diff --git a/soc/arm/nordic_nrf/Kconfig b/soc/arm/nordic_nrf/Kconfig index c2129db64b3b78f..f2a20321d6baf9a 100644 --- a/soc/arm/nordic_nrf/Kconfig +++ b/soc/arm/nordic_nrf/Kconfig @@ -25,6 +25,33 @@ config NRF_SOC_SECURE_SUPPORTED For non-secure the functions must redirect to secure services exposed by the secure firmware. +config BUILD_WITH_TFM + default y if TRUSTED_EXECUTION_NONSECURE + help + By default, if we build for a Non-Secure version of the board, + enable building with TF-M as the Secure Execution Environment. + +if BUILD_WITH_TFM + +config TFM_FLASH_MERGED_BINARY + default y + help + By default, if we build with TF-M, instruct build system to + flash the combined TF-M (Secure) & Zephyr (Non Secure) image + +config TFM_LOG_LEVEL_SILENCE + default y if !$(dt_nodelabel_has_prop,uart1,pinctrl-names) + help + Disable TF-M secure output if the uart1 node has not assigned GPIO + pins using pinctrl. + +config TFM_NRF_NS_STORAGE + bool "TF-M non-secure storage partition" + default y + +endif # BUILD_WITH_TFM + + config NRF_MPU_FLASH_REGION_SIZE hex default 0x1000 @@ -144,17 +171,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 3eedcf350c6cfc8..879217a92fed807 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 - 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/Kconfig.peripherals b/soc/arm/nordic_nrf/Kconfig.peripherals index 9a4152a6d84a5ae..5eeff856c968188 100644 --- a/soc/arm/nordic_nrf/Kconfig.peripherals +++ b/soc/arm/nordic_nrf/Kconfig.peripherals @@ -69,12 +69,30 @@ 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)) +config HAS_HW_NRF_I2S20 + def_bool $(dt_nodelabel_enabled_with_compat,i2s20,$(DT_COMPAT_NORDIC_NRF_I2S)) + config HAS_HW_NRF_IPC def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_IPC)) @@ -129,6 +147,18 @@ config HAS_HW_NRF_QDEC0 config HAS_HW_NRF_QDEC1 def_bool $(dt_nodelabel_enabled_with_compat,qdec1,$(DT_COMPAT_NORDIC_NRF_QDEC)) +config HAS_HW_NRF_QDEC20 + def_bool $(dt_nodelabel_enabled_with_compat,qdec20,$(DT_COMPAT_NORDIC_NRF_QDEC)) + +config HAS_HW_NRF_QDEC21 + def_bool $(dt_nodelabel_enabled_with_compat,qdec21,$(DT_COMPAT_NORDIC_NRF_QDEC)) + +config HAS_HW_NRF_QDEC130 + def_bool $(dt_nodelabel_enabled_with_compat,qdec130,$(DT_COMPAT_NORDIC_NRF_QDEC)) + +config HAS_HW_NRF_QDEC131 + def_bool $(dt_nodelabel_enabled_with_compat,qdec131,$(DT_COMPAT_NORDIC_NRF_QDEC)) + config HAS_HW_NRF_QSPI def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_QSPI)) @@ -192,6 +222,51 @@ config HAS_HW_NRF_SPIM3 config HAS_HW_NRF_SPIM4 def_bool $(dt_nodelabel_enabled_with_compat,spi4,$(DT_COMPAT_NORDIC_NRF_SPIM)) +config HAS_HW_NRF_SPIM00 + def_bool $(dt_nodelabel_enabled_with_compat,spi00,$(DT_COMPAT_NORDIC_NRF_SPIM)) + +config HAS_HW_NRF_SPIM20 + def_bool $(dt_nodelabel_enabled_with_compat,spi20,$(DT_COMPAT_NORDIC_NRF_SPIM)) + +config HAS_HW_NRF_SPIM21 + def_bool $(dt_nodelabel_enabled_with_compat,spi21,$(DT_COMPAT_NORDIC_NRF_SPIM)) + +config HAS_HW_NRF_SPIM22 + def_bool $(dt_nodelabel_enabled_with_compat,spi22,$(DT_COMPAT_NORDIC_NRF_SPIM)) + +config HAS_HW_NRF_SPIM30 + def_bool $(dt_nodelabel_enabled_with_compat,spi30,$(DT_COMPAT_NORDIC_NRF_SPIM)) + +config HAS_HW_NRF_SPIM120 + def_bool $(dt_nodelabel_enabled_with_compat,spi120,$(DT_COMPAT_NORDIC_NRF_SPIM)) + +config HAS_HW_NRF_SPIM121 + def_bool $(dt_nodelabel_enabled_with_compat,spi121,$(DT_COMPAT_NORDIC_NRF_SPIM)) + +config HAS_HW_NRF_SPIM130 + def_bool $(dt_nodelabel_enabled_with_compat,spi130,$(DT_COMPAT_NORDIC_NRF_SPIM)) + +config HAS_HW_NRF_SPIM131 + def_bool $(dt_nodelabel_enabled_with_compat,spi131,$(DT_COMPAT_NORDIC_NRF_SPIM)) + +config HAS_HW_NRF_SPIM132 + def_bool $(dt_nodelabel_enabled_with_compat,spi132,$(DT_COMPAT_NORDIC_NRF_SPIM)) + +config HAS_HW_NRF_SPIM133 + def_bool $(dt_nodelabel_enabled_with_compat,spi133,$(DT_COMPAT_NORDIC_NRF_SPIM)) + +config HAS_HW_NRF_SPIM134 + def_bool $(dt_nodelabel_enabled_with_compat,spi134,$(DT_COMPAT_NORDIC_NRF_SPIM)) + +config HAS_HW_NRF_SPIM135 + def_bool $(dt_nodelabel_enabled_with_compat,spi135,$(DT_COMPAT_NORDIC_NRF_SPIM)) + +config HAS_HW_NRF_SPIM136 + def_bool $(dt_nodelabel_enabled_with_compat,spi136,$(DT_COMPAT_NORDIC_NRF_SPIM)) + +config HAS_HW_NRF_SPIM137 + def_bool $(dt_nodelabel_enabled_with_compat,spi137,$(DT_COMPAT_NORDIC_NRF_SPIM)) + config HAS_HW_NRF_SPIS0 def_bool $(dt_nodelabel_enabled_with_compat,spi0,$(DT_COMPAT_NORDIC_NRF_SPIS)) @@ -243,6 +318,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)) @@ -261,6 +357,45 @@ config HAS_HW_NRF_TWIM2 config HAS_HW_NRF_TWIM3 def_bool $(dt_nodelabel_enabled_with_compat,i2c3,$(DT_COMPAT_NORDIC_NRF_TWIM)) +config HAS_HW_NRF_TWIM20 + def_bool $(dt_nodelabel_enabled_with_compat,i2c20,$(DT_COMPAT_NORDIC_NRF_TWIM)) + +config HAS_HW_NRF_TWIM21 + def_bool $(dt_nodelabel_enabled_with_compat,i2c21,$(DT_COMPAT_NORDIC_NRF_TWIM)) + +config HAS_HW_NRF_TWIM22 + def_bool $(dt_nodelabel_enabled_with_compat,i2c22,$(DT_COMPAT_NORDIC_NRF_TWIM)) + +config HAS_HW_NRF_TWIM30 + def_bool $(dt_nodelabel_enabled_with_compat,i2c30,$(DT_COMPAT_NORDIC_NRF_TWIM)) + +config HAS_HW_NRF_TWIM120 + def_bool $(dt_nodelabel_enabled_with_compat,i2c120,$(DT_COMPAT_NORDIC_NRF_TWIM)) + +config HAS_HW_NRF_TWIM130 + def_bool $(dt_nodelabel_enabled_with_compat,i2c130,$(DT_COMPAT_NORDIC_NRF_TWIM)) + +config HAS_HW_NRF_TWIM131 + def_bool $(dt_nodelabel_enabled_with_compat,i2c131,$(DT_COMPAT_NORDIC_NRF_TWIM)) + +config HAS_HW_NRF_TWIM132 + def_bool $(dt_nodelabel_enabled_with_compat,i2c132,$(DT_COMPAT_NORDIC_NRF_TWIM)) + +config HAS_HW_NRF_TWIM133 + def_bool $(dt_nodelabel_enabled_with_compat,i2c133,$(DT_COMPAT_NORDIC_NRF_TWIM)) + +config HAS_HW_NRF_TWIM134 + def_bool $(dt_nodelabel_enabled_with_compat,i2c134,$(DT_COMPAT_NORDIC_NRF_TWIM)) + +config HAS_HW_NRF_TWIM135 + def_bool $(dt_nodelabel_enabled_with_compat,i2c135,$(DT_COMPAT_NORDIC_NRF_TWIM)) + +config HAS_HW_NRF_TWIM136 + def_bool $(dt_nodelabel_enabled_with_compat,i2c136,$(DT_COMPAT_NORDIC_NRF_TWIM)) + +config HAS_HW_NRF_TWIM137 + def_bool $(dt_nodelabel_enabled_with_compat,i2c137,$(DT_COMPAT_NORDIC_NRF_TWIM)) + config HAS_HW_NRF_TWIS0 def_bool $(dt_nodelabel_enabled_with_compat,i2c0,$(DT_COMPAT_NORDIC_NRF_TWIS)) @@ -288,6 +423,21 @@ 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_USBD def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_USBD)) @@ -302,3 +452,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/CMakeLists.txt b/soc/arm/nordic_nrf/common/CMakeLists.txt index eb074dd054815b8..1c12813f2c33830 100644 --- a/soc/arm/nordic_nrf/common/CMakeLists.txt +++ b/soc/arm/nordic_nrf/common/CMakeLists.txt @@ -8,6 +8,6 @@ zephyr_include_directories(.) if (CONFIG_TFM_PARTITION_PLATFORM) zephyr_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 4c00d7c0237cb83..1e5e603967b5643 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 948f38547aa86ae..d38d66ab4889193 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 1a8b943ad5b3ed9..44d139e422a612e 100644 --- a/soc/arm/nordic_nrf/nrf51/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf51/CMakeLists.txt @@ -10,3 +10,5 @@ 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 "") diff --git a/soc/arm/nordic_nrf/nrf51/Kconfig.defconfig.series b/soc/arm/nordic_nrf/nrf51/Kconfig.defconfig.series index 8c0bc74c02f5c0d..a4053bf7fed0352 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/Kconfig.series b/soc/arm/nordic_nrf/nrf51/Kconfig.series index e7028b021909758..c484d44fc30fc9c 100644 --- a/soc/arm/nordic_nrf/nrf51/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf51/Kconfig.series @@ -9,7 +9,7 @@ config SOC_SERIES_NRF51X select ARM select CPU_CORTEX_M0 select SOC_FAMILY_NRF - select XIP + imply XIP select HAS_NRFX select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE select HAS_POWEROFF diff --git a/soc/arm/nordic_nrf/nrf51/linker.ld b/soc/arm/nordic_nrf/nrf51/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/nordic_nrf/nrf51/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/nordic_nrf/nrf51/soc.c b/soc/arm/nordic_nrf/nrf51/soc.c index 078a422c06b183f..af14f6f3003a23f 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, (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 24fdcf6093ec871..04e255a3eb12d89 100644 --- a/soc/arm/nordic_nrf/nrf52/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf52/CMakeLists.txt @@ -22,3 +22,5 @@ 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 4a7edf2aa95f656..2e89a5130a6810c 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/Kconfig.series b/soc/arm/nordic_nrf/nrf52/Kconfig.series index f11bd5cd59f5ab1..d47089cd5953d9e 100644 --- a/soc/arm/nordic_nrf/nrf52/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf52/Kconfig.series @@ -10,7 +10,7 @@ config SOC_SERIES_NRF52X select CPU_CORTEX_M4 select CPU_HAS_ARM_MPU select SOC_FAMILY_NRF - select XIP + imply XIP select HAS_NRFX select HAS_NORDIC_DRIVERS select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE diff --git a/soc/arm/nordic_nrf/nrf52/Kconfig.soc b/soc/arm/nordic_nrf/nrf52/Kconfig.soc index 517b4ce2baa3ded..de6a16129d37856 100644 --- a/soc/arm/nordic_nrf/nrf52/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf52/Kconfig.soc @@ -147,4 +147,12 @@ config NRF52_ANOMALY_109_WORKAROUND 64MHz clock at the same time as the peripheral that is using DMA is started. This anomaly applies to IC revisions up to "3", the most recent one. +config NRF52_ANOMALY_109_WORKAROUND_EGU_INSTANCE + int "Anomaly 109 workaround EGU instance" + depends on NRF52_ANOMALY_109_WORKAROUND + range 0 5 + default 5 + help + EGU instance used by the nRF52 Anomaly 109 workaround for PWM. + endif # SOC_SERIES_NRF52X diff --git a/soc/arm/nordic_nrf/nrf52/linker.ld b/soc/arm/nordic_nrf/nrf52/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/nordic_nrf/nrf52/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/nordic_nrf/nrf52/soc.c b/soc/arm/nordic_nrf/nrf52/soc.c index 52b97164e72bd5a..a6ef22468b16beb 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, (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 af4fe549a635469..b4e82f52c2886dd 100644 --- a/soc/arm/nordic_nrf/nrf53/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf53/CMakeLists.txt @@ -19,3 +19,5 @@ 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 0c0f9f059269277..f0f7f5a7d841808 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 88d53a3a0f7e941..0c60adc04f3b4b9 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 2857d5dd25ddfc6..7e5660cf514b3c9 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.series b/soc/arm/nordic_nrf/nrf53/Kconfig.series index 8ab81ad310bda5b..28d1c10fc1e2f7a 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.series @@ -11,7 +11,7 @@ config SOC_SERIES_NRF53X select CPU_CORTEX_M_HAS_DWT select CPU_HAS_ARM_MPU select SOC_FAMILY_NRF - select XIP + imply XIP select HAS_NRFX select HAS_NORDIC_DRIVERS select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.soc b/soc/arm/nordic_nrf/nrf53/Kconfig.soc index 2cd934af324f219..3ecf09ecd92ed14 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 @@ -98,6 +118,18 @@ config SOC_DCDC_NRF53X_HV help Enable nRF53 series System on Chip High Voltage DC/DC converter. +config NRF_SPU_FLASH_REGION_SIZE + hex + default 0x4000 + help + FLASH region size for the NRF_SPU peripheral + +config NRF_SPU_RAM_REGION_SIZE + hex + default 0x2000 + help + RAM region size for the NRF_SPU peripheral + config SOC_NRF_GPIO_FORWARDER_FOR_NRF5340 bool depends on NRF_SOC_SECURE_SUPPORTED @@ -188,78 +220,6 @@ config BUILD_WITH_TFM # TF-M nRF53 platform enables the cache unconditionally. select NRF_ENABLE_CACHE if SOC_NRF5340_CPUAPP -config NRF53_SYNC_RTC - bool "RTC clock synchronization" - default y if LOG && !LOG_MODE_MINIMAL - depends on NRF_RTC_TIMER - select NRFX_DPPI - select MBOX if !IPM - -if NRF53_SYNC_RTC - -module = SYNC_RTC -module-str = Synchronized RTC -source "subsys/logging/Kconfig.template.log_config" - -config NRF53_SYNC_RTC_INIT_PRIORITY - int "nRF53 Synchronized RTC init priority" - default APPLICATION_INIT_PRIORITY - help - nRF53 Synchronized RTC initialization priority. - -config NRF_RTC_TIMER_USER_CHAN_COUNT - default 2 if NRF_802154_RADIO_DRIVER && SOC_NRF5340_CPUNET - default 3 if NRF_802154_RADIO_DRIVER - default 1 +rsource "Kconfig.sync_rtc" -config NRF53_SYNC_RTC_LOG_TIMESTAMP - bool "Use Synchronized RTC for logging timestamp" - default y - -config NRF53_SYNC_RTC_IPM_OUT - int "IPM channel from APP to NET" - range 0 15 - default 7 if SOC_NRF5340_CPUAPP - default 8 - -config NRF53_SYNC_RTC_IPM_IN - int "IPM channel from APP to NET" - range 0 15 - default 8 if SOC_NRF5340_CPUAPP - default 7 - -ipm_num = 0 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 1 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 2 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 3 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 4 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 5 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 6 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 7 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 8 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 9 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 10 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 11 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 12 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 13 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 14 -rsource "Kconfig.sync_rtc_ipm" -ipm_num = 15 -rsource "Kconfig.sync_rtc_ipm" - -endif # NRF53_SYNC_RTC endif # SOC_SERIES_NRF53X diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.sync_rtc b/soc/arm/nordic_nrf/nrf53/Kconfig.sync_rtc new file mode 100644 index 000000000000000..475db911c672732 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.sync_rtc @@ -0,0 +1,77 @@ +# Copyright (c) 2019 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config NRF53_SYNC_RTC + bool "RTC clock synchronization" + default y if LOG && !LOG_MODE_MINIMAL + depends on NRF_RTC_TIMER + select NRFX_DPPI + select MBOX if !IPM + +if NRF53_SYNC_RTC + +module = SYNC_RTC +module-str = Synchronized RTC +source "subsys/logging/Kconfig.template.log_config" + +config NRF53_SYNC_RTC_INIT_PRIORITY + int "nRF53 Synchronized RTC init priority" + default APPLICATION_INIT_PRIORITY + help + nRF53 Synchronized RTC initialization priority. + +config NRF_RTC_TIMER_USER_CHAN_COUNT + default 2 if NRF_802154_RADIO_DRIVER && SOC_COMPATIBLE_NRF5340_CPUNET + default 3 if NRF_802154_RADIO_DRIVER + default 1 + +config NRF53_SYNC_RTC_LOG_TIMESTAMP + bool "Use Synchronized RTC for logging timestamp" + default y + +config NRF53_SYNC_RTC_IPM_OUT + int "IPM channel from APP to NET" + range 0 15 + default 7 if SOC_COMPATIBLE_NRF5340_CPUAPP + default 8 + +config NRF53_SYNC_RTC_IPM_IN + int "IPM channel from APP to NET" + range 0 15 + default 8 if SOC_COMPATIBLE_NRF5340_CPUAPP + default 7 + +ipm_num = 0 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 1 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 2 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 3 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 4 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 5 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 6 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 7 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 8 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 9 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 10 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 11 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 12 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 13 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 14 +rsource "Kconfig.sync_rtc_ipm" +ipm_num = 15 +rsource "Kconfig.sync_rtc_ipm" + +endif # NRF53_SYNC_RTC diff --git a/soc/arm/nordic_nrf/nrf53/linker.ld b/soc/arm/nordic_nrf/nrf53/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/nordic_nrf/nrf53/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/nordic_nrf/nrf53/soc.c b/soc/arm/nordic_nrf/nrf53/soc.c index 39d64d72cc2ebf8..3542ef3e9149e97 100644 --- a/soc/arm/nordic_nrf/nrf53/soc.c +++ b/soc/arm/nordic_nrf/nrf53/soc.c @@ -554,13 +554,13 @@ static int nordicsemi_nrf53_init(void) #endif #if defined(CONFIG_SOC_DCDC_NRF53X_APP) - nrf_regulators_dcdcen_set(NRF_REGULATORS, true); + nrf_regulators_vreg_enable_set(NRF_REGULATORS, NRF_REGULATORS_VREG_MAIN, true); #endif #if defined(CONFIG_SOC_DCDC_NRF53X_NET) - nrf_regulators_dcdcen_radio_set(NRF_REGULATORS, true); + nrf_regulators_vreg_enable_set(NRF_REGULATORS, NRF_REGULATORS_VREG_RADIO, true); #endif #if defined(CONFIG_SOC_DCDC_NRF53X_HV) - nrf_regulators_dcdcen_vddh_set(NRF_REGULATORS, true); + nrf_regulators_vreg_enable_set(NRF_REGULATORS, NRF_REGULATORS_VREG_HIGH, true); #endif #if defined(CONFIG_SOC_NRF_GPIO_FORWARDER_FOR_NRF5340) diff --git a/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h b/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h index b6cd92ca092aabe..c02c94514197815 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/nrf53/sync_rtc.c b/soc/arm/nordic_nrf/nrf53/sync_rtc.c index 235e9f26001a16e..031f93244f7eec8 100644 --- a/soc/arm/nordic_nrf/nrf53/sync_rtc.c +++ b/soc/arm/nordic_nrf/nrf53/sync_rtc.c @@ -119,7 +119,7 @@ static void free_resources(union rtc_sync_channels channels) int z_nrf_rtc_timer_nrf53net_offset_get(void) { - if (!IS_ENABLED(CONFIG_SOC_NRF5340_CPUNET)) { + if (!IS_ENABLED(CONFIG_SOC_COMPATIBLE_NRF5340_CPUNET)) { return -ENOSYS; } @@ -135,7 +135,7 @@ static void rtc_cb(int32_t id, uint64_t cc_value, void *user_data) channels.raw = (uint32_t)user_data; ppi_rtc_to_ipc(channels, false); - if (IS_ENABLED(CONFIG_SOC_NRF5340_CPUAPP)) { + if (IS_ENABLED(CONFIG_SOC_COMPATIBLE_NRF5340_CPUAPP)) { /* APP: Synchronized completed */ free_resources(channels); } else { @@ -165,7 +165,7 @@ static void remote_callback(void *user_data) /* Clear previous task,event */ ppi_ipc_to_rtc(channels, false); - if (IS_ENABLED(CONFIG_SOC_NRF5340_CPUAPP)) { + if (IS_ENABLED(CONFIG_SOC_COMPATIBLE_NRF5340_CPUAPP)) { /* Setup new connection from RTC to IPC and set RTC to a new * interval that contains captured offset. */ @@ -258,7 +258,7 @@ static int sync_rtc_setup(void) nrfx_gppi_channels_enable(BIT(channels.ch.ppi)); - if (IS_ENABLED(CONFIG_SOC_NRF5340_CPUAPP)) { + if (IS_ENABLED(CONFIG_SOC_COMPATIBLE_NRF5340_CPUAPP)) { ppi_ipc_to_rtc(channels, true); } else { ppi_rtc_to_ipc(channels, true); diff --git a/soc/arm/nordic_nrf/nrf54l/CMakeLists.txt b/soc/arm/nordic_nrf/nrf54l/CMakeLists.txt new file mode 100644 index 000000000000000..914aad289ef7f12 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources( + soc.c + ../validate_rram_partitions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") + +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 000000000000000..d19df604c027624 --- /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 000000000000000..6c0a5bc606d5cc7 --- /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 000000000000000..a9367a0bf363e63 --- /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 000000000000000..c42c8cfc9b378ef --- /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 000000000000000..a7b286fa048de26 --- /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 000000000000000..721e9336989a9ec --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/soc.h @@ -0,0 +1,21 @@ +/* + * 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_ + +#define __ICACHE_PRESENT 1 + +#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 332416ba43b0fe6..7424bb9f7b9bc80 100644 --- a/soc/arm/nordic_nrf/nrf91/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf91/CMakeLists.txt @@ -3,3 +3,5 @@ zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.nrf9151_LACA b/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.nrf9151_LACA new file mode 100644 index 000000000000000..1b3ea88e359baca --- /dev/null +++ b/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.nrf9151_LACA @@ -0,0 +1,14 @@ +# Nordic Semiconductor nRF9151 MCU + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF9151_LACA + +config SOC + default "nRF9151_LACA" + +config NUM_IRQS + default 65 + +endif # SOC_NRF9151_LACA diff --git a/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.series b/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.series index 9612555a4c823f7..6d6cccab9999642 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/nrf91/Kconfig.series b/soc/arm/nordic_nrf/nrf91/Kconfig.series index fd8f5b04d7ad3dc..1be69c377e5e0ba 100644 --- a/soc/arm/nordic_nrf/nrf91/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf91/Kconfig.series @@ -13,9 +13,23 @@ config SOC_SERIES_NRF91X select CPU_HAS_FPU select ARMV8_M_DSP select SOC_FAMILY_NRF - select XIP + imply XIP select HAS_NRFX select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE select HAS_POWEROFF help Enable support for NRF91 MCU series + +if SOC_SERIES_NRF91X +config NRF_SPU_FLASH_REGION_SIZE + hex + default 0x8000 + help + FLASH region size for the NRF_SPU peripheral + +config NRF_SPU_RAM_REGION_SIZE + hex + default 0x2000 + help + RAM region size for the NRF_SPU peripheral +endif diff --git a/soc/arm/nordic_nrf/nrf91/Kconfig.soc b/soc/arm/nordic_nrf/nrf91/Kconfig.soc index c9b8c54438bf80e..0267ada4850e275 100644 --- a/soc/arm/nordic_nrf/nrf91/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf91/Kconfig.soc @@ -34,6 +34,10 @@ config SOC_NRF9131_LACA bool "NRF9131_LACA" select SOC_NRF9120 +config SOC_NRF9151_LACA + bool "NRF9151_LACA" + select SOC_NRF9120 + endchoice config NRF_ENABLE_ICACHE diff --git a/soc/arm/nordic_nrf/nrf91/linker.ld b/soc/arm/nordic_nrf/nrf91/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/nordic_nrf/nrf91/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/nordic_nrf/validate_base_addresses.c b/soc/arm/nordic_nrf/validate_base_addresses.c index 58aaa5a75134bca..9daa820efa9fe51 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,22 @@ 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(uicr, NRF_UICR); CHECK_DT_REG(usbd, NRF_USBD); CHECK_DT_REG(usbreg, NRF_USBREGULATOR); @@ -199,6 +221,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 000000000000000..f35d9cf73f3c147 --- /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 27b260025ccc68e..1e27a6c4608d89e 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 e580758f2742b45..ab1aad770d8a808 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 4f302f5146186f0..ae1d6a61694b768 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 794bb5545bb514f..a4a23e543e6e66e 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_def.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_def.h @@ -228,49 +228,17 @@ struct scfg_reg { volatile uint8_t LV_GPIO_CTL0[5]; }; -/* SCFG internal inline functions for multi-registers */ -static inline uint32_t npcx_devalt_offset(uint32_t alt_no) -{ - return 0x010 + alt_no; -} - -static inline uint32_t npcx_devalt_lk_offset(uint32_t alt_lk_no) -{ - return 0x210 + alt_lk_no; -} - -static inline uint32_t npcx_pupd_en_offset(uint32_t pupd_en_no) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7) || IS_ENABLED(CONFIG_SOC_SERIES_NPCX9)) { - return 0x28 + pupd_en_no; - } else { /* NPCX4 and later series */ - return 0x2b + pupd_en_no; - } -} - -static inline uint32_t npcx_lv_gpio_ctl_offset(uint32_t ctl_no) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7) || IS_ENABLED(CONFIG_SOC_SERIES_NPCX9)) { - if (ctl_no < 5) { - return 0x02a + ctl_no; - } else { - return 0x026 + ctl_no - 5; - } - } else { /* NPCX4 and later series */ - return 0x150 + ctl_no; - } -} - /* Macro functions for SCFG multi-registers */ -#define NPCX_DEV_CTL(base, n) (*(volatile uint8_t *)(base + n)) -#define NPCX_DEVALT(base, n) (*(volatile uint8_t *)(base + \ - npcx_devalt_offset(n))) -#define NPCX_DEVALT_LK(base, n) (*(volatile uint8_t *)(base + \ - npcx_devalt_lk_offset(n))) -#define NPCX_PUPD_EN(base, n) (*(volatile uint8_t *)(base + \ - npcx_pupd_en_offset(n))) -#define NPCX_LV_GPIO_CTL(base, n) (*(volatile uint8_t *)(base + \ - npcx_lv_gpio_ctl_offset(n))) +#define NPCX_DEV_CTL(base, n) \ + (*(volatile uint8_t *)(base + n)) +#define NPCX_DEVALT(base, n) \ + (*(volatile uint8_t *)(base + NPCX_DEVALT_OFFSET(n))) +#define NPCX_DEVALT_LK(base, n) \ + (*(volatile uint8_t *)(base + NPCX_DEVALT_LK_OFFSET(n))) +#define NPCX_PUPD_EN(base, n) \ + (*(volatile uint8_t *)(base + NPCX_PUPD_EN_OFFSET(n))) +#define NPCX_LV_GPIO_CTL(base, n) \ + (*(volatile uint8_t *)(base + NPCX_LV_GPIO_CTL_OFFSET(n))) /* SCFG register fields */ #define NPCX_DEVCNT_F_SPI_TRIS 6 @@ -413,95 +381,21 @@ struct uart_reg { #define NPCX_UFRCTL_RNEMPTY_EN 6 #define NPCX_UFRCTL_ERR_EN 7 -/* - * Multi-Input Wake-Up Unit (MIWU) device registers - */ - -/* MIWU internal inline functions for multi-registers */ -static inline uint32_t npcx_wkedg_offset(uint32_t group) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x000 + (group * 2ul) + (group < 5 ? 0 : 0x1e); - } else { /* NPCX9 and later series */ - return 0x000 + group * 0x10UL; - } -} - -static inline uint32_t npcx_wkaedg_offset(uint32_t group) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x001 + (group * 2ul) + (group < 5 ? 0 : 0x1e); - } else { /* NPCX9 and later series */ - return 0x001 + group * 0x10ul; - } -} - -static inline uint32_t npcx_wkmod_offset(uint32_t group) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x070 + group; - } else { /* NPCX9 and later series */ - return 0x002 + group * 0x10ul; - } -} - -static inline uint32_t npcx_wkpnd_offset(uint32_t group) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x00a + (group * 4ul) + (group < 5 ? 0 : 0x10); - } else { /* NPCX9 and later series */ - return 0x003 + group * 0x10ul; - } -} - -static inline uint32_t npcx_wkpcl_offset(uint32_t group) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x00c + (group * 4ul) + (group < 5 ? 0 : 0x10); - } else { /* NPCX9 and later series */ - return 0x004 + group * 0x10ul; - } -} - -static inline uint32_t npcx_wken_offset(uint32_t group) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x01e + (group * 2ul) + (group < 5 ? 0 : 0x12); - } else { /* NPCX9 and later series */ - return 0x005 + group * 0x10ul; - } -} - -static inline uint32_t npcx_wkst_offset(uint32_t group) -{ - /* NPCX9 and later series only */ - return 0x006 + group * 0x10ul; -} - -static inline uint32_t npcx_wkinen_offset(uint32_t group) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x01f + (group * 2ul) + (group < 5 ? 0 : 0x12); - } else { /* NPCX9 and later series */ - return 0x007 + group * 0x10ul; - } -} - /* Macro functions for MIWU multi-registers */ #define NPCX_WKEDG(base, group) \ - (*(volatile uint8_t *)(base + npcx_wkedg_offset(group))) + (*(volatile uint8_t *)(base + NPCX_WKEDG_OFFSET(group))) #define NPCX_WKAEDG(base, group) \ - (*(volatile uint8_t *)(base + npcx_wkaedg_offset(group))) + (*(volatile uint8_t *)(base + NPCX_WKAEDG_OFFSET(group))) #define NPCX_WKPND(base, group) \ - (*(volatile uint8_t *)(base + npcx_wkpnd_offset(group))) + (*(volatile uint8_t *)(base + NPCX_WKPND_OFFSET(group))) #define NPCX_WKPCL(base, group) \ - (*(volatile uint8_t *)(base + npcx_wkpcl_offset(group))) + (*(volatile uint8_t *)(base + NPCX_WKPCL_OFFSET(group))) #define NPCX_WKEN(base, group) \ - (*(volatile uint8_t *)(base + npcx_wken_offset(group))) + (*(volatile uint8_t *)(base + NPCX_WKEN_OFFSET(group))) #define NPCX_WKINEN(base, group) \ - (*(volatile uint8_t *)(base + npcx_wkinen_offset(group))) + (*(volatile uint8_t *)(base + NPCX_WKINEN_OFFSET(group))) #define NPCX_WKMOD(base, group) \ - (*(volatile uint8_t *)(base + npcx_wkmod_offset(group))) + (*(volatile uint8_t *)(base + NPCX_WKMOD_OFFSET(group))) /* * General-Purpose I/O (GPIO) device registers @@ -582,33 +476,10 @@ struct adc_reg { }; /* ADC internal inline functions for multi-registers */ -static inline uint32_t npcx_chndat_offset(uint32_t ch) -{ - return 0x40 + ch * 2; -} - -static inline uint32_t npcx_thr_base(void) -{ - if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) { - return 0x014; - } else if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX9)) { - return 0x060; - } else { /* NPCX4 and later series */ - return 0x080; - } -} - -static inline uint32_t npcx_thrctl_offset(uint32_t ctrl) -{ - return npcx_thr_base() + ctrl * 2; -} - -#define CHNDAT(base, ch) (*(volatile uint16_t *)((base) + npcx_chndat_offset(ch))) +#define CHNDAT(base, ch) \ + (*(volatile uint16_t *)((base) + NPCX_CHNDAT_OFFSET(ch))) #define THRCTL(base, ctrl) \ - (*(volatile uint16_t *)(base + npcx_thrctl_offset(ctrl))) -#ifdef CONFIG_SOC_SERIES_NPCX4 -#define THEN(base) (*(volatile uint16_t *)(base + 0x90)) -#endif + (*(volatile uint16_t *)(base + NPCX_THRCTL_OFFSET(ctrl))) /* ADC register fields */ #define NPCX_ATCTL_SCLKDIV_FIELD FIELD(0, 6) @@ -628,16 +499,6 @@ static inline uint32_t npcx_thrctl_offset(uint32_t ctrl) #define NPCX_ADCCNF_STOP 11 #define NPCX_CHNDAT_CHDAT_FIELD FIELD(0, 10) #define NPCX_CHNDAT_NEW 15 -#ifdef CONFIG_SOC_SERIES_NPCX4 -#define NPCX_THRCTL_L_H 15 -#define NPCX_THRCTL_CHNSEL FIELD(10, 5) -#define NPCX_THRCTL_THRVAL FIELD(0, 10) -#else -#define NPCX_THRCTL_THEN 15 -#define NPCX_THRCTL_L_H 14 -#define NPCX_THRCTL_CHNSEL FIELD(10, 4) -#define NPCX_THRCTL_THRVAL FIELD(0, 10) -#endif #define NPCX_THRCTS_ADC_WKEN 15 #define NPCX_THRCTS_THR3_IEN 10 #define NPCX_THRCTS_THR2_IEN 9 @@ -764,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 */ @@ -787,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 @@ -796,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 @@ -814,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 @@ -825,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 @@ -839,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 @@ -855,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 @@ -864,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 */ @@ -1598,11 +1505,6 @@ struct fiu_reg { #define NPCX_SPI1_DEV_FOUR_BADDR_CS10 6 #define NPCX_SPI1_DEV_FOUR_BADDR_CS11 7 #define NPCX_SPI1_DEV_SPI1_LO_DEV_SIZE FIELD(0, 4) -#if defined(CONFIG_SOC_SERIES_NPCX9) -#define NPCX_FIU_EXT_CFG_SPI1_2DEV 7 -#else -#define NPCX_FIU_EXT_CFG_SPI1_2DEV 6 -#endif #define NPCX_FIU_EXT_CFG_SET_DMM_EN 2 #define NPCX_FIU_EXT_CFG_SET_CMD_EN 1 #define NPCX_SPI_DEV_NADDRB FIELD(5, 3) @@ -1763,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 */ @@ -1814,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 0405bee3567e314..8c4ed132b46cb7c 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_clock.h b/soc/arm/nuvoton_npcx/common/soc_clock.h index cda024dc0dfdc0a..d43a70d4529df6a 100644 --- a/soc/arm/nuvoton_npcx/common/soc_clock.h +++ b/soc/arm/nuvoton_npcx/common/soc_clock.h @@ -44,11 +44,11 @@ struct npcx_clk_cfg { #define APB3DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb3_prescaler) - 1) /* APB4 clock divider if supported */ #if DT_NODE_HAS_PROP(DT_NODELABEL(pcc), apb4_prescaler) -#if !defined(CONFIG_SOC_SERIES_NPCX7) /* Supported in NPCX9 and later series */ +#if defined(CONFIG_CLOCK_CONTROL_NPCX_SUPP_APB4) /* Supported in NPCX9 and later series */ #define APB4DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb4_prescaler) - 1) #else #error "APB4 clock divider is not supported but defined in pcc node!" -#endif /* !CONFIG_SOC_SERIES_NPCX7 */ +#endif /* CONFIG_CLOCK_CONTROL_NPCX_SUPP_APB4 */ #endif /* Construct a uint8_t array from 'pwdwn-ctl-val' prop for PWDWN_CTL initialization. */ @@ -68,12 +68,6 @@ struct npcx_clk_cfg { * - CORE_CLK > MAX_OFMCLK/2, AHB6DIV should be 1, else 0. * - CORE_CLK > MAX_OFMCLK/2, FIUDIV should be 1, else 0. */ -#if defined(CONFIG_SOC_SERIES_NPCX4) -#define MAX_OFMCLK 120000000 -#else -#define MAX_OFMCLK 100000000 -#endif /* CONFIG_SOC_SERIES_NPCX4 */ - /* Core domain clock */ #define CORE_CLK (OFMCLK / DT_PROP(DT_NODELABEL(pcc), core_prescaler)) /* Low Frequency clock */ @@ -103,13 +97,13 @@ struct npcx_clk_cfg { #define FIUDIV_VAL 0 /* FIU_CLK = CORE_CLK */ #endif -#if defined(CONFIG_SOC_SERIES_NPCX4) +#if defined(CONFIG_CLOCK_CONTROL_NPCX_SUPP_FIU1) #if (CORE_CLK > (MAX_OFMCLK / 2)) #define FIU1DIV_VAL 1 /* FIU1_CLK = CORE_CLK/2 */ #else #define FIU1DIV_VAL 0 /* FIU1_CLK = CORE_CLK */ #endif -#endif /* CONFIG_SOC_SERIES_NPCX4 */ +#endif /* CONFIG_CLOCK_CONTROL_NPCX_SUPP_FIU1 */ /* Get APB clock freq */ #define NPCX_APB_CLOCK(no) (APBSRC_CLK / (APB##no##DIV_VAL + 1)) 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 000000000000000..a8755e080f7594d --- /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/CMakeLists.txt b/soc/arm/nuvoton_npcx/npcx4/CMakeLists.txt index ee55c1c2a5ba6b3..158ae5cbbc7c99c 100644 --- a/soc/arm/nuvoton_npcx/npcx4/CMakeLists.txt +++ b/soc/arm/nuvoton_npcx/npcx4/CMakeLists.txt @@ -5,3 +5,5 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series b/soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series index 018a38cc14b6e3b..1b692cf76211a46 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/Kconfig.series b/soc/arm/nuvoton_npcx/npcx4/Kconfig.series index 2eb4ac5d184e546..1585ace4e981bc7 100644 --- a/soc/arm/nuvoton_npcx/npcx4/Kconfig.series +++ b/soc/arm/nuvoton_npcx/npcx4/Kconfig.series @@ -11,5 +11,6 @@ config SOC_SERIES_NPCX4 select CPU_HAS_FPU select CPU_HAS_ARM_MPU select SOC_FAMILY_NPCX + select HAS_PM help Enable support for Nuvoton NPCX4 series diff --git a/soc/arm/nuvoton_npcx/npcx4/linker.ld b/soc/arm/nuvoton_npcx/npcx4/linker.ld deleted file mode 100644 index 36859865d024dd6..000000000000000 --- a/soc/arm/nuvoton_npcx/npcx4/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2023 Nuvoton Technology Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/nuvoton_npcx/npcx4/soc.h b/soc/arm/nuvoton_npcx/npcx4/soc.h index e61c1e108f020f8..4ada738102c43c2 100644 --- a/soc/arm/nuvoton_npcx/npcx4/soc.h +++ b/soc/arm/nuvoton_npcx/npcx4/soc.h @@ -7,15 +7,53 @@ #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) +#define NPCX_PUPD_EN_OFFSET(n) (0x02b + n) +#define NPCX_LV_GPIO_CTL_OFFSET(n) (0x150 + n) +#define NPCX_DEVALT_LK_OFFSET(n) (0x210 + n) + +/* NPCX4 MIWU multi-registers */ +#define NPCX_WKEDG_OFFSET(n) (0x000 + (n * 0x010)) +#define NPCX_WKAEDG_OFFSET(n) (0x001 + (n * 0x010)) +#define NPCX_WKMOD_OFFSET(n) (0x002 + (n * 0x010)) +#define NPCX_WKPND_OFFSET(n) (0x003 + (n * 0x010)) +#define NPCX_WKPCL_OFFSET(n) (0x004 + (n * 0x010)) +#define NPCX_WKEN_OFFSET(n) (0x005 + (n * 0x010)) +#define NPCX_WKST_OFFSET(n) (0x006 + (n * 0x010)) +#define NPCX_WKINEN_OFFSET(n) (0x007 + (n * 0x010)) + +/* NPCX4 ADC multi-registers */ +#define NPCX_CHNDAT_OFFSET(n) (0x040 + n * 2) +#define NPCX_THRCTL_OFFSET(n) (0x080 + n * 2) +#define NPCX_THEN_OFFSET 0x090 +#define THEN(base) (*(volatile uint16_t *)(base + NPCX_THEN_OFFSET)) + +/* NPCX4 ADC register fields */ +#define NPCX_THRCTL_L_H 15 +#define NPCX_THRCTL_CHNSEL FIELD(10, 5) +#define NPCX_THRCTL_THRVAL FIELD(0, 10) + +/* NPCX4 FIU register fields */ +#define NPCX_FIU_EXT_CFG_SPI1_2DEV 6 + +/* NPCX4 supported group mask of DEVALT_LK */ +#define NPCX_DEVALT_LK_GROUP_MASK \ + (BIT(0) | BIT(2) | BIT(3) | BIT(4) | \ + BIT(5) | BIT(6) | BIT(11) | BIT(13) | \ + BIT(15) | BIT(16) | BIT(17) | BIT(18) | \ + BIT(19) | BIT(21)) /* DEVALT0_LK - DEVALTN_LK */ + +/* NPCX4 Clock Configuration */ +#define MAX_OFMCLK 120000000 #include #include #include #include +#include #include #include diff --git a/soc/arm/nuvoton_npcx/npcx7/CMakeLists.txt b/soc/arm/nuvoton_npcx/npcx7/CMakeLists.txt index c4b945e8ad1ef5a..01792bf9fce87d0 100644 --- a/soc/arm/nuvoton_npcx/npcx7/CMakeLists.txt +++ b/soc/arm/nuvoton_npcx/npcx7/CMakeLists.txt @@ -10,3 +10,5 @@ zephyr_sources_ifdef( CONFIG_ARM_MPU mpu_regions.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series b/soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series index 4af311aebcbd6cc..9b12678dc8e44d5 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/linker.ld b/soc/arm/nuvoton_npcx/npcx7/linker.ld deleted file mode 100644 index c27b59604dc0475..000000000000000 --- a/soc/arm/nuvoton_npcx/npcx7/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2020 Nuvoton Technology Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/nuvoton_npcx/npcx7/soc.h b/soc/arm/nuvoton_npcx/npcx7/soc.h index 9c293e05753c5cc..9b523ce1b8fc6d2 100644 --- a/soc/arm/nuvoton_npcx/npcx7/soc.h +++ b/soc/arm/nuvoton_npcx/npcx7/soc.h @@ -7,10 +7,40 @@ #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) +#define NPCX_PUPD_EN_OFFSET(n) (0x028 + n) +#define NPCX_LV_GPIO_CTL_OFFSET(n) ((n < 5) ? (0x02a + n) : (0x021 + n)) +#define NPCX_DEVALT_LK_OFFSET(n) (0x210 + n) + +/* NPCX7 MIWU multi-registers offset */ +#define NPCX_WKEDG_OFFSET(n) (0x000 + (n * 2) + ((n < 5) ? 0 : 0x01e)) +#define NPCX_WKAEDG_OFFSET(n) (0x001 + (n * 2) + ((n < 5) ? 0 : 0x01e)) +#define NPCX_WKMOD_OFFSET(n) (0x070 + n) +#define NPCX_WKPND_OFFSET(n) (0x00a + (n * 4) + ((n < 5) ? 0 : 0x010)) +#define NPCX_WKPCL_OFFSET(n) (0x00c + (n * 4) + ((n < 5) ? 0 : 0x010)) +#define NPCX_WKEN_OFFSET(n) (0x01e + (n * 2) + ((n < 5) ? 0 : 0x012)) +#define NPCX_WKINEN_OFFSET(n) (0x01f + (n * 2) + ((n < 5) ? 0 : 0x012)) + +/* NPCX7 ADC multi-registers offset */ +#define NPCX_CHNDAT_OFFSET(n) (0x040 + (n * 2)) +#define NPCX_THRCTL_OFFSET(n) (0x014 + (n * 2)) + +/* NPCX7 ADC register fields */ +#define NPCX_THRCTL_THEN 15 +#define NPCX_THRCTL_L_H 14 +#define NPCX_THRCTL_CHNSEL FIELD(10, 4) +#define NPCX_THRCTL_THRVAL FIELD(0, 10) + +/* NPCX7 supported group mask of DEVALT_LK */ +#define NPCX_DEVALT_LK_GROUP_MASK \ + (BIT(0) | BIT(2) | BIT(3) | BIT(4) | \ + BIT(6) | BIT(11) | BIT(15)) /* DEVALT0_LK - DEVALTF_LK */ + +/* NPCX7 Clock configuration */ +#define MAX_OFMCLK 100000000 #include #include diff --git a/soc/arm/nuvoton_npcx/npcx9/CMakeLists.txt b/soc/arm/nuvoton_npcx/npcx9/CMakeLists.txt index 5b2aad82a5a0736..56f793d0580f1e3 100644 --- a/soc/arm/nuvoton_npcx/npcx9/CMakeLists.txt +++ b/soc/arm/nuvoton_npcx/npcx9/CMakeLists.txt @@ -1,3 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_include_directories(${ZEPHYR_BASE}/drivers) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") 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 000000000000000..170c3deceaa0c62 --- /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 b5ffb594eed0c7b..6487b70cf59cf63 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 e198c44698af340..dbebc40d52d696f 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/linker.ld b/soc/arm/nuvoton_npcx/npcx9/linker.ld deleted file mode 100644 index a07329b636027b6..000000000000000 --- a/soc/arm/nuvoton_npcx/npcx9/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2021 Nuvoton Technology Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/nuvoton_npcx/npcx9/soc.h b/soc/arm/nuvoton_npcx/npcx9/soc.h index a1769e11a00659d..2ce745650fb0393 100644 --- a/soc/arm/nuvoton_npcx/npcx9/soc.h +++ b/soc/arm/nuvoton_npcx/npcx9/soc.h @@ -7,10 +7,45 @@ #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) +#define NPCX_PUPD_EN_OFFSET(n) (0x028 + n) +#define NPCX_LV_GPIO_CTL_OFFSET(n) ((n < 5) ? (0x02a + n) : (0x021 + n)) +#define NPCX_DEVALT_LK_OFFSET(n) (0x210 + n) + +/* NPCX9 MIWU multi-registers */ +#define NPCX_WKEDG_OFFSET(n) (0x000 + (n * 0x010)) +#define NPCX_WKAEDG_OFFSET(n) (0x001 + (n * 0x010)) +#define NPCX_WKMOD_OFFSET(n) (0x002 + (n * 0x010)) +#define NPCX_WKPND_OFFSET(n) (0x003 + (n * 0x010)) +#define NPCX_WKPCL_OFFSET(n) (0x004 + (n * 0x010)) +#define NPCX_WKEN_OFFSET(n) (0x005 + (n * 0x010)) +#define NPCX_WKST_OFFSET(n) (0x006 + (n * 0x010)) +#define NPCX_WKINEN_OFFSET(n) (0x007 + (n * 0x010)) + +/* NPCX9 ADC multi-registers */ +#define NPCX_CHNDAT_OFFSET(n) (0x040 + (n * 2)) +#define NPCX_THRCTL_OFFSET(n) (0x060 + (n * 2)) + +/* NPCX9 ADC register fields */ +#define NPCX_THRCTL_THEN 15 +#define NPCX_THRCTL_L_H 14 +#define NPCX_THRCTL_CHNSEL FIELD(10, 4) +#define NPCX_THRCTL_THRVAL FIELD(0, 10) + +/* NPCX9 FIU register fields */ +#define NPCX_FIU_EXT_CFG_SPI1_2DEV 7 + +/* NPCX9 supported group mask of DEVALT_LK */ +#define NPCX_DEVALT_LK_GROUP_MASK \ + (BIT(0) | BIT(2) | BIT(3) | BIT(4) | \ + BIT(5) | BIT(6) | BIT(11) | BIT(13) | \ + BIT(15) | BIT(16) | BIT(17) | BIT(18)) /* DEVALT0_LK - DEVALTJ_LK */ + +/* NPCX9 Clock configuration and limitation */ +#define MAX_OFMCLK 100000000 #include #include diff --git a/soc/arm/nuvoton_numaker/m46x/CMakeLists.txt b/soc/arm/nuvoton_numaker/m46x/CMakeLists.txt index 6b2126d22bdc357..2fa91b640cfe023 100644 --- a/soc/arm/nuvoton_numaker/m46x/CMakeLists.txt +++ b/soc/arm/nuvoton_numaker/m46x/CMakeLists.txt @@ -3,3 +3,5 @@ # 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 "") diff --git a/soc/arm/nuvoton_numaker/m46x/linker.ld b/soc/arm/nuvoton_numaker/m46x/linker.ld deleted file mode 100644 index 37c968fda6357d7..000000000000000 --- a/soc/arm/nuvoton_numaker/m46x/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2023 Nuvoton Technology Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/nuvoton_numicro/m48x/CMakeLists.txt b/soc/arm/nuvoton_numicro/m48x/CMakeLists.txt index 5d14a880fef38b4..322465a92cedb28 100644 --- a/soc/arm/nuvoton_numicro/m48x/CMakeLists.txt +++ b/soc/arm/nuvoton_numicro/m48x/CMakeLists.txt @@ -4,3 +4,5 @@ # Author: Saravanan Sekar zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nuvoton_numicro/m48x/linker.ld b/soc/arm/nuvoton_numicro/m48x/linker.ld deleted file mode 100644 index 737722a16114302..000000000000000 --- a/soc/arm/nuvoton_numicro/m48x/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * Copyright (c) 2020 Linumiz - */ - -#include diff --git a/soc/arm/nxp_imx/mcimx6x_m4/CMakeLists.txt b/soc/arm/nxp_imx/mcimx6x_m4/CMakeLists.txt index a720300fca17928..ee28789fe7daae2 100644 --- a/soc/arm/nxp_imx/mcimx6x_m4/CMakeLists.txt +++ b/soc/arm/nxp_imx/mcimx6x_m4/CMakeLists.txt @@ -8,3 +8,5 @@ zephyr_sources( soc.c soc_clk_freq.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_imx/mcimx6x_m4/Kconfig.series b/soc/arm/nxp_imx/mcimx6x_m4/Kconfig.series index ac0428eff53a934..7279ac8596ec742 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/mcimx6x_m4/linker.ld b/soc/arm/nxp_imx/mcimx6x_m4/linker.ld deleted file mode 100644 index 3cf863608e1d3da..000000000000000 --- a/soc/arm/nxp_imx/mcimx6x_m4/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/nxp_imx/mcimx7_m4/CMakeLists.txt b/soc/arm/nxp_imx/mcimx7_m4/CMakeLists.txt index f6aa4ef3332d554..e5c7ae22fd6a0cb 100644 --- a/soc/arm/nxp_imx/mcimx7_m4/CMakeLists.txt +++ b/soc/arm/nxp_imx/mcimx7_m4/CMakeLists.txt @@ -8,3 +8,5 @@ zephyr_sources( soc.c soc_clk_freq.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_imx/mcimx7_m4/Kconfig.series b/soc/arm/nxp_imx/mcimx7_m4/Kconfig.series index be0065cb3730373..e7ae54bcbdadd33 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/mcimx7_m4/linker.ld b/soc/arm/nxp_imx/mcimx7_m4/linker.ld deleted file mode 100644 index 3cf863608e1d3da..000000000000000 --- a/soc/arm/nxp_imx/mcimx7_m4/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/nxp_imx/mimx8ml8_m7/CMakeLists.txt b/soc/arm/nxp_imx/mimx8ml8_m7/CMakeLists.txt index a992a8509b46970..3dce744104fcbb3 100644 --- a/soc/arm/nxp_imx/mimx8ml8_m7/CMakeLists.txt +++ b/soc/arm/nxp_imx/mimx8ml8_m7/CMakeLists.txt @@ -15,3 +15,5 @@ if(CONFIG_OPENAMP_RSC_TABLE) zephyr_linker_section(NAME .resource_table GROUP ROM_REGION NOINPUT) zephyr_linker_section_configure(SECTION .resource_table KEEP INPUT ".resource_table*") endif() + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.defconfig.mimx8ml8_m7 b/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.defconfig.mimx8ml8_m7 index df80e83fdf21ed6..8b92477601c7211 100644 --- a/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.defconfig.mimx8ml8_m7 +++ b/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.defconfig.mimx8ml8_m7 @@ -16,7 +16,7 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config GPIO default y -config IPM_IMX_REV2 +config IPM_IMX default y depends on IPM diff --git a/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.series b/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.series index fc55afd4aae1961..f1eb1fd40fdef4c 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/CMakeLists.txt b/soc/arm/nxp_imx/mimx8mm6_m4/CMakeLists.txt index 468b44a4588cca6..ef0ba73b1594b48 100644 --- a/soc/arm/nxp_imx/mimx8mm6_m4/CMakeLists.txt +++ b/soc/arm/nxp_imx/mimx8mm6_m4/CMakeLists.txt @@ -12,3 +12,5 @@ if(CONFIG_OPENAMP_RSC_TABLE) zephyr_linker_section(NAME .resource_table GROUP ROM_REGION NOINPUT) zephyr_linker_section_configure(SECTION .resource_table KEEP INPUT ".resource_table*") endif() + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.defconfig.mimx8mm6_m4 b/soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.defconfig.mimx8mm6_m4 index 1f2fe1b6c0a3bd7..70e75a6bfce481e 100644 --- a/soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.defconfig.mimx8mm6_m4 +++ b/soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.defconfig.mimx8mm6_m4 @@ -13,7 +13,7 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC int default 400000000 -config IPM_IMX_REV2 +config IPM_IMX default y depends on IPM diff --git a/soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.series b/soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.series index dddb12d1b70a802..f860a7fbd26290f 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/CMakeLists.txt b/soc/arm/nxp_imx/mimx8mq6_m4/CMakeLists.txt index af5db79548ab637..9555fd57a89a7f7 100644 --- a/soc/arm/nxp_imx/mimx8mq6_m4/CMakeLists.txt +++ b/soc/arm/nxp_imx/mimx8mq6_m4/CMakeLists.txt @@ -7,3 +7,5 @@ zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_imx/mimx8mq6_m4/Kconfig.series b/soc/arm/nxp_imx/mimx8mq6_m4/Kconfig.series index c4b16d3fb5cd66f..3933037c3a034c2 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/mimx8mq6_m4/linker.ld b/soc/arm/nxp_imx/mimx8mq6_m4/linker.ld deleted file mode 100644 index 895341fda8d4385..000000000000000 --- a/soc/arm/nxp_imx/mimx8mq6_m4/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2021, Kwon Tae-young - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/nxp_imx/rt/CMakeLists.txt b/soc/arm/nxp_imx/rt/CMakeLists.txt index 5bfc8d336fcc1fb..92ab665a0efbf21 100644 --- a/soc/arm/nxp_imx/rt/CMakeLists.txt +++ b/soc/arm/nxp_imx/rt/CMakeLists.txt @@ -50,6 +50,9 @@ zephyr_compile_definitions_ifdef(CONFIG_ENTROPY_MCUX_CAAM CACHE_MODE_WRITE_THROU zephyr_compile_definitions_ifdef(CONFIG_USB_DEVICE_DRIVER DATA_SECTION_IS_CACHEABLE=1) +# flexram header +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers/memc) + zephyr_linker_section_configure( SECTION .rom_start INPUT ".boot_hdr.ivt" @@ -59,3 +62,5 @@ zephyr_linker_section_configure( KEEP PRIO 11 ) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_imx/rt/Kconfig.defconfig.series b/soc/arm/nxp_imx/rt/Kconfig.defconfig.series index 7a1aac41ce32517..61f537a402d2ee3 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 @@ -92,6 +99,9 @@ config FLASH_SIZE default $(dt_node_int_prop_int,$(DT_CHOSEN_FLASH_NODE),size,Kb) \ if $(DT_FLASH_HAS_SIZE_PROP) +config MEMC + default y + choice USB_MCUX_CONTROLLER_TYPE default USB_DC_NXP_EHCI endchoice @@ -126,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 253e316548e9425..cbc00915046a32a 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.soc +++ b/soc/arm/nxp_imx/rt/Kconfig.soc @@ -1,6 +1,6 @@ # i.MX RT series -# Copyright (c) 2017-2021, NXP +# Copyright 2017-2021,2023 NXP # SPDX-License-Identifier: Apache-2.0 choice @@ -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,8 +342,9 @@ 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 ADJUST_DCDC select BYPASS_LDO_LPSR select ADJUST_LDO select HAS_MCUX_PWM @@ -369,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 @@ -403,12 +409,13 @@ 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 select HAS_MCUX_EDMA select CPU_HAS_FPU_DOUBLE_PRECISION - select ADJUST_DCDC select BYPASS_LDO_LPSR select ADJUST_LDO select HAS_MCUX_PWM @@ -437,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 @@ -661,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 @@ -686,6 +696,7 @@ config DCDC_VALUE config ADJUST_DCDC bool "Adjust internal DCDC output" + default y if SOC_SERIES_IMX_RT11XX config BYPASS_LDO_LPSR bool "Bypass LDO lpsr" @@ -823,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/soc_rt10xx.c b/soc/arm/nxp_imx/rt/soc_rt10xx.c index ba22a633a506eab..dd6e534be232cda 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 @@ -21,6 +22,8 @@ #include "usb.h" #endif +#include "memc_nxp_flexram.h" + #include #define CCM_NODE DT_INST(0, nxp_imx_ccm) @@ -53,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 @@ -316,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(); @@ -345,6 +333,11 @@ void z_arm_platform_init(void) { /* Call CMSIS SystemInit */ SystemInit(); + +#if defined(FLEXRAM_RUNTIME_BANKS_USED) + /* Configure flexram if not running from RAM */ + memc_flexram_dt_partition(); +#endif } #endif diff --git a/soc/arm/nxp_imx/rt/soc_rt11xx.c b/soc/arm/nxp_imx/rt/soc_rt11xx.c index 7340fd0f3ff12ab..3adedde8d38c51f 100644 --- a/soc/arm/nxp_imx/rt/soc_rt11xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt11xx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, NXP + * Copyright 2021-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -33,17 +34,18 @@ #include "usb_phy.h" #include "usb.h" #endif +#include "memc_nxp_flexram.h" #include #define DUAL_CORE_MU_ENABLED \ - (CONFIG_SECOND_CORE_MCUX && CONFIG_IPM && CONFIG_IPM_IMX_REV2) + (CONFIG_SECOND_CORE_MCUX && CONFIG_IPM && CONFIG_IPM_IMX) #if DUAL_CORE_MU_ENABLED /* Dual core mode is enabled, and messaging unit is present */ #include #define BOOT_FLAG 0x1U -#define MU_BASE (MU_Type *)DT_REG_ADDR(DT_INST(0, nxp_imx_mu_rev2)) +#define MU_BASE (MU_Type *)DT_REG_ADDR(DT_INST(0, nxp_imx_mu)) #endif #if CONFIG_USB_DC_NXP_EHCI /* USB PHY configuration */ @@ -276,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); @@ -323,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; @@ -395,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 - @@ -413,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 */ @@ -660,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 */ @@ -689,6 +688,11 @@ static int imxrt_init(void) void z_arm_platform_init(void) { SystemInit(); + +#if defined(FLEXRAM_RUNTIME_BANKS_USED) + /* Configure flexram if not running from RAM */ + memc_flexram_dt_partition(); +#endif } #endif diff --git a/soc/arm/nxp_imx/rt5xx/CMakeLists.txt b/soc/arm/nxp_imx/rt5xx/CMakeLists.txt index f3c6404d18523e9..e12f2e9ae180900 100644 --- a/soc/arm/nxp_imx/rt5xx/CMakeLists.txt +++ b/soc/arm/nxp_imx/rt5xx/CMakeLists.txt @@ -29,3 +29,5 @@ zephyr_linker_sources_ifdef(CONFIG_USB_DEVICE_DRIVER SECTIONS usb.ld) zephyr_code_relocate(FILES flash_clock_setup.c LOCATION RAM) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_imx/rt5xx/Kconfig.defconfig.series b/soc/arm/nxp_imx/rt5xx/Kconfig.defconfig.series index 31b6a2c70db3993..b277f621d0a2c4b 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 2c82c533de99813..35b86c2e90358e3 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 69b60936fb42e2b..3599dcfa646cb58 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 c216f63890d25b9..ca2a89cd5532470 100644 --- a/soc/arm/nxp_imx/rt5xx/soc.c +++ b/soc/arm/nxp_imx/rt5xx/soc.c @@ -216,7 +216,8 @@ void z_arm_platform_init(void) SystemInit(); } -static void clock_init(void) +/* Weak so that board can override with their own clock init routine. */ +void __weak rt5xx_clock_init(void) { /* Configure LPOSC 1M */ /* Power on LPOSC (1MHz) */ @@ -280,8 +281,12 @@ static void 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(); @@ -418,6 +423,23 @@ static void clock_init(void) CLOCK_SetClkDiv(kCLOCK_DivAdcClk, 1); #endif +#if CONFIG_COUNTER_NXP_MRT + 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; @@ -426,7 +448,8 @@ static void clock_init(void) } #if CONFIG_MIPI_DSI -void imxrt_pre_init_display_interface(void) +/* Weak so board can override this function */ +void __weak imxrt_pre_init_display_interface(void) { /* Assert MIPI DPHY reset. */ RESET_SetPeripheralReset(kMIPI_DSI_PHY_RST_SHIFT_RSTn); @@ -452,21 +475,41 @@ void 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); } -void imxrt_post_init_display_interface(void) +void __weak imxrt_post_init_display_interface(void) { /* Deassert MIPI DPHY reset. */ RESET_ClearPeripheralReset(kMIPI_DSI_PHY_RST_SHIFT_RSTn); } + +void __weak imxrt_deinit_display_interface(void) +{ + /* Assert MIPI DPHY and DSI reset */ + RESET_SetPeripheralReset(kMIPI_DSI_PHY_RST_SHIFT_RSTn); + RESET_SetPeripheralReset(kMIPI_DSI_CTRL_RST_SHIFT_RSTn); + /* Remove clock from DPHY */ + CLOCK_AttachClk(kNONE_to_MIPI_DPHY_CLK); +} + + #endif /** @@ -481,12 +524,20 @@ void imxrt_post_init_display_interface(void) static int nxp_rt500_init(void) { /* Initialize clocks with tool generated code */ - clock_init(); + rt5xx_clock_init(); #ifndef CONFIG_IMXRT5XX_CODE_CACHE 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/rt5xx/soc.h b/soc/arm/nxp_imx/rt5xx/soc.h index c2ebff0369d8ce6..eefef70ff8203d9 100644 --- a/soc/arm/nxp_imx/rt5xx/soc.h +++ b/soc/arm/nxp_imx/rt5xx/soc.h @@ -80,6 +80,8 @@ void imxrt_pre_init_display_interface(void); void imxrt_post_init_display_interface(void); + +void imxrt_deinit_display_interface(void); #endif #endif diff --git a/soc/arm/nxp_imx/rt6xx/CMakeLists.txt b/soc/arm/nxp_imx/rt6xx/CMakeLists.txt index a5a853cd853f1af..57d5cb3fd04671d 100644 --- a/soc/arm/nxp_imx/rt6xx/CMakeLists.txt +++ b/soc/arm/nxp_imx/rt6xx/CMakeLists.txt @@ -32,3 +32,5 @@ zephyr_linker_sources_ifdef(CONFIG_USB_DEVICE_DRIVER if(CONFIG_FLASH_MCUX_FLEXSPI_XIP) zephyr_code_relocate(FILES flash_clock_setup.c LOCATION RAM) endif() + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_imx/rt6xx/linker.ld b/soc/arm/nxp_imx/rt6xx/linker.ld deleted file mode 100644 index cf5cc4c9968c7d7..000000000000000 --- a/soc/arm/nxp_imx/rt6xx/linker.ld +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2020, NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images and XIP images. - */ - - -#include diff --git a/soc/arm/nxp_imx/rt6xx/soc.c b/soc/arm/nxp_imx/rt6xx/soc.c index e04499b289d84ce..165cf92e234b1c3 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 @@ -321,6 +321,10 @@ static ALWAYS_INLINE void clock_init(void) flexspi_setup_clock(FLEXSPI, 1U, 9U); #endif +#if CONFIG_COUNTER_NXP_MRT + RESET_PeripheralReset(kMRT0_RST_SHIFT_RSTn); +#endif + /* Set SystemCoreClock variable. */ SystemCoreClock = CLOCK_INIT_CORE_CLOCK; diff --git a/soc/arm/nxp_kinetis/k2x/CMakeLists.txt b/soc/arm/nxp_kinetis/k2x/CMakeLists.txt index f61746c261077e8..8ff38d089cea992 100644 --- a/soc/arm/nxp_kinetis/k2x/CMakeLists.txt +++ b/soc/arm/nxp_kinetis/k2x/CMakeLists.txt @@ -8,3 +8,10 @@ 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 3e2e2f50ef7706e..01f0ec78f2ffec1 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 000000000000000..963fdf87162ad5a --- /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 4cec66459643ff1..254fd251014933e 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 5653d6cd75a6314..0535ac2e684123f 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/linker.ld b/soc/arm/nxp_kinetis/k2x/linker.ld deleted file mode 100644 index 7a1df7beaa5248c..000000000000000 --- a/soc/arm/nxp_kinetis/k2x/linker.ld +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images and XIP images. - */ - -#include 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 000000000000000..30a5cff42ead77d --- /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 67ea1183401de35..d5108fb49d9057e 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 cb88009a49d55f0..88a93b62ef674a6 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/CMakeLists.txt b/soc/arm/nxp_kinetis/k6x/CMakeLists.txt index d26821f690b550b..8cf7a11f62e15ab 100644 --- a/soc/arm/nxp_kinetis/k6x/CMakeLists.txt +++ b/soc/arm/nxp_kinetis/k6x/CMakeLists.txt @@ -7,3 +7,5 @@ zephyr_sources_ifdef( CONFIG_ARM_MPU nxp_mpu_regions.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_kinetis/k6x/linker.ld b/soc/arm/nxp_kinetis/k6x/linker.ld deleted file mode 100644 index 7a1df7beaa5248c..000000000000000 --- a/soc/arm/nxp_kinetis/k6x/linker.ld +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images and XIP images. - */ - -#include diff --git a/soc/arm/nxp_kinetis/k6x/soc.c b/soc/arm/nxp_kinetis/k6x/soc.c index 083f695db32c70e..2463b5ddc28271d 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/k8x/CMakeLists.txt b/soc/arm/nxp_kinetis/k8x/CMakeLists.txt index d26821f690b550b..8cf7a11f62e15ab 100644 --- a/soc/arm/nxp_kinetis/k8x/CMakeLists.txt +++ b/soc/arm/nxp_kinetis/k8x/CMakeLists.txt @@ -7,3 +7,5 @@ zephyr_sources_ifdef( CONFIG_ARM_MPU nxp_mpu_regions.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_kinetis/k8x/linker.ld b/soc/arm/nxp_kinetis/k8x/linker.ld deleted file mode 100644 index 7a1df7beaa5248c..000000000000000 --- a/soc/arm/nxp_kinetis/k8x/linker.ld +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images and XIP images. - */ - -#include diff --git a/soc/arm/nxp_kinetis/ke1xf/CMakeLists.txt b/soc/arm/nxp_kinetis/ke1xf/CMakeLists.txt index 0b26284343c4f77..ccbf2208d5a0fab 100644 --- a/soc/arm/nxp_kinetis/ke1xf/CMakeLists.txt +++ b/soc/arm/nxp_kinetis/ke1xf/CMakeLists.txt @@ -11,3 +11,5 @@ zephyr_sources_ifdef( CONFIG_PM power.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_kinetis/ke1xf/linker.ld b/soc/arm/nxp_kinetis/ke1xf/linker.ld deleted file mode 100644 index 7a1df7beaa5248c..000000000000000 --- a/soc/arm/nxp_kinetis/ke1xf/linker.ld +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images and XIP images. - */ - -#include diff --git a/soc/arm/nxp_kinetis/kl2x/CMakeLists.txt b/soc/arm/nxp_kinetis/kl2x/CMakeLists.txt index 9486f25591264b0..268f065fb12d7f7 100644 --- a/soc/arm/nxp_kinetis/kl2x/CMakeLists.txt +++ b/soc/arm/nxp_kinetis/kl2x/CMakeLists.txt @@ -1,3 +1,5 @@ # 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 "") diff --git a/soc/arm/nxp_kinetis/kl2x/Kconfig.series b/soc/arm/nxp_kinetis/kl2x/Kconfig.series index 53558c8164814a1..3c606c7db272de4 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/kl2x/linker.ld b/soc/arm/nxp_kinetis/kl2x/linker.ld deleted file mode 100644 index 7a1df7beaa5248c..000000000000000 --- a/soc/arm/nxp_kinetis/kl2x/linker.ld +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images and XIP images. - */ - -#include diff --git a/soc/arm/nxp_kinetis/kv5x/CMakeLists.txt b/soc/arm/nxp_kinetis/kv5x/CMakeLists.txt index 332416ba43b0fe6..7424bb9f7b9bc80 100644 --- a/soc/arm/nxp_kinetis/kv5x/CMakeLists.txt +++ b/soc/arm/nxp_kinetis/kv5x/CMakeLists.txt @@ -3,3 +3,5 @@ zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_kinetis/kv5x/Kconfig.series b/soc/arm/nxp_kinetis/kv5x/Kconfig.series index 009d31ea350b7f5..0df355a58236c87 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 3a9a6d3adf2487a..dd69ca523b0b410 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/linker.ld b/soc/arm/nxp_kinetis/kv5x/linker.ld deleted file mode 100644 index 7a1df7beaa5248c..000000000000000 --- a/soc/arm/nxp_kinetis/kv5x/linker.ld +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images and XIP images. - */ - -#include diff --git a/soc/arm/nxp_kinetis/kv5x/soc.c b/soc/arm/nxp_kinetis/kv5x/soc.c index 4c566dadcd05513..59b77f1c1724913 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/CMakeLists.txt b/soc/arm/nxp_kinetis/kwx/CMakeLists.txt index 9b651c95828ef70..d414d72a63a4f58 100644 --- a/soc/arm/nxp_kinetis/kwx/CMakeLists.txt +++ b/soc/arm/nxp_kinetis/kwx/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_sources_ifdef(CONFIG_SOC_MKW24D5 soc_kw2xd.c) zephyr_sources_ifdef(CONFIG_SOC_MKW22D5 soc_kw2xd.c) zephyr_sources_ifdef(CONFIG_SOC_MKW41Z4 soc_kw4xz.c) zephyr_sources_ifdef(CONFIG_SOC_MKW40Z4 soc_kw4xz.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_kinetis/kwx/Kconfig.series b/soc/arm/nxp_kinetis/kwx/Kconfig.series index 4b00dd997a952c4..36ba7b54c2199a1 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_kinetis/kwx/linker.ld b/soc/arm/nxp_kinetis/kwx/linker.ld deleted file mode 100644 index 7a1df7beaa5248c..000000000000000 --- a/soc/arm/nxp_kinetis/kwx/linker.ld +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images and XIP images. - */ - -#include diff --git a/soc/arm/nxp_lpc/lpc11u6x/CMakeLists.txt b/soc/arm/nxp_lpc/lpc11u6x/CMakeLists.txt index 84686ad59cd1175..e9a04818a9376ad 100644 --- a/soc/arm/nxp_lpc/lpc11u6x/CMakeLists.txt +++ b/soc/arm/nxp_lpc/lpc11u6x/CMakeLists.txt @@ -3,3 +3,5 @@ # # SPDX-License-Identifier: Apache-2.0 # + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_lpc/lpc11u6x/linker.ld b/soc/arm/nxp_lpc/lpc11u6x/linker.ld deleted file mode 100644 index ad9319b49774353..000000000000000 --- a/soc/arm/nxp_lpc/lpc11u6x/linker.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images and XIP images. - */ - - -#include diff --git a/soc/arm/nxp_lpc/lpc11u6x/soc.h b/soc/arm/nxp_lpc/lpc11u6x/soc.h index fd7ffbd54006a9f..ec0abb4faf17841 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/CMakeLists.txt b/soc/arm/nxp_lpc/lpc51u68/CMakeLists.txt index c2ef013fe6244d2..a0b6a0303032703 100644 --- a/soc/arm/nxp_lpc/lpc51u68/CMakeLists.txt +++ b/soc/arm/nxp_lpc/lpc51u68/CMakeLists.txt @@ -11,3 +11,5 @@ zephyr_library_include_directories( ${ZEPHYR_BASE}/kernel/include ${ZEPHYR_BASE}/arch/${ARCH}/include ) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_lpc/lpc51u68/Kconfig.series b/soc/arm/nxp_lpc/lpc51u68/Kconfig.series index 6995de0917acf4e..8b1a9dd18b18639 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 45355fb148e20f3..9135c3fed71796f 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/CMakeLists.txt b/soc/arm/nxp_lpc/lpc54xxx/CMakeLists.txt index 09fdf8ae51ad680..fda5d9532e8fc55 100644 --- a/soc/arm/nxp_lpc/lpc54xxx/CMakeLists.txt +++ b/soc/arm/nxp_lpc/lpc54xxx/CMakeLists.txt @@ -19,3 +19,5 @@ zephyr_library_include_directories( if(NOT DEFINED CONFIG_LPC54XXX_SRAM2_CLOCK) zephyr_compile_definitions(DONT_ENABLE_DISABLED_RAMBANKS=1) endif() + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_lpc/lpc54xxx/Kconfig.soc b/soc/arm/nxp_lpc/lpc54xxx/Kconfig.soc index 099dc832d5bb77d..e71bc8f451e46e7 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 bbc689dbc68d172..20f2022cd56b560 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/CMakeLists.txt b/soc/arm/nxp_lpc/lpc55xxx/CMakeLists.txt index 22bb1ed0d552242..fb58ca649f232ab 100644 --- a/soc/arm/nxp_lpc/lpc55xxx/CMakeLists.txt +++ b/soc/arm/nxp_lpc/lpc55xxx/CMakeLists.txt @@ -23,3 +23,5 @@ endif() if(NOT DEFINED CONFIG_LPC55XXX_SRAM_CLOCKS) zephyr_compile_definitions(DONT_ENABLE_DISABLED_RAMBANKS=1) endif() + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc b/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc index a1531b8ede4905d..c8c3cae3c496288 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,13 +124,17 @@ 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. Note that flash programming operations are limited to 100MHz, and this PLL should not be used as the core clock in those cases. +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 144000000 if INIT_PLL1 + default 96000000 + config SECOND_CORE_MCUX bool "LPC55xxx's second core" depends on HAS_MCUX diff --git a/soc/arm/nxp_lpc/lpc55xxx/soc.c b/soc/arm/nxp_lpc/lpc55xxx/soc.c index 8084be533841e51..a26aae34d9b7637 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 @@ -217,7 +217,7 @@ static ALWAYS_INLINE void clock_init(void) #if CONFIG_USB_DC_NXP_LPCIP3511 -#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(usbfs), nxp_mcux_usbd, okay) +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(usbfs), nxp_lpcip3511, okay) /*< Turn on USB Phy */ #if defined(CONFIG_SOC_LPC55S36) POWER_DisablePD(kPDRUNCFG_PD_USBFSPHY); @@ -248,7 +248,7 @@ static ALWAYS_INLINE void clock_init(void) #endif /* USB_DEVICE_TYPE_FS */ -#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(usbhs), nxp_mcux_usbd, okay) +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(usbhs), nxp_lpcip3511, okay) /* enable usb1 host clock */ CLOCK_EnableClock(kCLOCK_Usbh1); /* Put PHY powerdown under software control */ @@ -347,6 +347,10 @@ DT_FOREACH_STATUS_OKAY(nxp_lpc_ctimer, CTIMER_CLOCK_SETUP) #endif /* SOC platform */ #endif /* DAC */ +#ifdef CONFIG_COUNTER_NXP_MRT + RESET_PeripheralReset(kMRT_RST_SHIFT_RSTn); +#endif + } /** diff --git a/soc/arm/nxp_s32/Kconfig b/soc/arm/nxp_s32/Kconfig index 5a33f2065fffc2b..d014315e4d70b1d 100644 --- a/soc/arm/nxp_s32/Kconfig +++ b/soc/arm/nxp_s32/Kconfig @@ -35,8 +35,4 @@ config NXP_S32_DEST_RESET_THRESHOLD source "soc/arm/nxp_s32/*/Kconfig.soc" -config SOC_PART_NUMBER - default SOC_PART_NUMBER_S32ZE_R52 if SOC_SERIES_S32ZE_R52 - default SOC_PART_NUMBER_S32K3 if SOC_SERIES_S32K3_M7 - endif # SOC_FAMILY_NXP_S32 diff --git a/soc/arm/nxp_s32/common/CMakeLists.txt b/soc/arm/nxp_s32/common/CMakeLists.txt index 13ec5b281017967..6142be7ab642d96 100644 --- a/soc/arm/nxp_s32/common/CMakeLists.txt +++ b/soc/arm/nxp_s32/common/CMakeLists.txt @@ -3,4 +3,4 @@ zephyr_include_directories(.) zephyr_sources(osif.c) -zephyr_sources_ifdef(CONFIG_SOC_SERIES_S32K3_M7 power_soc.c) +zephyr_sources_ifdef(CONFIG_SOC_SERIES_S32K3XX power_soc.c) 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 000000000000000..ab2bcd971f03a3c --- /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 344a1416ee84fb0..73b5c6c1d1fe4bb 100644 --- a/soc/arm/nxp_s32/common/osif.c +++ b/soc/arm/nxp_s32/common/osif.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include -#if defined(CONFIG_SOC_S32Z27_R52) -#include -#elif defined(CONFIG_SOC_S32K344_M7) -#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 */ diff --git a/soc/arm/nxp_s32/common/pinctrl_soc.h b/soc/arm/nxp_s32/common/pinctrl_soc.h index 46c1c77bfd1c80e..60c609497aa0853 100644 --- a/soc/arm/nxp_s32/common/pinctrl_soc.h +++ b/soc/arm/nxp_s32/common/pinctrl_soc.h @@ -19,6 +19,11 @@ /** @brief Type for NXP S32 pin configuration. */ typedef Siul2_Port_Ip_PinSettingsConfig pinctrl_soc_pin_t; +/* Alias for compatibility with previous RTD versions */ +#if !defined(FEATURE_SIUL2_MAX_NUMBER_OF_INPUT) && defined(FEATURE_SIUL2_MAX_NUMBER_OF_INPUT_U8) +#define FEATURE_SIUL2_MAX_NUMBER_OF_INPUT FEATURE_SIUL2_MAX_NUMBER_OF_INPUT_U8 +#endif + #if defined(SIUL2_PORT_IP_MULTIPLE_SIUL2_INSTANCES) #define NXP_S32_SIUL2_IDX(n) \ n == 0 ? IP_SIUL2_0 : (n == 1 ? IP_SIUL2_1 : ( \ diff --git a/soc/arm/nxp_s32/common/power_soc.c b/soc/arm/nxp_s32/common/power_soc.c index eef489ee8df74be..3e277155cb82ea9 100644 --- a/soc/arm/nxp_s32/common/power_soc.c +++ b/soc/arm/nxp_s32/common/power_soc.c @@ -71,7 +71,7 @@ static int nxp_s32_power_init(void) }; const Power_Ip_PMC_ConfigType pmc_cfg = { -#ifdef CONFIG_SOC_PART_NUMBER_S32K3 +#ifdef CONFIG_SOC_SERIES_S32K3XX /* PMC Configuration Register (CONFIG) */ .ConfigRegister = PMC_CONFIG_LMEN(IS_ENABLED(CONFIG_NXP_S32_PMC_LMEN)) | PMC_CONFIG_LMBCTLEN(IS_ENABLED(CONFIG_NXP_S32_PMC_LMBCTLEN)), diff --git a/soc/arm/nxp_s32/s32k/CMakeLists.txt b/soc/arm/nxp_s32/s32k/CMakeLists.txt deleted file mode 100644 index f223c351a702a89..000000000000000 --- a/soc/arm/nxp_s32/s32k/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright 2023 NXP -# SPDX-License-Identifier: Apache-2.0 - -zephyr_library() - -zephyr_library_sources(soc.c) -zephyr_library_sources_ifdef(CONFIG_CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS mpu_regions.c) -zephyr_linker_sources(SECTIONS sections.ld) -zephyr_library_sources_ifdef(CONFIG_PLATFORM_SPECIFIC_INIT s32k3xx_startup.S) diff --git a/soc/arm/nxp_s32/s32k/Kconfig.defconfig.s32k344 b/soc/arm/nxp_s32/s32k/Kconfig.defconfig.s32k344 deleted file mode 100644 index 3dfab7603379adf..000000000000000 --- a/soc/arm/nxp_s32/s32k/Kconfig.defconfig.s32k344 +++ /dev/null @@ -1,14 +0,0 @@ -# S32K344 - -# Copyright 2023 NXP -# SPDX-License-Identifier: Apache-2.0 - -if SOC_S32K344_M7 - -config SOC - default "s32k344" - -config FPU - default y - -endif # SOC_S32K344_M7 diff --git a/soc/arm/nxp_s32/s32k/Kconfig.defconfig.series b/soc/arm/nxp_s32/s32k/Kconfig.defconfig.series deleted file mode 100644 index 93786720698689c..000000000000000 --- a/soc/arm/nxp_s32/s32k/Kconfig.defconfig.series +++ /dev/null @@ -1,37 +0,0 @@ -# S32 K M7 core series - -# Copyright 2023 NXP -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_S32K3_M7 - -config SOC_SERIES - default "s32k" - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 2000000 - -config NUM_IRQS - # must be >= the highest interrupt number used - default 239 - -if !XIP -config FLASH_SIZE - default 0 -config FLASH_BASE_ADDRESS - default 0 -endif - -if NET_L2_ETHERNET - -config NET_TCP_CHECKSUM - default n - -config NET_UDP_CHECKSUM - default n - -endif # NET_L2_ETHERNET - -source "soc/arm/nxp_s32/s32k/Kconfig.defconfig.s32k*" - -endif # SOC_SERIES_S32K_M7 diff --git a/soc/arm/nxp_s32/s32k/Kconfig.series b/soc/arm/nxp_s32/s32k/Kconfig.series deleted file mode 100644 index 3567b562cd79014..000000000000000 --- a/soc/arm/nxp_s32/s32k/Kconfig.series +++ /dev/null @@ -1,24 +0,0 @@ -# NXP S32K3 MCUs family - -# Copyright 2023 NXP -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_S32K3_M7 - bool "S32K3 M7 Core Series" - select ARM - select CPU_CORTEX_M7 - select SOC_FAMILY_NXP_S32 - select CPU_HAS_FPU - select CPU_HAS_ARM_MPU - select CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS - select PLATFORM_SPECIFIC_INIT if XIP - select USE_DT_CODE_PARTITION if XIP - select CLOCK_CONTROL - select HAS_MCUX - select HAS_MCUX_LPUART - select HAS_MCUX_FLEXCAN - select HAS_MCUX_LPI2C - select HAS_MCUX_LPSPI - select HAS_MCUX_CACHE - help - Enable support for NXP S32K3 MCUs family on Cortex-M7 cores diff --git a/soc/arm/nxp_s32/s32k/Kconfig.soc b/soc/arm/nxp_s32/s32k/Kconfig.soc deleted file mode 100644 index 978c5daf65a393c..000000000000000 --- a/soc/arm/nxp_s32/s32k/Kconfig.soc +++ /dev/null @@ -1,62 +0,0 @@ -# NXP S32K MCUs family - -# Copyright 2023 NXP -# SPDX-License-Identifier: Apache-2.0 - -choice - prompt "NXP S32K MCUs family SoC Selection" - depends on SOC_SERIES_S32K3_M7 - -config SOC_S32K344_M7 - bool "SOC_S32K_M7" - select HAS_NXP_S32_HAL - -endchoice - -if SOC_SERIES_S32K3_M7 - -config SOC_PART_NUMBER_S32K344 - bool - -config SOC_PART_NUMBER_S32K3 - string - default "S32K344" if SOC_PART_NUMBER_S32K344 - 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 IVT_HEADER_OFFSET - hex - depends on XIP - default $(dt_node_reg_addr_hex,$(dt_nodelabel_path,ivt_header)) - help - The offset address from flash base address for ivt header - -config IVT_HEADER_SIZE - hex - depends on XIP - default $(dt_node_reg_size_hex,$(dt_nodelabel_path,ivt_header)) - help - Size of ivt header region - -config NXP_S32_PMC_LMEN - bool "Last Mile regulator" - default y if CLOCK_CONTROL - help - Enables the Last Mile regulator, which regulates an external 1.5V - voltage on V15 down to the core and logic supply (V11 power domain), - which is typically 1.1V. - When enabling PLL as system clock, the PMC last mile regulator should - be enabled. - -config NXP_S32_PMC_LMBCTLEN - bool "External BCTL regulator for V15" - depends on NXP_S32_PMC_LMEN - help - This option must be selected if an external BJT between VDD_HV_A and - V15 is used on the PCB. The base of this BJT must be connected to the - VRC_CTRL pin and is controlled by the PMC to regulate a voltage of - 1.5V on V15 pin. - -endif diff --git a/soc/arm/nxp_s32/s32k/soc.c b/soc/arm/nxp_s32/s32k/soc.c deleted file mode 100644 index 5db4204a89ca5b3..000000000000000 --- a/soc/arm/nxp_s32/s32k/soc.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2023 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#include -#include - -#ifdef CONFIG_XIP -/* Image Vector Table structure definition for S32K3XX */ -struct ivt { - uint32_t header; - uint32_t boot_configure; - const uint32_t reserved_1; - const uint32_t *cm7_0_start_address; - const uint32_t reserved_2; - const uint32_t *cm7_1_start_address; - const uint32_t reserved_3; - const uint32_t *cm7_2_start_address; - const uint32_t reserved_4; - const uint32_t *lc_configure; - uint8_t reserved7[216]; -}; - -#define IVT_MAGIC_MARKER 0x5AA55AA5 - -extern char _vector_start[]; - -/* - * IVT for SoC S32K344, the minimal boot configuration is: - * - Watchdog (SWT0) is disabled (default value). - * - Non-Secure Boot is used (default value). - * - Ungate clock for Cortex-M7_0 after boot. - * - Application start address of Cortex-M7_0 is application's vector table. - */ -const struct ivt ivt_header __attribute__((section(".ivt_header"))) = { - .header = IVT_MAGIC_MARKER, - .boot_configure = 1, - .cm7_0_start_address = (const void *)_vector_start, - .cm7_1_start_address = NULL, - .cm7_2_start_address = NULL, - .lc_configure = NULL, -}; -#endif /* CONFIG_XIP */ - -static int soc_init(void) -{ - SCB_EnableICache(); - - if (IS_ENABLED(CONFIG_DCACHE)) { - if (!(SCB->CCR & SCB_CCR_DC_Msk)) { - SCB_EnableDCache(); - } - } - - OsIf_Init(NULL); - - return 0; -} - -SYS_INIT(soc_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/nxp_s32/s32k/soc.h b/soc/arm/nxp_s32/s32k/soc.h deleted file mode 100644 index fa29a9601724ccc..000000000000000 --- a/soc/arm/nxp_s32/s32k/soc.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2023 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _NXP_S32_S32K_SOC_H_ -#define _NXP_S32_S32K_SOC_H_ - -#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 -#endif - -#endif /* _NXP_S32_S32K_SOC_H_ */ diff --git a/soc/arm/nxp_s32/s32k1/CMakeLists.txt b/soc/arm/nxp_s32/s32k1/CMakeLists.txt new file mode 100644 index 000000000000000..ff8085fc5c1cc8f --- /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 000000000000000..522710112dcac00 --- /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 000000000000000..49dfd9f31cf04a0 --- /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 000000000000000..07fe41bda9e930a --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/Kconfig.series @@ -0,0 +1,23 @@ +# 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 + 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 000000000000000..78caf49f677fb9c --- /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 000000000000000..6ff64221be47d22 --- /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 000000000000000..af1ec998ebbc394 --- /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 000000000000000..5c8ac8de3b95b54 --- /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 000000000000000..fde3c12954fe488 --- /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 000000000000000..bed85dbc91ddae0 --- /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 000000000000000..b58a49ab2567166 --- /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/CMakeLists.txt b/soc/arm/nxp_s32/s32k3/CMakeLists.txt new file mode 100644 index 000000000000000..d65a1a2e73b66b6 --- /dev/null +++ b/soc/arm/nxp_s32/s32k3/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(soc.c) +zephyr_library_sources_ifdef(CONFIG_CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS mpu_regions.c) +zephyr_linker_sources(SECTIONS sections.ld) +zephyr_library_sources_ifdef(CONFIG_PLATFORM_SPECIFIC_INIT s32k3xx_startup.S) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.s32k344 b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.s32k344 new file mode 100644 index 000000000000000..b1b534f6102dad4 --- /dev/null +++ b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.s32k344 @@ -0,0 +1,14 @@ +# NXP S32K344 + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_S32K344 + +config SOC + default "s32k344" + +config FPU + default y + +endif # SOC_S32K344 diff --git a/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series new file mode 100644 index 000000000000000..2307571611aba07 --- /dev/null +++ b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series @@ -0,0 +1,40 @@ +# NXP S32K3XX MCU series + +# Copyright 2023-2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_S32K3XX + +config SOC_SERIES + default "s32k3" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 2000000 + +config NUM_IRQS + # must be >= the highest interrupt number used + default 239 + +if !XIP +config FLASH_SIZE + default 0 +config FLASH_BASE_ADDRESS + default 0 +endif + +if NET_L2_ETHERNET + +config NET_TCP_CHECKSUM + default n + +config NET_UDP_CHECKSUM + default n + +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 new file mode 100644 index 000000000000000..ac90439b6446a34 --- /dev/null +++ b/soc/arm/nxp_s32/s32k3/Kconfig.series @@ -0,0 +1,27 @@ +# NXP S32K3XX MCU series + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_S32K3XX + bool "NXP S32K3XX MCU series" + select ARM + select CPU_CORTEX_M7 + select SOC_FAMILY_NXP_S32 + 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 + select CLOCK_CONTROL + select HAS_MCUX + select HAS_MCUX_LPUART + select HAS_MCUX_FLEXCAN + select HAS_MCUX_LPI2C + select HAS_MCUX_LPSPI + select HAS_MCUX_CACHE + help + Enable support for NXP S32K3XX MCU series. diff --git a/soc/arm/nxp_s32/s32k3/Kconfig.soc b/soc/arm/nxp_s32/s32k3/Kconfig.soc new file mode 100644 index 000000000000000..6b8f4e3a8839702 --- /dev/null +++ b/soc/arm/nxp_s32/s32k3/Kconfig.soc @@ -0,0 +1,61 @@ +# NXP S32K3XX MCU series + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "NXP S32K3XX MCU selection" + depends on SOC_SERIES_S32K3XX + +config SOC_S32K344 + bool "s32k344" + +endchoice + +if SOC_SERIES_S32K3XX + +config SOC_PART_NUMBER_PS32K344EHVPBS + bool + +config SOC_PART_NUMBER + string + default "PS32K344EHVPBS" if SOC_PART_NUMBER_PS32K344EHVPBS + 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 IVT_HEADER_OFFSET + hex + depends on XIP + default $(dt_node_reg_addr_hex,$(dt_nodelabel_path,ivt_header)) + help + The offset address from flash base address for ivt header + +config IVT_HEADER_SIZE + hex + depends on XIP + default $(dt_node_reg_size_hex,$(dt_nodelabel_path,ivt_header)) + help + Size of ivt header region + +config NXP_S32_PMC_LMEN + bool "Last Mile regulator" + default y if CLOCK_CONTROL + help + Enables the Last Mile regulator, which regulates an external 1.5V + voltage on V15 down to the core and logic supply (V11 power domain), + which is typically 1.1V. + When enabling PLL as system clock, the PMC last mile regulator should + be enabled. + +config NXP_S32_PMC_LMBCTLEN + bool "External BCTL regulator for V15" + depends on NXP_S32_PMC_LMEN + help + This option must be selected if an external BJT between VDD_HV_A and + V15 is used on the PCB. The base of this BJT must be connected to the + VRC_CTRL pin and is controlled by the PMC to regulate a voltage of + 1.5V on V15 pin. + +endif diff --git a/soc/arm/nxp_s32/s32k/linker.ld b/soc/arm/nxp_s32/s32k3/linker.ld similarity index 100% rename from soc/arm/nxp_s32/s32k/linker.ld rename to soc/arm/nxp_s32/s32k3/linker.ld diff --git a/soc/arm/nxp_s32/s32k/mpu_regions.c b/soc/arm/nxp_s32/s32k3/mpu_regions.c similarity index 100% rename from soc/arm/nxp_s32/s32k/mpu_regions.c rename to soc/arm/nxp_s32/s32k3/mpu_regions.c diff --git a/soc/arm/nxp_s32/s32k/s32k3xx_startup.S b/soc/arm/nxp_s32/s32k3/s32k3xx_startup.S similarity index 100% rename from soc/arm/nxp_s32/s32k/s32k3xx_startup.S rename to soc/arm/nxp_s32/s32k3/s32k3xx_startup.S diff --git a/soc/arm/nxp_s32/s32k/sections.ld b/soc/arm/nxp_s32/s32k3/sections.ld similarity index 100% rename from soc/arm/nxp_s32/s32k/sections.ld rename to soc/arm/nxp_s32/s32k3/sections.ld diff --git a/soc/arm/nxp_s32/s32k3/soc.c b/soc/arm/nxp_s32/s32k3/soc.c new file mode 100644 index 000000000000000..be822677189e614 --- /dev/null +++ b/soc/arm/nxp_s32/s32k3/soc.c @@ -0,0 +1,62 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_XIP +/* Image Vector Table structure definition for S32K3XX */ +struct ivt { + uint32_t header; + uint32_t boot_configure; + const uint32_t reserved_1; + const uint32_t *cm7_0_start_address; + const uint32_t reserved_2; + const uint32_t *cm7_1_start_address; + const uint32_t reserved_3; + const uint32_t *cm7_2_start_address; + const uint32_t reserved_4; + const uint32_t *lc_configure; + uint8_t reserved7[216]; +}; + +#define IVT_MAGIC_MARKER 0x5AA55AA5 + +extern char _vector_start[]; + +/* + * IVT for SoC S32K344, the minimal boot configuration is: + * - Watchdog (SWT0) is disabled (default value). + * - Non-Secure Boot is used (default value). + * - Ungate clock for Cortex-M7_0 after boot. + * - Application start address of Cortex-M7_0 is application's vector table. + */ +const struct ivt ivt_header __attribute__((section(".ivt_header"))) = { + .header = IVT_MAGIC_MARKER, + .boot_configure = 1, + .cm7_0_start_address = (const void *)_vector_start, + .cm7_1_start_address = NULL, + .cm7_2_start_address = NULL, + .lc_configure = NULL, +}; +#endif /* CONFIG_XIP */ + +static int soc_init(void) +{ + sys_cache_instr_enable(); + sys_cache_data_enable(); + + OsIf_Init(NULL); + + return 0; +} + +SYS_INIT(soc_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/nxp_s32/s32k3/soc.h b/soc/arm/nxp_s32/s32k3/soc.h new file mode 100644 index 000000000000000..86af70cc9c67b10 --- /dev/null +++ b/soc/arm/nxp_s32/s32k3/soc.h @@ -0,0 +1,22 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _NXP_S32_S32K_SOC_H_ +#define _NXP_S32_S32K_SOC_H_ + +#include +#include + +#if defined(CONFIG_CMSIS_RTOS_V2) +#include +#endif + +/* Aliases for peripheral base addresses */ + +/* SIUL2 */ +#define IP_SIUL2_0_BASE IP_SIUL2_BASE + +#endif /* _NXP_S32_S32K_SOC_H_ */ diff --git a/soc/arm/nxp_s32/s32ze/CMakeLists.txt b/soc/arm/nxp_s32/s32ze/CMakeLists.txt index 155354816f3aaf3..d0eb4cf78b1e1a3 100644 --- a/soc/arm/nxp_s32/s32ze/CMakeLists.txt +++ b/soc/arm/nxp_s32/s32ze/CMakeLists.txt @@ -6,3 +6,5 @@ zephyr_library_sources( ) zephyr_library_sources_ifdef(CONFIG_ARM_MPU mpu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_s32/s32ze/Kconfig.soc b/soc/arm/nxp_s32/s32ze/Kconfig.soc index 757b40966349836..790751362d3e634 100644 --- a/soc/arm/nxp_s32/s32ze/Kconfig.soc +++ b/soc/arm/nxp_s32/s32ze/Kconfig.soc @@ -1,6 +1,6 @@ # NXP S32Z/E MCUs family -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # SPDX-License-Identifier: Apache-2.0 choice @@ -18,7 +18,7 @@ if SOC_SERIES_S32ZE_R52 config SOC_PART_NUMBER_S32Z27 bool -config SOC_PART_NUMBER_S32ZE_R52 +config SOC_PART_NUMBER string default "S32Z27" if SOC_PART_NUMBER_S32Z27 help diff --git a/soc/arm/nxp_s32/s32ze/linker.ld b/soc/arm/nxp_s32/s32ze/linker.ld deleted file mode 100644 index d04a2dc6065b4d1..000000000000000 --- a/soc/arm/nxp_s32/s32ze/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright 2022 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/nxp_s32/s32ze/soc.c b/soc/arm/nxp_s32/s32ze/soc.c index 36acfbf9dc83be8..871536a26c6ef1a 100644 --- a/soc/arm/nxp_s32/s32ze/soc.c +++ b/soc/arm/nxp_s32/s32ze/soc.c @@ -21,6 +21,12 @@ void z_arm_platform_init(void) barrier_dsync_fence_full(); barrier_isync_fence_full(); + /* + * Take exceptions in Arm mode because Zephyr ASM code for Cortex-R Aarch32 + * is written for Arm + */ + __set_SCTLR(__get_SCTLR() & ~SCTLR_TE_Msk); + if (IS_ENABLED(CONFIG_ICACHE)) { if (!(__get_SCTLR() & SCTLR_I_Msk)) { L1C_InvalidateICacheAll(); diff --git a/soc/arm/nxp_s32/s32ze/soc.h b/soc/arm/nxp_s32/s32ze/soc.h index 1bacb430a004a52..e042ebe8af90750 100644 --- a/soc/arm/nxp_s32/s32ze/soc.h +++ b/soc/arm/nxp_s32/s32ze/soc.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 NXP + * Copyright 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,4 +10,65 @@ /* Do not let CMSIS to handle GIC */ #define __GIC_PRESENT 0 +#if defined(CONFIG_SOC_S32Z27_R52) +#include +#else +#error "SoC not supported" +#endif + +#if defined(CONFIG_CMSIS_RTOS_V2) +#include +#endif + +/* Aliases for peripheral base addresses */ + +/* SIUL2 */ +#define IP_SIUL2_2_BASE 0U /* instance does not exist on this SoC */ + +/* LINFlexD*/ +#define IP_LINFLEX_12_BASE IP_MSC_0_LIN_BASE + +/* SWT */ +#define IP_SWT_0_BASE IP_CE_SWT_0_BASE +#define IP_SWT_1_BASE IP_CE_SWT_1_BASE +#define IP_SWT_2_BASE IP_RTU0__SWT_0_BASE +#define IP_SWT_3_BASE IP_RTU0__SWT_1_BASE +#define IP_SWT_4_BASE IP_RTU0__SWT_2_BASE +#define IP_SWT_5_BASE IP_RTU0__SWT_3_BASE +#define IP_SWT_6_BASE IP_RTU0__SWT_4_BASE +#define IP_SWT_7_BASE IP_RTU1__SWT_0_BASE +#define IP_SWT_8_BASE IP_RTU1__SWT_1_BASE +#define IP_SWT_9_BASE IP_RTU1__SWT_2_BASE +#define IP_SWT_10_BASE IP_RTU1__SWT_3_BASE +#define IP_SWT_11_BASE IP_RTU1__SWT_4_BASE +#define IP_SWT_12_BASE IP_SMU__SWT_BASE + +/* STM */ +#define IP_STM_0_BASE IP_CE_STM_0_BASE +#define IP_STM_1_BASE IP_CE_STM_1_BASE +#define IP_STM_2_BASE IP_CE_STM_2_BASE +#define IP_STM_3_BASE IP_RTU0__STM_0_BASE +#define IP_STM_4_BASE IP_RTU0__STM_1_BASE +#define IP_STM_5_BASE IP_RTU0__STM_2_BASE +#define IP_STM_6_BASE IP_RTU0__STM_3_BASE +#define IP_STM_7_BASE IP_RTU1__STM_0_BASE +#define IP_STM_8_BASE IP_RTU1__STM_1_BASE +#define IP_STM_9_BASE IP_RTU1__STM_2_BASE +#define IP_STM_10_BASE IP_RTU1__STM_3_BASE +#define IP_STM_11_BASE IP_SMU__STM_0_BASE +#define IP_STM_12_BASE IP_SMU__STM_2_BASE + +/* NETC */ +#define IP_NETC_EMDIO_0_BASE IP_NETC__EMDIO_BASE_BASE + +/* MRU */ +#define IP_MRU_0_BASE IP_RTU0__MRU_0_BASE +#define IP_MRU_1_BASE IP_RTU0__MRU_1_BASE +#define IP_MRU_2_BASE IP_RTU0__MRU_2_BASE +#define IP_MRU_3_BASE IP_RTU0__MRU_3_BASE +#define IP_MRU_4_BASE IP_RTU1__MRU_0_BASE +#define IP_MRU_5_BASE IP_RTU1__MRU_1_BASE +#define IP_MRU_6_BASE IP_RTU1__MRU_2_BASE +#define IP_MRU_7_BASE IP_RTU1__MRU_3_BASE + #endif /* _NXP_S32_S32ZE_SOC_H_ */ diff --git a/soc/arm/quicklogic_eos_s3/CMakeLists.txt b/soc/arm/quicklogic_eos_s3/CMakeLists.txt index 5da2746a1bcd08b..224b298c4096389 100644 --- a/soc/arm/quicklogic_eos_s3/CMakeLists.txt +++ b/soc/arm/quicklogic_eos_s3/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/quicklogic_eos_s3/Kconfig.soc b/soc/arm/quicklogic_eos_s3/Kconfig.soc index cb5fd170870ca18..e555933430bbdb3 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/quicklogic_eos_s3/linker.ld b/soc/arm/quicklogic_eos_s3/linker.ld deleted file mode 100644 index 5d2ea23f266694e..000000000000000 --- a/soc/arm/quicklogic_eos_s3/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* -# Copyright (c) 2020 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/renesas_ra/CMakeLists.txt b/soc/arm/renesas_ra/CMakeLists.txt new file mode 100644 index 000000000000000..b6a22aa757b4716 --- /dev/null +++ b/soc/arm/renesas_ra/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(common) + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/arm/renesas_ra/Kconfig b/soc/arm/renesas_ra/Kconfig new file mode 100644 index 000000000000000..628b75a93deeee3 --- /dev/null +++ b/soc/arm/renesas_ra/Kconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_RA + bool + +if SOC_FAMILY_RA + +config SOC_FAMILY + string + default "renesas_ra" + +config SERIES_SPECIFIC_SOC_INIT + bool "Use series specific initialize" + +source "soc/arm/renesas_ra/*/Kconfig.soc" + +endif # SOC_FAMILY_RA diff --git a/soc/arm/renesas_ra/Kconfig.defconfig b/soc/arm/renesas_ra/Kconfig.defconfig new file mode 100644 index 000000000000000..e5e211a94b3da8c --- /dev/null +++ b/soc/arm/renesas_ra/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +source "soc/arm/renesas_ra/*/Kconfig.defconfig.series" diff --git a/soc/arm/renesas_ra/Kconfig.soc b/soc/arm/renesas_ra/Kconfig.soc new file mode 100644 index 000000000000000..2652ee94d2ee233 --- /dev/null +++ b/soc/arm/renesas_ra/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +source "soc/arm/renesas_ra/*/Kconfig.series" diff --git a/soc/arm/renesas_ra/common/pinctrl_ra.h b/soc/arm/renesas_ra/common/pinctrl_ra.h new file mode 100644 index 000000000000000..ed80b3fda1856f1 --- /dev/null +++ b/soc/arm/renesas_ra/common/pinctrl_ra.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_RENESAS_RA_COMMON_RA_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_RENESAS_RA_COMMON_RA_PINCTRL_SOC_H_ + +enum { + PmnPFS_PODR_POS, + PmnPFS_PIDR_POS, + PmnPFS_PDR_POS, + PmnPFS_RSV3_POS, + PmnPFS_PCR_POS, + PmnPFS_RSV5_POS, + PmnPFS_NCODR_POS, + PmnPFS_RSV7_POS, + PmnPFS_RSV8_POS, + PmnPFS_RSV9_POS, + PmnPFS_DSCR_POS, + PmnPFS_DSCR1_POS, + PmnPFS_EOR_POS, + PmnPFS_EOF_POS, + PmnPFS_ISEL_POS, + PmnPFS_ASEL_POS, + PmnPFS_PMR_POS, +}; + +struct pinctrl_ra_pin { + union { + uint32_t config; + struct { + uint8_t PODR: 1; + uint8_t PIDR: 1; + uint8_t PDR: 1; + uint8_t RESERVED3: 1; + uint8_t PCR: 1; + uint8_t RESERVED5: 1; + uint8_t NCODR: 1; + uint8_t RESERVED7: 1; + uint8_t RESERVED8: 1; + uint8_t RESERVED9: 1; + uint8_t DSCR: 2; + uint8_t EOFR: 2; + uint8_t ISEL: 1; + uint8_t ASEL: 1; + uint8_t PMR: 1; + uint8_t RESERVED17: 7; + uint8_t PSEL: 5; + uint8_t RESERVED29: 3; + }; + /* Using RESERVED fields for store pin and port info. */ + struct { + uint32_t UNUSED0: 17; + uint8_t pin: 4; + uint8_t port: 3; + uint32_t UNUSED24: 5; + uint8_t port4: 1; + uint32_t UNUSED30: 2; + }; + }; +}; + +typedef struct pinctrl_ra_pin pinctrl_soc_pin_t; + +extern int pinctrl_ra_query_config(uint32_t port, uint32_t pin, + struct pinctrl_ra_pin *const pincfg); + +/** + * @brief Utility macro to initialize each pin. + * + * @param node_id Node identifier. + * @param prop Property name. + * @param idx Property entry index. + */ +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + { \ + .config = DT_PROP_BY_IDX(node_id, 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_CHILD_VARGS(DT_PHANDLE(node_id, prop), DT_FOREACH_PROP_ELEM, pinmux, \ + Z_PINCTRL_STATE_PIN_INIT) \ + } + +#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 new file mode 100644 index 000000000000000..f76c4c26fc0d47f --- /dev/null +++ b/soc/arm/renesas_ra/common/ra_common_soc.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_RENESAS_RA_COMMON_RA_COMMON_SOC_H_ +#define ZEPHYR_SOC_ARM_RENESAS_RA_COMMON_RA_COMMON_SOC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_SOC_ARM_RENESAS_RA_COMMON_RA_COMMON_SOC_H_ */ diff --git a/soc/arm/renesas_ra/ra4m1/CMakeLists.txt b/soc/arm/renesas_ra/ra4m1/CMakeLists.txt new file mode 100644 index 000000000000000..4debbfdbf8a8e98 --- /dev/null +++ b/soc/arm/renesas_ra/ra4m1/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/renesas_ra/ra4m1/Kconfig.defconfig.r7fa4m1xxxxxx b/soc/arm/renesas_ra/ra4m1/Kconfig.defconfig.r7fa4m1xxxxxx new file mode 100644 index 000000000000000..c138e20d85cc7d6 --- /dev/null +++ b/soc/arm/renesas_ra/ra4m1/Kconfig.defconfig.r7fa4m1xxxxxx @@ -0,0 +1,9 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +if SOC_R7FA4M1AB3CFM + +config SOC + default "r7fa4m1ab3cfm" + +endif # SOC_R7FA4M1AB3CFM diff --git a/soc/arm/renesas_ra/ra4m1/Kconfig.defconfig.series b/soc/arm/renesas_ra/ra4m1/Kconfig.defconfig.series new file mode 100644 index 000000000000000..99e8e3f639d26ed --- /dev/null +++ b/soc/arm/renesas_ra/ra4m1/Kconfig.defconfig.series @@ -0,0 +1,14 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_RA4M1 + +rsource "Kconfig.defconfig.r7fa4*" + +config SOC_SERIES + default "ra4m1" + +config NUM_IRQS + default 32 + +endif # SOC_SERIES_RA4M1 diff --git a/soc/arm/renesas_ra/ra4m1/Kconfig.series b/soc/arm/renesas_ra/ra4m1/Kconfig.series new file mode 100644 index 000000000000000..7307a2d26c0c1f7 --- /dev/null +++ b/soc/arm/renesas_ra/ra4m1/Kconfig.series @@ -0,0 +1,13 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_RA4M1 + bool "Renesas RA4M1" + select ARM + select CPU_CORTEX_M4 + select CPU_HAS_ARM_MPU + select CPU_CORTEX_M_HAS_SYSTICK + select DYNAMIC_INTERRUPTS + select SOC_FAMILY_RA + select TIMER_READS_ITS_FREQUENCY_AT_RUNTIME + select XIP diff --git a/soc/arm/renesas_ra/ra4m1/Kconfig.soc b/soc/arm/renesas_ra/ra4m1/Kconfig.soc new file mode 100644 index 000000000000000..a7b402fd2910736 --- /dev/null +++ b/soc/arm/renesas_ra/ra4m1/Kconfig.soc @@ -0,0 +1,11 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "Renesas RA4M1 SoC Selection" + depends on SOC_SERIES_RA4M1 + +config SOC_R7FA4M1AB3CFM + bool "R7FA4M1AB3CFM" + +endchoice diff --git a/soc/arm/renesas_ra/ra4m1/linker.ld b/soc/arm/renesas_ra/ra4m1/linker.ld new file mode 100644 index 000000000000000..44d5ee518896eef --- /dev/null +++ b/soc/arm/renesas_ra/ra4m1/linker.ld @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include diff --git a/soc/arm/renesas_ra/ra4m1/pinctrl_soc.h b/soc/arm/renesas_ra/ra4m1/pinctrl_soc.h new file mode 100644 index 000000000000000..e149509fab240d5 --- /dev/null +++ b/soc/arm/renesas_ra/ra4m1/pinctrl_soc.h @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "../common/pinctrl_ra.h" diff --git a/soc/arm/renesas_ra/ra4m1/soc.h b/soc/arm/renesas_ra/ra4m1/soc.h new file mode 100644 index 000000000000000..127ee9ab44477e6 --- /dev/null +++ b/soc/arm/renesas_ra/ra4m1/soc.h @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "../common/ra_common_soc.h" diff --git a/soc/arm/renesas_rcar/CMakeLists.txt b/soc/arm/renesas_rcar/CMakeLists.txt index 226f3bd626f6119..20bed32f36af328 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 000000000000000..c3563e014ba1de6 --- /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/CMakeLists.txt b/soc/arm/renesas_rcar/gen3/CMakeLists.txt index 092b4b2c828f185..4356fe77d51250b 100644 --- a/soc/arm/renesas_rcar/gen3/CMakeLists.txt +++ b/soc/arm/renesas_rcar/gen3/CMakeLists.txt @@ -5,3 +5,5 @@ zephyr_sources( soc.c ) zephyr_library_sources_ifdef(CONFIG_SOC_R8A77951 pfc_r8a77951.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/renesas_rcar/gen3/linker.ld b/soc/arm/renesas_rcar/gen3/linker.ld deleted file mode 100644 index f94542d9256e984..000000000000000 --- a/soc/arm/renesas_rcar/gen3/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2021 IoT.bzh - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/renesas_rcar/gen3/pfc_r8a77951.c b/soc/arm/renesas_rcar/gen3/pfc_r8a77951.c index c59be6cfe6fdf4f..c5fb3ab967b246c 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 92f7aa507a44f37..b4f5da3bff0fdbb 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 000000000000000..906bfdecfba748b --- /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 000000000000000..6da34845bf95f08 --- /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 000000000000000..36218fe504fa3a0 --- /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 000000000000000..606b2c50e43a9e5 --- /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 000000000000000..5c443d6101e73e6 --- /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 000000000000000..a51ff84991f8992 --- /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 000000000000000..25eba334d77f9e1 --- /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 000000000000000..f55b114cddba3be --- /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 000000000000000..3717fb8a8a8a440 --- /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_rzt2m/CMakeLists.txt b/soc/arm/renesas_rzt2m/CMakeLists.txt new file mode 100644 index 000000000000000..05fd66ec83cd403 --- /dev/null +++ b/soc/arm/renesas_rzt2m/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources( + soc.c + ) diff --git a/soc/arm/renesas_rzt2m/Kconfig b/soc/arm/renesas_rzt2m/Kconfig new file mode 100644 index 000000000000000..fc2f6e81c4eca4b --- /dev/null +++ b/soc/arm/renesas_rzt2m/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config SOC_RENESAS_RZT2M + bool + +if SOC_RENESAS_RZT2M + +config SOC_PART_NUMBER_R9A07G075 + bool + +config SOC_PART_NUMBER + default SOC_PART_NUMBER_R9A07G075 + +endif # SOC_RENESAS_RZT2M diff --git a/soc/arm/renesas_rzt2m/Kconfig.defconfig b/soc/arm/renesas_rzt2m/Kconfig.defconfig new file mode 100644 index 000000000000000..72f828d4351179c --- /dev/null +++ b/soc/arm/renesas_rzt2m/Kconfig.defconfig @@ -0,0 +1,24 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +if SOC_RENESAS_RZT2M + +config SOC + default "renesas_rzt2m" + +config NUM_IRQS + default 994 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 20000000 + +config FPU + default y + +config FLASH_SIZE + default 0 + +config FLASH_BASE_ADDRESS + default 0 + +endif # SOC_RENESAS_RZT2M diff --git a/soc/arm/renesas_rzt2m/Kconfig.soc b/soc/arm/renesas_rzt2m/Kconfig.soc new file mode 100644 index 000000000000000..0275833b7925ece --- /dev/null +++ b/soc/arm/renesas_rzt2m/Kconfig.soc @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config SOC_RENESAS_RZT2M + bool "Renesas RZ/T2M MCU" + select ARM + select CPU_CORTEX_R52 + select CPU_HAS_ARM_MPU + select GIC_V3 + select GIC_SINGLE_SECURITY_STATE + select ARM_ARCH_TIMER + select SYSCON diff --git a/soc/arm/renesas_rzt2m/linker.ld b/soc/arm/renesas_rzt2m/linker.ld new file mode 100644 index 000000000000000..3a016555ba95bcb --- /dev/null +++ b/soc/arm/renesas_rzt2m/linker.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/soc/arm/renesas_rzt2m/pinctrl_soc.h b/soc/arm/renesas_rzt2m/pinctrl_soc.h new file mode 100644 index 000000000000000..d740d6c115e9bd9 --- /dev/null +++ b/soc/arm/renesas_rzt2m/pinctrl_soc.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_RENESAS_RZT2M_PINCTRL_H_ +#define ZEPHYR_SOC_ARM_RENESAS_RZT2M_PINCTRL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pinctrl_soc_pin_t { + uint32_t port; + uint32_t pin; + uint32_t func; + uint32_t input_enable: 1; + uint32_t output_enable: 1; + uint32_t pull_up: 1; + uint32_t pull_down: 1; + uint32_t high_impedance: 1; + uint32_t slew_rate: 2; + uint8_t drive_strength; + uint32_t schmitt_enable: 1; +} pinctrl_soc_pin_t; + +#define RZT2M_GET_PORT(pinctrl) ((pinctrl >> 16) & 0xff) +#define RZT2M_GET_PIN(pinctrl) ((pinctrl >> 8) & 0xff) +#define RZT2M_GET_FUNC(pinctrl) (pinctrl & 0xff) + +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + { \ + .port = RZT2M_GET_PORT(DT_PROP_BY_IDX(node_id, prop, idx)), \ + .pin = RZT2M_GET_PIN(DT_PROP_BY_IDX(node_id, prop, idx)), \ + .func = RZT2M_GET_FUNC(DT_PROP_BY_IDX(node_id, prop, idx)), \ + .input_enable = DT_PROP(node_id, input_enable), \ + .pull_up = DT_PROP(node_id, bias_pull_up), \ + .pull_down = DT_PROP(node_id, bias_pull_down), \ + .high_impedance = DT_PROP(node_id, bias_high_impedance), \ + .slew_rate = DT_ENUM_IDX(node_id, slew_rate), \ + .drive_strength = DT_ENUM_IDX(node_id, drive_strength), \ + .schmitt_enable = DT_PROP(node_id, input_schmitt_enable), \ + }, + +#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_RENESAS_RZT2M_PINCTRL_H_ */ diff --git a/soc/arm/renesas_rzt2m/soc.c b/soc/arm/renesas_rzt2m/soc.c new file mode 100644 index 000000000000000..5a85409022934ce --- /dev/null +++ b/soc/arm/renesas_rzt2m/soc.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "soc.h" +#include + +static const struct device *const prcrn_dev = DEVICE_DT_GET(DT_NODELABEL(prcrn)); +static const struct device *const prcrs_dev = DEVICE_DT_GET(DT_NODELABEL(prcrs)); + +void rzt2m_unlock_prcrn(uint32_t mask) +{ + uint32_t prcrn; + + syscon_read_reg(prcrn_dev, 0, &prcrn); + prcrn |= PRC_KEY_CODE | mask; + + syscon_write_reg(prcrn_dev, 0, prcrn); +} + +void rzt2m_lock_prcrn(uint32_t mask) +{ + uint32_t prcrn; + + syscon_read_reg(prcrn_dev, 0, &prcrn); + prcrn &= ~mask; + prcrn |= PRC_KEY_CODE; + + syscon_write_reg(prcrn_dev, 0, prcrn); +} + +void rzt2m_unlock_prcrs(uint32_t mask) +{ + uint32_t prcrs; + + syscon_read_reg(prcrs_dev, 0, &prcrs); + prcrs |= PRC_KEY_CODE | mask; + + syscon_write_reg(prcrs_dev, 0, prcrs); +} + +void rzt2m_lock_prcrs(uint32_t mask) +{ + uint32_t prcrs; + + syscon_read_reg(prcrs_dev, 0, &prcrs); + prcrs &= ~mask; + prcrs |= PRC_KEY_CODE; + + syscon_write_reg(prcrs_dev, 0, prcrs); +} + +void rzt2m_enable_counters(void) +{ + const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(gsc)); + + syscon_write_reg(dev, 0, CNTCR_EN); +} + +static int rzt2m_init(void) +{ + /* Unlock the Protect Registers + * so that device drivers can access configuration registers of peripherals. + */ + /* After the device drivers are done, lock the Protect Registers. */ + + rzt2m_enable_counters(); + return 0; +} + +SYS_INIT(rzt2m_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/renesas_rzt2m/soc.h b/soc/arm/renesas_rzt2m/soc.h new file mode 100644 index 000000000000000..02bd03b69a1ad30 --- /dev/null +++ b/soc/arm/renesas_rzt2m/soc.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SOC__H_ +#define _SOC__H_ + +/* Do not let CMSIS to handle GIC and Timer */ +#include +#define __GIC_PRESENT 0 +#define __TIM_PRESENT 0 + +/* Global system counter */ +#define CNTCR_EN BIT(0) +#define CNTCR_HDBG BIT(1) + +/* Safety area protect register */ +#define PRCRS_CLK BIT(0) +#define PRCRS_LPC_RESET BIT(1) +#define PRCRS_GPIO BIT(2) +#define PRCRS_SYS_CTRL BIT(3) + +/* Non-safety area protect register */ +#define PRCRN_PRC0 BIT(0) +#define PRCRN_PRC1 BIT(1) +#define PRCRN_PRC2 BIT(2) + +/* PRC Key Code - this value is required to allow any write operation + * to the PRCRS / PRCRN registers. + * See section 10.2 of the RZ/T2M User's Manual: Hardware. + */ +#define PRC_KEY_CODE 0xa500 + +void rzt2m_unlock_prcrn(uint32_t mask); +void rzt2m_lock_prcrn(uint32_t mask); +void rzt2m_unlock_prcrs(uint32_t mask); +void rzt2m_lock_prcrs(uint32_t mask); + +#endif /* _SOC__H_ */ diff --git a/soc/arm/renesas_smartbond/da1469x/CMakeLists.txt b/soc/arm/renesas_smartbond/da1469x/CMakeLists.txt index 094293e9f321fd6..115f3a3402875fe 100644 --- a/soc/arm/renesas_smartbond/da1469x/CMakeLists.txt +++ b/soc/arm/renesas_smartbond/da1469x/CMakeLists.txt @@ -7,3 +7,5 @@ zephyr_linker_sources( ) zephyr_library() zephyr_library_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/renesas_smartbond/da1469x/Kconfig.defconfig.da14695 b/soc/arm/renesas_smartbond/da1469x/Kconfig.defconfig.da14695 new file mode 100644 index 000000000000000..101e275b79f69d6 --- /dev/null +++ b/soc/arm/renesas_smartbond/da1469x/Kconfig.defconfig.da14695 @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Renesas Electronics Corporation and/or its affiliates +# SPDX-License-Identifier: Apache-2.0 + +if SOC_DA14695 + +config SOC + default "da14695" + +endif # SOC_DA14695 diff --git a/soc/arm/renesas_smartbond/da1469x/Kconfig.series b/soc/arm/renesas_smartbond/da1469x/Kconfig.series index a3a9e569460bb66..c3672a9ecaf7533 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/renesas_smartbond/da1469x/Kconfig.soc b/soc/arm/renesas_smartbond/da1469x/Kconfig.soc index edce40398670676..b1e7eddb8500337 100644 --- a/soc/arm/renesas_smartbond/da1469x/Kconfig.soc +++ b/soc/arm/renesas_smartbond/da1469x/Kconfig.soc @@ -1,4 +1,4 @@ -# Copyright (c) 2022 Renesas Electronics Corporation +# Copyright (c) 2022-2023 Renesas Electronics Corporation and/or its affiliates # SPDX-License-Identifier: Apache-2.0 choice @@ -8,4 +8,7 @@ choice config SOC_DA14699 bool "DA14699" +config SOC_DA14695 + bool "DA14695" + endchoice diff --git a/soc/arm/renesas_smartbond/da1469x/linker.ld b/soc/arm/renesas_smartbond/da1469x/linker.ld deleted file mode 100644 index dfa36b95d49ca11..000000000000000 --- a/soc/arm/renesas_smartbond/da1469x/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2022 Renesas Electronics Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/rpi_pico/rp2/CMakeLists.txt b/soc/arm/rpi_pico/rp2/CMakeLists.txt index 210f5623ae9869d..119517e5e1c7dd0 100644 --- a/soc/arm/rpi_pico/rp2/CMakeLists.txt +++ b/soc/arm/rpi_pico/rp2/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_library() zephyr_library_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/rpi_pico/rp2/soc.c b/soc/arm/rpi_pico/rp2/soc.c index d953436f77e3e7f..012f5431283b87a 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 b38d2edf4614623..0eef4cf92a2477e 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 d0bbf68c885e2af..60bda813903d46e 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/CMakeLists.txt b/soc/arm/silabs_exx32/common/CMakeLists.txt index ac965e28d46676e..27e11228b9793f0 100644 --- a/soc/arm/silabs_exx32/common/CMakeLists.txt +++ b/soc/arm/silabs_exx32/common/CMakeLists.txt @@ -6,3 +6,5 @@ zephyr_sources_ifdef(CONFIG_SOC_GECKO_PM_BACKEND_EMU soc_power.c) zephyr_sources_ifdef(CONFIG_SOC_GECKO_PM_BACKEND_PMGR soc_power_pmgr.c) zephyr_include_directories(.) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") 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 new file mode 100644 index 000000000000000..14a59b29612da5a --- /dev/null +++ b/soc/arm/silabs_exx32/common/sl_device_init_hfxo_config.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SL_DEVICE_INIT_HFXO_CONFIG_H +#define SL_DEVICE_INIT_HFXO_CONFIG_H + +#include + +#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/efm32gg11b/linker.ld b/soc/arm/silabs_exx32/efm32gg11b/linker.ld deleted file mode 100644 index 120507fb63f7496..000000000000000 --- a/soc/arm/silabs_exx32/efm32gg11b/linker.ld +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2019 Interay Solutions B.V. - * Copyright (c) 2019 Oane Kingma - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images. - */ - - -#include diff --git a/soc/arm/silabs_exx32/efm32gg12b/linker.ld b/soc/arm/silabs_exx32/efm32gg12b/linker.ld deleted file mode 100644 index f478ff72c40210c..000000000000000 --- a/soc/arm/silabs_exx32/efm32gg12b/linker.ld +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2023 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images. - */ - -#include diff --git a/soc/arm/silabs_exx32/efm32hg/Kconfig.series b/soc/arm/silabs_exx32/efm32hg/Kconfig.series index 33793b5386d8e5f..d17c24fbcdb286a 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/efm32hg/linker.ld b/soc/arm/silabs_exx32/efm32hg/linker.ld deleted file mode 100644 index da96a05932a6892..000000000000000 --- a/soc/arm/silabs_exx32/efm32hg/linker.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2018 Marcio Montenegro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images. - */ - - -#include diff --git a/soc/arm/silabs_exx32/efm32jg12b/linker.ld b/soc/arm/silabs_exx32/efm32jg12b/linker.ld deleted file mode 100644 index cb2bbd2fdf1c7f7..000000000000000 --- a/soc/arm/silabs_exx32/efm32jg12b/linker.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2018 Christian Taedcke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images. - */ - - -#include diff --git a/soc/arm/silabs_exx32/efm32pg12b/linker.ld b/soc/arm/silabs_exx32/efm32pg12b/linker.ld deleted file mode 100644 index cb2bbd2fdf1c7f7..000000000000000 --- a/soc/arm/silabs_exx32/efm32pg12b/linker.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2018 Christian Taedcke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images. - */ - - -#include diff --git a/soc/arm/silabs_exx32/efm32pg1b/linker.ld b/soc/arm/silabs_exx32/efm32pg1b/linker.ld deleted file mode 100644 index cb2bbd2fdf1c7f7..000000000000000 --- a/soc/arm/silabs_exx32/efm32pg1b/linker.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2018 Christian Taedcke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images. - */ - - -#include diff --git a/soc/arm/silabs_exx32/efm32wg/linker.ld b/soc/arm/silabs_exx32/efm32wg/linker.ld deleted file mode 100644 index d877abf5fd4fd72..000000000000000 --- a/soc/arm/silabs_exx32/efm32wg/linker.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2017 Christian Taedcke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images. - */ - - -#include diff --git a/soc/arm/silabs_exx32/efr32bg13p/linker.ld b/soc/arm/silabs_exx32/efr32bg13p/linker.ld deleted file mode 100644 index 09c3e1cf94344fa..000000000000000 --- a/soc/arm/silabs_exx32/efr32bg13p/linker.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2018 Diego Sueiro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images. - */ - - -#include diff --git a/soc/arm/silabs_exx32/efr32bg22/linker.ld b/soc/arm/silabs_exx32/efr32bg22/linker.ld deleted file mode 100644 index 38d9b250c5b0887..000000000000000 --- a/soc/arm/silabs_exx32/efr32bg22/linker.ld +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2021 Sateesh Kotapati - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images. - */ - -#include diff --git a/soc/arm/silabs_exx32/efr32bg27/linker.ld b/soc/arm/silabs_exx32/efr32bg27/linker.ld deleted file mode 100644 index b65086a5ce15406..000000000000000 --- a/soc/arm/silabs_exx32/efr32bg27/linker.ld +++ /dev/null @@ -1,5 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/silabs_exx32/efr32fg13p/linker.ld b/soc/arm/silabs_exx32/efr32fg13p/linker.ld deleted file mode 100644 index cb2bbd2fdf1c7f7..000000000000000 --- a/soc/arm/silabs_exx32/efr32fg13p/linker.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2018 Christian Taedcke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images. - */ - - -#include diff --git a/soc/arm/silabs_exx32/efr32fg1p/linker.ld b/soc/arm/silabs_exx32/efr32fg1p/linker.ld deleted file mode 100644 index cb2bbd2fdf1c7f7..000000000000000 --- a/soc/arm/silabs_exx32/efr32fg1p/linker.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2018 Christian Taedcke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images. - */ - - -#include diff --git a/soc/arm/silabs_exx32/efr32mg12p/Kconfig.defconfig.series b/soc/arm/silabs_exx32/efr32mg12p/Kconfig.defconfig.series index a6881d77861b15c..6f20bfbe57e4547 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 8f2f260730d3065..b171553e638842e 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/efr32mg12p/linker.ld b/soc/arm/silabs_exx32/efr32mg12p/linker.ld deleted file mode 100644 index 09c3e1cf94344fa..000000000000000 --- a/soc/arm/silabs_exx32/efr32mg12p/linker.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2018 Diego Sueiro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images. - */ - - -#include diff --git a/soc/arm/silabs_exx32/efr32mg21/Kconfig.series b/soc/arm/silabs_exx32/efr32mg21/Kconfig.series index 146493469e8c052..731658d29e348b0 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/silabs_exx32/efr32mg21/linker.ld b/soc/arm/silabs_exx32/efr32mg21/linker.ld deleted file mode 100644 index 7295169eae8aa9b..000000000000000 --- a/soc/arm/silabs_exx32/efr32mg21/linker.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2020 TriaGnoSys GmbH - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images. - */ - - -#include diff --git a/soc/arm/silabs_exx32/efr32mg24/linker.ld b/soc/arm/silabs_exx32/efr32mg24/linker.ld deleted file mode 100644 index 0d44f8636131727..000000000000000 --- a/soc/arm/silabs_exx32/efr32mg24/linker.ld +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2021 Sateesh Kotapati - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * This is the linker script for both standard images. - */ - -#include - -#include diff --git a/soc/arm/st_stm32/Kconfig b/soc/arm/st_stm32/Kconfig index c644b50a5ff1653..dcdb22ca26b6d0b 100644 --- a/soc/arm/st_stm32/Kconfig +++ b/soc/arm/st_stm32/Kconfig @@ -6,7 +6,7 @@ config SOC_FAMILY_STM32 bool select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE - select STM32_ENABLE_DEBUG_SLEEP_STOP if DEBUG + select STM32_ENABLE_DEBUG_SLEEP_STOP if DEBUG || ZTEST select BUILD_OUTPUT_HEX if SOC_FAMILY_STM32 diff --git a/soc/arm/st_stm32/common/CMakeLists.txt b/soc/arm/st_stm32/common/CMakeLists.txt index 70dd8c865c9789a..af898951cc5f37a 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 40dda7b6fa06d5a..5b586516d838872 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 07b2122cefd9694..2fd9084cc55ab7f 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 000000000000000..5897670e5f6ec40 --- /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/stm32c0/CMakeLists.txt b/soc/arm/st_stm32/stm32c0/CMakeLists.txt index ac3ba70ace6e704..e02052e39465329 100644 --- a/soc/arm/st_stm32/stm32c0/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32c0/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32c0/linker.ld b/soc/arm/st_stm32/stm32c0/linker.ld deleted file mode 100644 index d5f07ed942a1f0c..000000000000000 --- a/soc/arm/st_stm32/stm32c0/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2023 Benjamin Björnsson - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32f0/CMakeLists.txt b/soc/arm/st_stm32/stm32f0/CMakeLists.txt index 56b5d1ffa8ed141..914e395d27a3924 100644 --- a/soc/arm/st_stm32/stm32f0/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32f0/CMakeLists.txt @@ -8,3 +8,5 @@ zephyr_linker_sources_ifdef(CONFIG_SRAM_VECTOR_TABLE ) zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32f0/linker.ld b/soc/arm/st_stm32/stm32f0/linker.ld deleted file mode 100644 index c39286d86f52ce4..000000000000000 --- a/soc/arm/st_stm32/stm32f0/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014-2016 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32f1/CMakeLists.txt b/soc/arm/st_stm32/stm32f1/CMakeLists.txt index ac3ba70ace6e704..e02052e39465329 100644 --- a/soc/arm/st_stm32/stm32f1/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32f1/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32f1/linker.ld b/soc/arm/st_stm32/stm32f1/linker.ld deleted file mode 100644 index c39286d86f52ce4..000000000000000 --- a/soc/arm/st_stm32/stm32f1/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014-2016 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32f2/CMakeLists.txt b/soc/arm/st_stm32/stm32f2/CMakeLists.txt index ac3ba70ace6e704..e02052e39465329 100644 --- a/soc/arm/st_stm32/stm32f2/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32f2/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32f2/linker.ld b/soc/arm/st_stm32/stm32f2/linker.ld deleted file mode 100644 index b5f5c77d59c2745..000000000000000 --- a/soc/arm/st_stm32/stm32f2/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2018 qianfan Zhao - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32f3/CMakeLists.txt b/soc/arm/st_stm32/stm32f3/CMakeLists.txt index ac3ba70ace6e704..e02052e39465329 100644 --- a/soc/arm/st_stm32/stm32f3/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32f3/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") 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 000000000000000..752bef896908127 --- /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 875ed373a69624a..000000000000000 --- 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 6dde4dfd8cfad13..20af2538ba52720 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/stm32f3/linker.ld b/soc/arm/st_stm32/stm32f3/linker.ld deleted file mode 100644 index c39286d86f52ce4..000000000000000 --- a/soc/arm/st_stm32/stm32f3/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014-2016 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32f4/CMakeLists.txt b/soc/arm/st_stm32/stm32f4/CMakeLists.txt index ac3ba70ace6e704..021708b9d02db1a 100644 --- a/soc/arm/st_stm32/stm32f4/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32f4/CMakeLists.txt @@ -4,3 +4,9 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") + +zephyr_sources_ifdef(CONFIG_PM + power.c + ) diff --git a/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series b/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series index 14dea5bf4d2f850..63725609480192f 100644 --- a/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series @@ -17,4 +17,17 @@ config TASK_WDT_HW_FALLBACK_DELAY depends on TASK_WDT_HW_FALLBACK default 200 +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/stm32f4/Kconfig.series b/soc/arm/st_stm32/stm32f4/Kconfig.series index 6b8fdf80c7ba966..a4e65c97784e5a5 100644 --- a/soc/arm/st_stm32/stm32f4/Kconfig.series +++ b/soc/arm/st_stm32/stm32f4/Kconfig.series @@ -13,5 +13,6 @@ config SOC_SERIES_STM32F4X select HAS_STM32CUBE select CPU_HAS_ARM_MPU select HAS_SWO + select HAS_PM help Enable support for STM32F4 MCU series diff --git a/soc/arm/st_stm32/stm32f4/linker.ld b/soc/arm/st_stm32/stm32f4/linker.ld deleted file mode 100644 index c39286d86f52ce4..000000000000000 --- a/soc/arm/st_stm32/stm32f4/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014-2016 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32f4/power.c b/soc/arm/st_stm32/stm32f4/power.c new file mode 100644 index 000000000000000..02b645ee9f191f8 --- /dev/null +++ b/soc/arm/st_stm32/stm32f4/power.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +BUILD_ASSERT(DT_SAME_NODE(DT_CHOSEN(zephyr_cortex_m_idle_timer), DT_NODELABEL(rtc)), + "STM32Fx series needs RTC as an additional IDLE timer for power management"); + +void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + switch (state) { + case PM_STATE_SUSPEND_TO_IDLE: + LL_LPM_DisableEventOnPend(); + LL_PWR_ClearFlag_WU(); + /* According to datasheet (DS11139 Rev 8,Table 38.), wakeup with regulator in + * low-power mode takes typically 8us, max 13us more time than with the main + * regulator. We are using RTC as a wakeup source, which has a tick 62,5us. + * It means we have to add significant margin to the exit-latency anyway, + * so it is worth always using the low-power regulator. + */ + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_LPREGU); + LL_LPM_EnableDeepSleep(); + + k_cpu_idle(); + + break; + default: + LOG_DBG("Unsupported power state %u", state); + break; + } +} + +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + switch (state) { + case PM_STATE_SUSPEND_TO_IDLE: + LL_LPM_DisableSleepOnExit(); + LL_LPM_EnableSleep(); + + /* Restore the clock setup. */ + stm32_clock_control_init(NULL); + break; + default: + LOG_DBG("Unsupported power substate-id %u", state); + break; + } + + /* + * System is now in active mode. Reenable interrupts which were + * disabled when OS started idling code. + */ + irq_unlock(0); +} + +static int stm32_power_init(void) +{ + /* Enable Power clock. It should by done by default, but make sure to + * enable it for all STM32F4x chips. + */ + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR); + + /* Enabling debug during STOP mode is done by the common STM32 configuration */ + return 0; +} + +SYS_INIT(stm32_power_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/st_stm32/stm32f7/CMakeLists.txt b/soc/arm/st_stm32/stm32f7/CMakeLists.txt index ac3ba70ace6e704..e02052e39465329 100644 --- a/soc/arm/st_stm32/stm32f7/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32f7/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") 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 000000000000000..5b85551f939ad31 --- /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 860aea7e7168dc7..a298fa2b579d945 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 727ed9088137a82..c83a9962a604ccd 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/linker.ld b/soc/arm/st_stm32/stm32f7/linker.ld deleted file mode 100644 index be06b7accb60938..000000000000000 --- a/soc/arm/st_stm32/stm32f7/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2018 Yurii Hamann - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32f7/soc.c b/soc/arm/st_stm32/stm32f7/soc.c index b06a894197aaaf1..4a9cc72a78dc85e 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/CMakeLists.txt b/soc/arm/st_stm32/stm32g0/CMakeLists.txt index aff2873dc18240d..85869a31ddfc6bc 100644 --- a/soc/arm/st_stm32/stm32g0/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32g0/CMakeLists.txt @@ -9,3 +9,5 @@ zephyr_sources( zephyr_sources_ifdef(CONFIG_PM power.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32g0/Kconfig.defconfig.stm32g0b1xx b/soc/arm/st_stm32/stm32g0/Kconfig.defconfig.stm32g0b1xx index 86c47b158e9adfd..767cea2556cd778 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/stm32g0/linker.ld b/soc/arm/st_stm32/stm32g0/linker.ld deleted file mode 100644 index a5c6d669295d79f..000000000000000 --- a/soc/arm/st_stm32/stm32g0/linker.ld +++ /dev/null @@ -1,10 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2019 Philippe Retornaz - * Copyright (c) 2019 STMicroelectronics - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32g4/CMakeLists.txt b/soc/arm/st_stm32/stm32g4/CMakeLists.txt index d924a7b28409dce..04911a6a2e47bd2 100644 --- a/soc/arm/st_stm32/stm32g4/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32g4/CMakeLists.txt @@ -7,3 +7,5 @@ zephyr_sources( zephyr_sources_ifdef(CONFIG_PM power.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32g4/Kconfig.series b/soc/arm/st_stm32/stm32g4/Kconfig.series index 6d81e3f1fc14970..f04432c3ee301b6 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/stm32g4/linker.ld b/soc/arm/st_stm32/stm32g4/linker.ld deleted file mode 100644 index 8053c5cfc116498..000000000000000 --- a/soc/arm/st_stm32/stm32g4/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2019 Richard Osterloh - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32h5/CMakeLists.txt b/soc/arm/st_stm32/stm32h5/CMakeLists.txt index 9cb843e9cafc1de..e02052e39465329 100644 --- a/soc/arm/st_stm32/stm32h5/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32h5/CMakeLists.txt @@ -4,4 +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/linker.ld b/soc/arm/st_stm32/stm32h5/linker.ld deleted file mode 100644 index f20e6999579b3e3..000000000000000 --- a/soc/arm/st_stm32/stm32h5/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2023 STMicroelectronics - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32h5/sections.ld b/soc/arm/st_stm32/stm32h5/sections.ld deleted file mode 100644 index ead1bcd811b6f15..000000000000000 --- 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/CMakeLists.txt b/soc/arm/st_stm32/stm32h7/CMakeLists.txt index 24f6f90e6e445ff..d1ae6c3325da1ea 100644 --- a/soc/arm/st_stm32/stm32h7/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32h7/CMakeLists.txt @@ -7,3 +7,5 @@ zephyr_sources_ifdef(CONFIG_CPU_CORTEX_M4 soc_m4.c) zephyr_sources(mpu_regions.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/stm32h7/Kconfig.defconfig.stm32h7b0xx b/soc/arm/st_stm32/stm32h7/Kconfig.defconfig.stm32h7b0xx new file mode 100644 index 000000000000000..105021350149c89 --- /dev/null +++ b/soc/arm/st_stm32/stm32h7/Kconfig.defconfig.stm32h7b0xx @@ -0,0 +1,15 @@ +# ST STM32H7B0XX MCU configuration options + +# Copyright (c) 2023 Charles Dias +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32H7B0XX || SOC_STM32H7B0XXQ + +config SOC + default "stm32h7b0xxQ" if SOC_STM32H7B0XXQ + default "stm32h7b0xx" if SOC_STM32H7B0XX + +config NUM_IRQS + default 155 + +endif # SOC_STM32H7B0XX || SOC_STM32H7B0XXQ diff --git a/soc/arm/st_stm32/stm32h7/Kconfig.soc b/soc/arm/st_stm32/stm32h7/Kconfig.soc index 46f101f0e1420d2..4f7441a6fdcf562 100644 --- a/soc/arm/st_stm32/stm32h7/Kconfig.soc +++ b/soc/arm/st_stm32/stm32h7/Kconfig.soc @@ -16,71 +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/linker.ld b/soc/arm/st_stm32/stm32h7/linker.ld deleted file mode 100644 index 20713e9bfd3b837..000000000000000 --- a/soc/arm/st_stm32/stm32h7/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2019 Linaro Limited - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32h7/soc_m7.c b/soc/arm/st_stm32/stm32h7/soc_m7.c index 8e72b3ee390c1c8..39c1d917c34942e 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/stm32l0/CMakeLists.txt b/soc/arm/st_stm32/stm32l0/CMakeLists.txt index 59be7817eab8204..0fd5073770d3016 100644 --- a/soc/arm/st_stm32/stm32l0/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32l0/CMakeLists.txt @@ -8,3 +8,5 @@ zephyr_sources( zephyr_sources_ifdef(CONFIG_PM power.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l010x4 b/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l010x4 new file mode 100644 index 000000000000000..779d26245082b2e --- /dev/null +++ b/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l010x4 @@ -0,0 +1,14 @@ +# ST Microelectronics STM32L010XX MCU +# +# Copyright (c) 2023 OS Systems +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32L010X4 + +config SOC + default "stm32l010x4" + +config NUM_IRQS + default 30 + +endif # SOC_STM32L010X4 diff --git a/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l010x6 b/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l010x6 new file mode 100644 index 000000000000000..dd86c005ad8054b --- /dev/null +++ b/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l010x6 @@ -0,0 +1,14 @@ +# ST Microelectronics STM32L010XX MCU +# +# Copyright (c) 2023 OS Systems +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32L010X6 + +config SOC + default "stm32l010x6" + +config NUM_IRQS + default 30 + +endif # SOC_STM32L010X6 diff --git a/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l010x8 b/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l010x8 new file mode 100644 index 000000000000000..20dd0b0c09a83a4 --- /dev/null +++ b/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l010x8 @@ -0,0 +1,14 @@ +# ST Microelectronics STM32L010XX MCU +# +# Copyright (c) 2023 OS Systems +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32L010X8 + +config SOC + default "stm32l010x8" + +config NUM_IRQS + default 30 + +endif # SOC_STM32L010X8 diff --git a/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l010xb b/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l010xb index d447e92f4e09151..89e20292fc1281b 100644 --- a/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l010xb +++ b/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l010xb @@ -9,6 +9,6 @@ config SOC default "stm32l010xb" config NUM_IRQS - default 32 + default 30 endif # SOC_STM32L010XB diff --git a/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l081xx b/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l081xx new file mode 100644 index 000000000000000..f3cc93c38c84f7b --- /dev/null +++ b/soc/arm/st_stm32/stm32l0/Kconfig.defconfig.stm32l081xx @@ -0,0 +1,14 @@ +# ST Microelectronics STM32L081XX MCU + +# Copyright (c) 2023 Caspar Friedrich +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32L081XX + +config SOC + default "stm32l081xx" + +config NUM_IRQS + default 32 + +endif # SOC_STM32L081XX diff --git a/soc/arm/st_stm32/stm32l0/Kconfig.soc b/soc/arm/st_stm32/stm32l0/Kconfig.soc index 42d49fde84e3727..0baab0cf2b981f9 100644 --- a/soc/arm/st_stm32/stm32l0/Kconfig.soc +++ b/soc/arm/st_stm32/stm32l0/Kconfig.soc @@ -2,6 +2,7 @@ # Copyright (c) 2018 Endre Karlson # Copyright (c) 2021 Nomono AS +# Copyright (c) 2023 OS Systems # # SPDX-License-Identifier: Apache-2.0 @@ -9,6 +10,15 @@ choice prompt "STM32L0x MCU Selection" depends on SOC_SERIES_STM32L0X +config SOC_STM32L010X4 + bool "STM32L010X4" + +config SOC_STM32L010X6 + bool "STM32L010X6" + +config SOC_STM32L010X8 + bool "STM32L010X8" + config SOC_STM32L010XB bool "STM32L010XB" @@ -38,4 +48,8 @@ config SOC_STM32L073XX bool "STM32L073XX" select CPU_HAS_ARM_MPU +config SOC_STM32L081XX + bool "STM32L081XX" + select CPU_HAS_ARM_MPU + endchoice diff --git a/soc/arm/st_stm32/stm32l0/linker.ld b/soc/arm/st_stm32/stm32l0/linker.ld deleted file mode 100644 index 31b070c6950f4fa..000000000000000 --- a/soc/arm/st_stm32/stm32l0/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2018 Endre Karlson - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32l1/CMakeLists.txt b/soc/arm/st_stm32/stm32l1/CMakeLists.txt index 844c525200937af..68bf00e81c1eb33 100644 --- a/soc/arm/st_stm32/stm32l1/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32l1/CMakeLists.txt @@ -2,3 +2,5 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32l1/linker.ld b/soc/arm/st_stm32/stm32l1/linker.ld deleted file mode 100644 index 0bbb83d949ba239..000000000000000 --- a/soc/arm/st_stm32/stm32l1/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2019 Linaro Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32l4/CMakeLists.txt b/soc/arm/st_stm32/stm32l4/CMakeLists.txt index 8f4b837538de21f..94edc2622740f65 100644 --- a/soc/arm/st_stm32/stm32l4/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32l4/CMakeLists.txt @@ -10,3 +10,5 @@ zephyr_sources_ifdef(CONFIG_PM ) zephyr_sources_ifdef(CONFIG_POWEROFF poweroff.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32l4/linker.ld b/soc/arm/st_stm32/stm32l4/linker.ld deleted file mode 100644 index c39286d86f52ce4..000000000000000 --- a/soc/arm/st_stm32/stm32l4/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014-2016 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32l5/CMakeLists.txt b/soc/arm/st_stm32/stm32l5/CMakeLists.txt index 59be7817eab8204..0fd5073770d3016 100644 --- a/soc/arm/st_stm32/stm32l5/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32l5/CMakeLists.txt @@ -8,3 +8,5 @@ zephyr_sources( zephyr_sources_ifdef(CONFIG_PM power.c ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32l5/linker.ld b/soc/arm/st_stm32/stm32l5/linker.ld deleted file mode 100644 index 987547b1ee1b359..000000000000000 --- a/soc/arm/st_stm32/stm32l5/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2020 Linaro Limited - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32mp1/CMakeLists.txt b/soc/arm/st_stm32/stm32mp1/CMakeLists.txt index 4a1dfd305037772..7805c0ffbf24f69 100644 --- a/soc/arm/st_stm32/stm32mp1/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32mp1/CMakeLists.txt @@ -6,3 +6,5 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( soc.c ) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32mp1/Kconfig.series b/soc/arm/st_stm32/stm32mp1/Kconfig.series index 0c6580e84cce5cb..c1576a7ee178b7e 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/stm32u5/CMakeLists.txt b/soc/arm/st_stm32/stm32u5/CMakeLists.txt index 8f4b837538de21f..94edc2622740f65 100644 --- a/soc/arm/st_stm32/stm32u5/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32u5/CMakeLists.txt @@ -10,3 +10,5 @@ zephyr_sources_ifdef(CONFIG_PM ) zephyr_sources_ifdef(CONFIG_POWEROFF poweroff.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32u5/Kconfig.defconfig.stm32u5a9xx b/soc/arm/st_stm32/stm32u5/Kconfig.defconfig.stm32u5a9xx new file mode 100644 index 000000000000000..0553382acb1e06e --- /dev/null +++ b/soc/arm/st_stm32/stm32u5/Kconfig.defconfig.stm32u5a9xx @@ -0,0 +1,14 @@ +# STMicroelectronics STM32U5A9XX MCU + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32U5A9XX + +config SOC + default "stm32u5a9xx" + +config NUM_IRQS + default 139 + +endif # SOC_STM32U5A9XX diff --git a/soc/arm/st_stm32/stm32u5/Kconfig.soc b/soc/arm/st_stm32/stm32u5/Kconfig.soc index 8308c64372fe385..ec8c964ad3ee80d 100644 --- a/soc/arm/st_stm32/stm32u5/Kconfig.soc +++ b/soc/arm/st_stm32/stm32u5/Kconfig.soc @@ -2,6 +2,7 @@ # Copyright (c) 2021 Linaro Limited # Copyright (c) 2023 PSICONTROL nv +# Copyright (c) 2023 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 choice @@ -23,4 +24,7 @@ config SOC_STM32U599XX config SOC_STM32U5A5XX bool "STM32U5A5XX" +config SOC_STM32U5A9XX + bool "STM32U5A9XX" + endchoice diff --git a/soc/arm/st_stm32/stm32u5/linker.ld b/soc/arm/st_stm32/stm32u5/linker.ld deleted file mode 100644 index a5b0e37e825ff40..000000000000000 --- a/soc/arm/st_stm32/stm32u5/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2021 Linaro Limited - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32wb/CMakeLists.txt b/soc/arm/st_stm32/stm32wb/CMakeLists.txt index 2b21a72d3268e5e..32ce62ee53071de 100644 --- a/soc/arm/st_stm32/stm32wb/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32wb/CMakeLists.txt @@ -13,3 +13,5 @@ zephyr_sources_ifdef(CONFIG_PM ) zephyr_sources_ifdef(CONFIG_POWEROFF poweroff.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32wb/linker.ld b/soc/arm/st_stm32/stm32wb/linker.ld deleted file mode 100644 index 20713e9bfd3b837..000000000000000 --- a/soc/arm/st_stm32/stm32wb/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2019 Linaro Limited - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32wba/CMakeLists.txt b/soc/arm/st_stm32/stm32wba/CMakeLists.txt index 59be7817eab8204..d26c143f8f6e8b3 100644 --- a/soc/arm/st_stm32/stm32wba/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32wba/CMakeLists.txt @@ -8,3 +8,15 @@ zephyr_sources( 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 e6d57729a09213b..340b62049e85d92 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 000000000000000..ca745f874711c89 --- /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 28edaf07790e110..5cdaaa7e6724aa3 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 6e8586d8f3d14cb..75f48454b1cc2be 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 000000000000000..d7d66b3451490c3 --- /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 000000000000000..6cc224cc60ae547 --- /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 000000000000000..1e890949147908b --- /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 000000000000000..1cf621b89ded095 --- /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 000000000000000..8607cbbafd8dde2 --- /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 000000000000000..45c3f1b378293ab --- /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/linker.ld b/soc/arm/st_stm32/stm32wba/linker.ld deleted file mode 100644 index f20e6999579b3e3..000000000000000 --- a/soc/arm/st_stm32/stm32wba/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2023 STMicroelectronics - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/st_stm32/stm32wba/power.c b/soc/arm/st_stm32/stm32wba/power.c index 018c27ee0b88742..1565c59cfc6ca15 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 9d027af604ff9a7..c3f12078e8de1ea 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 ef41f7adf8a183e..0c337ea9e2205e2 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/st_stm32/stm32wl/CMakeLists.txt b/soc/arm/st_stm32/stm32wl/CMakeLists.txt index 40ff85ccbbee953..af44cc273e1f7ce 100644 --- a/soc/arm/st_stm32/stm32wl/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32wl/CMakeLists.txt @@ -8,3 +8,5 @@ zephyr_sources_ifdef(CONFIG_PM ) zephyr_sources_ifdef(CONFIG_POWEROFF poweroff.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32wl/linker.ld b/soc/arm/st_stm32/stm32wl/linker.ld deleted file mode 100644 index c81df32357e9c05..000000000000000 --- a/soc/arm/st_stm32/stm32wl/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2020 STMicroelectronics - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/ti_k3/am62x_m4/CMakeLists.txt b/soc/arm/ti_k3/am62x_m4/CMakeLists.txt index e8d816988de5c71..bc9b13ea188041d 100644 --- a/soc/arm/ti_k3/am62x_m4/CMakeLists.txt +++ b/soc/arm/ti_k3/am62x_m4/CMakeLists.txt @@ -9,3 +9,5 @@ if(CONFIG_OPENAMP_RSC_TABLE) zephyr_linker_section(NAME .resource_table GROUP ROM_REGION NOINPUT) zephyr_linker_section_configure(SECTION .resource_table KEEP INPUT ".resource_table*") endif() + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/ti_k3/am62x_m4/soc.c b/soc/arm/ti_k3/am62x_m4/soc.c index 1010e045ea59a76..9c86eb09a1d5838 100644 --- a/soc/arm/ti_k3/am62x_m4/soc.c +++ b/soc/arm/ti_k3/am62x_m4/soc.c @@ -70,4 +70,4 @@ static int am62x_m4_init(void) return 0; } -SYS_INIT(am62x_m4_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(am62x_m4_init, EARLY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/ti_k3/am62x_m4/soc.h b/soc/arm/ti_k3/am62x_m4/soc.h index 01ff4b07080cfd1..2fd6537b98408bf 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/CMakeLists.txt b/soc/arm/ti_lm3s6965/CMakeLists.txt index c5f6f41f49ab341..c76906ff5c347e0 100644 --- a/soc/arm/ti_lm3s6965/CMakeLists.txt +++ b/soc/arm/ti_lm3s6965/CMakeLists.txt @@ -12,3 +12,5 @@ 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 "") diff --git a/soc/arm/ti_lm3s6965/linker.ld b/soc/arm/ti_lm3s6965/linker.ld deleted file mode 100644 index 757d858cb690ac3..000000000000000 --- a/soc/arm/ti_lm3s6965/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/ti_lm3s6965/soc.h b/soc/arm/ti_lm3s6965/soc.h index bef939013bac037..3c353b1a79b2e1e 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/CMakeLists.txt b/soc/arm/ti_simplelink/cc13x2_cc26x2/CMakeLists.txt index d2a1748738311e7..bf52a055e3b34ba 100644 --- a/soc/arm/ti_simplelink/cc13x2_cc26x2/CMakeLists.txt +++ b/soc/arm/ti_simplelink/cc13x2_cc26x2/CMakeLists.txt @@ -11,3 +11,5 @@ endif() zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) zephyr_linker_sources_ifdef(CONFIG_HAS_TI_CCFG SECTIONS ccfg.ld) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/linker.ld b/soc/arm/ti_simplelink/cc13x2_cc26x2/linker.ld deleted file mode 100644 index 643b4899397da7c..000000000000000 --- a/soc/arm/ti_simplelink/cc13x2_cc26x2/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file - * - * Copyright (c) 2019 Brett Witherspoon - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/soc.h b/soc/arm/ti_simplelink/cc13x2_cc26x2/soc.h index a1d3504b98679f3..fdc9214732c1b30 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/cc13x2x7_cc26x2x7/CMakeLists.txt b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/CMakeLists.txt index 4a2a41c5a5f2747..4194f4262219a67 100644 --- a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/CMakeLists.txt +++ b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/CMakeLists.txt @@ -9,3 +9,5 @@ zephyr_library_sources_ifdef(CONFIG_PM power.c) zephyr_library_sources_ifdef(CONFIG_PM_DEVICE power.c) zephyr_linker_sources_ifdef(CONFIG_HAS_TI_CCFG SECTIONS ccfg.ld) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.soc b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.soc index 74fae9acafd0eee..96bd6cfce941886 100644 --- a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.soc +++ b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.soc @@ -65,4 +65,11 @@ config CC13X2_CC26X2_BOOTLOADER_BACKDOOR_LEVEL help Set the active level of the pin selected for the bootloader backdoor. +config CC13X2_CC26X2_XOSC_CAPARRAY_DELTA + hex "Cap array tuning delta" + range 0 0xFF + default 0xD5 + help + Enable a specific cap array tunning delta. + endmenu diff --git a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/ccfg.c b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/ccfg.c index 74f34acac0d5788..de7b81c32bfbd8c 100644 --- a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/ccfg.c +++ b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/ccfg.c @@ -28,7 +28,7 @@ * https://software-dl.ti.com/simplelink/esd/simplelink_cc13xx_cc26xx_sdk/6.20.00.29/exports/release_notes_simplelink_cc13xx_cc26xx_sdk_6_20_00_29.html#known-issues */ #define SET_CCFG_MODE_CONF_XOSC_CAP_MOD 0x0 -#define SET_CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA 0xD5 +#define SET_CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA CONFIG_CC13X2_CC26X2_XOSC_CAPARRAY_DELTA #endif /* TI recommends setting CCFG values and then including the TI provided ccfg.c */ diff --git a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/linker.ld b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/linker.ld deleted file mode 100644 index 772be96ca3baf4e..000000000000000 --- a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* linker.ld - Linker command/script file - * - * Copyright (c) 2022 Vaishnav Achath - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/ti_simplelink/cc32xx/CMakeLists.txt b/soc/arm/ti_simplelink/cc32xx/CMakeLists.txt index cc11ff419540aa6..9d704214718a118 100644 --- a/soc/arm/ti_simplelink/cc32xx/CMakeLists.txt +++ b/soc/arm/ti_simplelink/cc32xx/CMakeLists.txt @@ -6,3 +6,5 @@ zephyr_include_directories(.) if (DEFINED CONFIG_CC3220SF_DEBUG OR DEFINED CONFIG_CC3235SF_DEBUG) zephyr_linker_sources(ROM_START SORT_KEY 0 cc32xx_debug.ld) endif() + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3220sf b/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3220sf index e082df05a80d295..461802f2155ad4d 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 86c881a40f9acc7..37852a154a015b8 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/linker.ld b/soc/arm/ti_simplelink/cc32xx/linker.ld deleted file mode 100644 index 812d6f503317d1d..000000000000000 --- a/soc/arm/ti_simplelink/cc32xx/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ - -/* - * SPDX-License-Identifier: Apache-2.0 - * linker.ld - Linker command/script file - */ - -#include diff --git a/soc/arm/ti_simplelink/cc32xx/soc.h b/soc/arm/ti_simplelink/cc32xx/soc.h index 9c841e0e4b0c7ab..e18dfce626ae4c9 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/CMakeLists.txt b/soc/arm/ti_simplelink/msp432p4xx/CMakeLists.txt index 363109a38533c05..d93f837e79ec9d5 100644 --- a/soc/arm/ti_simplelink/msp432p4xx/CMakeLists.txt +++ b/soc/arm/ti_simplelink/msp432p4xx/CMakeLists.txt @@ -2,3 +2,5 @@ zephyr_compile_definitions(-D__MSP432P401R__) zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/ti_simplelink/msp432p4xx/Kconfig.series b/soc/arm/ti_simplelink/msp432p4xx/Kconfig.series index 6bb0043ff900cde..8af48672ed23be4 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/ti_simplelink/msp432p4xx/linker.ld b/soc/arm/ti_simplelink/msp432p4xx/linker.ld deleted file mode 100644 index 812d6f503317d1d..000000000000000 --- a/soc/arm/ti_simplelink/msp432p4xx/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ - -/* - * SPDX-License-Identifier: Apache-2.0 - * linker.ld - Linker command/script file - */ - -#include diff --git a/soc/arm/xilinx_zynq7000/xc7zxxx/CMakeLists.txt b/soc/arm/xilinx_zynq7000/xc7zxxx/CMakeLists.txt index 98057786d371c5f..d47bcfb128fe16e 100644 --- a/soc/arm/xilinx_zynq7000/xc7zxxx/CMakeLists.txt +++ b/soc/arm/xilinx_zynq7000/xc7zxxx/CMakeLists.txt @@ -4,3 +4,5 @@ # zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/xilinx_zynq7000/xc7zxxx/linker.ld b/soc/arm/xilinx_zynq7000/xc7zxxx/linker.ld deleted file mode 100644 index 00ffe9ceff3ad71..000000000000000 --- a/soc/arm/xilinx_zynq7000/xc7zxxx/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2021 Weidmueller Interface GmbH & Co. KG - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/xilinx_zynq7000/xc7zxxxs/CMakeLists.txt b/soc/arm/xilinx_zynq7000/xc7zxxxs/CMakeLists.txt index 98057786d371c5f..d47bcfb128fe16e 100644 --- a/soc/arm/xilinx_zynq7000/xc7zxxxs/CMakeLists.txt +++ b/soc/arm/xilinx_zynq7000/xc7zxxxs/CMakeLists.txt @@ -4,3 +4,5 @@ # zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/xilinx_zynq7000/xc7zxxxs/linker.ld b/soc/arm/xilinx_zynq7000/xc7zxxxs/linker.ld deleted file mode 100644 index 00ffe9ceff3ad71..000000000000000 --- a/soc/arm/xilinx_zynq7000/xc7zxxxs/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2021 Weidmueller Interface GmbH & Co. KG - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/xilinx_zynqmp/CMakeLists.txt b/soc/arm/xilinx_zynqmp/CMakeLists.txt index e6654d03cb76c77..65bf778779bc2a3 100644 --- a/soc/arm/xilinx_zynqmp/CMakeLists.txt +++ b/soc/arm/xilinx_zynqmp/CMakeLists.txt @@ -9,3 +9,7 @@ zephyr_sources_ifdef( CONFIG_ARM_MPU arm_mpu_regions.c ) + +if(CONFIG_SOC_XILINX_ZYNQMP_RPU) + set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld CACHE INTERNAL "") +endif() diff --git a/soc/arm/xilinx_zynqmp/linker.ld b/soc/arm/xilinx_zynqmp/linker.ld deleted file mode 100644 index 4f22c8618cf507b..000000000000000 --- a/soc/arm/xilinx_zynqmp/linker.ld +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2019 Lexmark International, Inc. - * Copyright (c) 2019 Stephanos Ioannidis - * - * SPDX-License-Identifier: Apache-2.0 - */ - - -#if defined(CONFIG_SOC_XILINX_ZYNQMP_RPU) -#include -#endif diff --git a/soc/arm/xilinx_zynqmp/pinctrl_soc.h b/soc/arm/xilinx_zynqmp/pinctrl_soc.h new file mode 100644 index 000000000000000..90b6d2acac34769 --- /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/arm/fvp_aemv8a/CMakeLists.txt b/soc/arm64/arm/fvp_aemv8a/CMakeLists.txt index fd39809a833866c..b28d8b24523e3d0 100644 --- a/soc/arm64/arm/fvp_aemv8a/CMakeLists.txt +++ b/soc/arm64/arm/fvp_aemv8a/CMakeLists.txt @@ -2,3 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_library_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/arm/fvp_aemv8a/linker.ld b/soc/arm64/arm/fvp_aemv8a/linker.ld deleted file mode 100644 index ab1d76f36bac6d9..000000000000000 --- a/soc/arm64/arm/fvp_aemv8a/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* - * linker.ld - Linker command/script file - * - * Copyright (c) 2021 Carlo Caione - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm64/arm/fvp_aemv8r/CMakeLists.txt b/soc/arm64/arm/fvp_aemv8r/CMakeLists.txt index cf23f50c5d071b3..ce116cb936eb41e 100644 --- a/soc/arm64/arm/fvp_aemv8r/CMakeLists.txt +++ b/soc/arm64/arm/fvp_aemv8r/CMakeLists.txt @@ -5,3 +5,5 @@ zephyr_library_sources( ) zephyr_library_sources_ifdef(CONFIG_ARM_MPU arm_mpu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/arm/fvp_aemv8r/linker.ld b/soc/arm64/arm/fvp_aemv8r/linker.ld deleted file mode 100644 index afed4f40d25c26b..000000000000000 --- a/soc/arm64/arm/fvp_aemv8r/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* - * linker.ld - Linker command/script file - * - * Copyright (c) 2021 Arm Limited (or its affiliates). All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm64/bcm2711/CMakeLists.txt b/soc/arm64/bcm2711/CMakeLists.txt index fb2dcd9c15f411e..733abbebd911a3a 100644 --- a/soc/arm64/bcm2711/CMakeLists.txt +++ b/soc/arm64/bcm2711/CMakeLists.txt @@ -1,2 +1,4 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/bcm2711/linker.ld b/soc/arm64/bcm2711/linker.ld deleted file mode 100644 index fb3fabcecfe0ce2..000000000000000 --- a/soc/arm64/bcm2711/linker.ld +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright 2023 honglin leng - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include diff --git a/soc/arm64/bcm2711/linker_a72.ld b/soc/arm64/bcm2711/linker_a72.ld deleted file mode 100644 index 6f187219b29c210..000000000000000 --- a/soc/arm64/bcm2711/linker_a72.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright 2023 honglin leng - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm64/bcm_vk/viper/CMakeLists.txt b/soc/arm64/bcm_vk/viper/CMakeLists.txt index 8b59f41d728529c..93f8b45bc82dce0 100644 --- a/soc/arm64/bcm_vk/viper/CMakeLists.txt +++ b/soc/arm64/bcm_vk/viper/CMakeLists.txt @@ -7,3 +7,5 @@ zephyr_sources( zephyr_sources_ifdef(CONFIG_SOC_BCM58402_A72 plat_core.c) zephyr_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/bcm_vk/viper/linker.ld b/soc/arm64/bcm_vk/viper/linker.ld deleted file mode 100644 index 223bd37f5c56831..000000000000000 --- a/soc/arm64/bcm_vk/viper/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2020 Broadcom - * - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include diff --git a/soc/arm64/bcm_vk/viper/linker_a72.ld b/soc/arm64/bcm_vk/viper/linker_a72.ld deleted file mode 100644 index a12c2bd066b17bf..000000000000000 --- a/soc/arm64/bcm_vk/viper/linker_a72.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright 2020 Broadcom - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm64/intel_socfpga/agilex/CMakeLists.txt b/soc/arm64/intel_socfpga/agilex/CMakeLists.txt index ba3d3c4e03425e8..3cdb01da699a0e0 100644 --- a/soc/arm64/intel_socfpga/agilex/CMakeLists.txt +++ b/soc/arm64/intel_socfpga/agilex/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_include_directories(.) zephyr_library_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/intel_socfpga/agilex/linker.ld b/soc/arm64/intel_socfpga/agilex/linker.ld deleted file mode 100644 index 2b4cd596a17bb5a..000000000000000 --- a/soc/arm64/intel_socfpga/agilex/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright (c) 2020 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - * - */ - -#include diff --git a/soc/arm64/intel_socfpga/agilex5/CMakeLists.txt b/soc/arm64/intel_socfpga/agilex5/CMakeLists.txt index f0e79e927d3aa4f..a538caf7a335bd4 100644 --- a/soc/arm64/intel_socfpga/agilex5/CMakeLists.txt +++ b/soc/arm64/intel_socfpga/agilex5/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_include_directories(.) zephyr_library_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/intel_socfpga/agilex5/linker.ld b/soc/arm64/intel_socfpga/agilex5/linker.ld deleted file mode 100644 index 9f5bc4c4f7e0713..000000000000000 --- a/soc/arm64/intel_socfpga/agilex5/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright (c) 2022 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - * - */ - -#include diff --git a/soc/arm64/intel_socfpga/common/socfpga_system_manager.h b/soc/arm64/intel_socfpga/common/socfpga_system_manager.h index 4e56ee5af4f72c0..58f9e0d2c5654c0 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/CMakeLists.txt b/soc/arm64/nxp_imx/mimx8m/CMakeLists.txt index ff4a4e0deba1a75..032c4a8642d4d0e 100644 --- a/soc/arm64/nxp_imx/mimx8m/CMakeLists.txt +++ b/soc/arm64/nxp_imx/mimx8m/CMakeLists.txt @@ -3,3 +3,5 @@ zephyr_include_directories(.) zephyr_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mm b/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mm index a35ff4951ef2c68..a77d9f837dff8ff 100644 --- a/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mm +++ b/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mm @@ -1,10 +1,10 @@ -# Copyright 2020-2022 NXP +# Copyright 2020-2023 NXP # SPDX-License-Identifier: Apache-2.0 if SOC_MIMX8MM_A53 config SOC - default "mimx8mm6" + default "mimx8mm6_ca53" # Workaround for not being able to have commas in macro arguments DT_CHOSEN_Z_FLASH := zephyr,flash diff --git a/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mn b/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mn index 9c5e7bfe04128ee..c6c2837d74de185 100644 --- a/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mn +++ b/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mn @@ -1,10 +1,10 @@ -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # SPDX-License-Identifier: Apache-2.0 if SOC_MIMX8MN_A53 config SOC - default "mimx8mn6" + default "mimx8mn6_ca53" # Workaround for not being able to have commas in macro arguments DT_CHOSEN_Z_FLASH := zephyr,flash diff --git a/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mp b/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mp index 5a99f354e5d4a7a..ebdfa764a699172 100644 --- a/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mp +++ b/soc/arm64/nxp_imx/mimx8m/Kconfig.defconfig.mimx8mp @@ -1,10 +1,10 @@ -# Copyright 2021-2022 NXP +# Copyright 2021-2023 NXP # SPDX-License-Identifier: Apache-2.0 if SOC_MIMX8MP_A53 config SOC - default "mimx8ml8" + default "mimx8ml8_ca53" # Workaround for not being able to have commas in macro arguments DT_CHOSEN_Z_FLASH := zephyr,flash diff --git a/soc/arm64/nxp_imx/mimx8m/linker.ld b/soc/arm64/nxp_imx/mimx8m/linker.ld deleted file mode 100644 index 65c5d0722aa2654..000000000000000 --- a/soc/arm64/nxp_imx/mimx8m/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2020 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include diff --git a/soc/arm64/nxp_imx/mimx8m/mmu_regions.c b/soc/arm64/nxp_imx/mimx8m/mmu_regions.c index 4add4386ef5847b..e6dd90ecc280406 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/CMakeLists.txt b/soc/arm64/nxp_imx/mimx9/CMakeLists.txt index ff4a4e0deba1a75..77a9500f5b7cf47 100644 --- a/soc/arm64/nxp_imx/mimx9/CMakeLists.txt +++ b/soc/arm64/nxp_imx/mimx9/CMakeLists.txt @@ -3,3 +3,5 @@ zephyr_include_directories(.) zephyr_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/nxp_imx/mimx9/Kconfig.defconfig.mimx93 b/soc/arm64/nxp_imx/mimx9/Kconfig.defconfig.mimx93 index 5927717506377dd..45e67de35eda52f 100644 --- a/soc/arm64/nxp_imx/mimx9/Kconfig.defconfig.mimx93 +++ b/soc/arm64/nxp_imx/mimx9/Kconfig.defconfig.mimx93 @@ -1,10 +1,10 @@ -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # SPDX-License-Identifier: Apache-2.0 if SOC_MIMX93_A55 config SOC - default "mimx9352" + default "mimx9352_ca55" # Workaround for not being able to have commas in macro arguments DT_CHOSEN_Z_FLASH := zephyr,flash diff --git a/soc/arm64/nxp_imx/mimx9/Kconfig.soc b/soc/arm64/nxp_imx/mimx9/Kconfig.soc index 01ba98968744ea7..3f38d40131fd15c 100644 --- a/soc/arm64/nxp_imx/mimx9/Kconfig.soc +++ b/soc/arm64/nxp_imx/mimx9/Kconfig.soc @@ -11,7 +11,7 @@ config SOC_MIMX93_A55 select CPU_CORTEX_A55 select ARM_ARCH_TIMER if SYS_CLOCK_EXISTS select HAS_MCUX if CLOCK_CONTROL - select HAS_MCUX_CCM if CLOCK_CONTROL + select HAS_MCUX_CCM_REV2 if CLOCK_CONTROL select HAS_MCUX_IOMUXC if PINCTRL endchoice diff --git a/soc/arm64/nxp_imx/mimx9/mmu_regions.c b/soc/arm64/nxp_imx/mimx9/mmu_regions.c index fb53c54e7f38f77..4305d8ff7e23e9f 100644 --- a/soc/arm64/nxp_imx/mimx9/mmu_regions.c +++ b/soc/arm64/nxp_imx/mimx9/mmu_regions.c @@ -30,37 +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("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 c3c66d532ec38c2..bd9496ec582bf99 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/nxp_layerscape/ls1046a/CMakeLists.txt b/soc/arm64/nxp_layerscape/ls1046a/CMakeLists.txt index 2cf9a407f84e019..22fc2aa11bee468 100644 --- a/soc/arm64/nxp_layerscape/ls1046a/CMakeLists.txt +++ b/soc/arm64/nxp_layerscape/ls1046a/CMakeLists.txt @@ -1,3 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/nxp_layerscape/ls1046a/linker.ld b/soc/arm64/nxp_layerscape/ls1046a/linker.ld deleted file mode 100644 index 40dbcd63fca75db..000000000000000 --- a/soc/arm64/nxp_layerscape/ls1046a/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2021 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include diff --git a/soc/arm64/qemu_cortex_a53/CMakeLists.txt b/soc/arm64/qemu_cortex_a53/CMakeLists.txt index fd39809a833866c..b28d8b24523e3d0 100644 --- a/soc/arm64/qemu_cortex_a53/CMakeLists.txt +++ b/soc/arm64/qemu_cortex_a53/CMakeLists.txt @@ -2,3 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_library_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/qemu_cortex_a53/linker.ld b/soc/arm64/qemu_cortex_a53/linker.ld deleted file mode 100644 index 9b7be757e17fc7d..000000000000000 --- a/soc/arm64/qemu_cortex_a53/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright (c) 2019 Carlo Caione - * - * SPDX-License-Identifier: Apache-2.0 - * - */ - -#include diff --git a/soc/arm64/qemu_virt_arm64/CMakeLists.txt b/soc/arm64/qemu_virt_arm64/CMakeLists.txt index 495a3d96b89d593..7c7a3c4d52c40f6 100644 --- a/soc/arm64/qemu_virt_arm64/CMakeLists.txt +++ b/soc/arm64/qemu_virt_arm64/CMakeLists.txt @@ -2,3 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_library_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/qemu_virt_arm64/linker.ld b/soc/arm64/qemu_virt_arm64/linker.ld deleted file mode 100644 index a7bcbf24cfb18a2..000000000000000 --- a/soc/arm64/qemu_virt_arm64/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright (c) 2022 Huawei France Technologies SAS - * - * SPDX-License-Identifier: Apache-2.0 - * - */ - -#include diff --git a/soc/arm64/renesas_rcar/gen3/CMakeLists.txt b/soc/arm64/renesas_rcar/gen3/CMakeLists.txt index 23315289c610529..16dcc07b754a49e 100644 --- a/soc/arm64/renesas_rcar/gen3/CMakeLists.txt +++ b/soc/arm64/renesas_rcar/gen3/CMakeLists.txt @@ -4,3 +4,5 @@ zephyr_library_sources_ifdef(CONFIG_SOC_ARM64_R8A77951 pfc_r8a77951.c) zephyr_library_sources_ifdef(CONFIG_SOC_R8A77961 pfc_r8a77961.c) zephyr_library_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/renesas_rcar/gen3/linker.ld b/soc/arm64/renesas_rcar/gen3/linker.ld deleted file mode 100644 index 0deb8cd27942cbb..000000000000000 --- a/soc/arm64/renesas_rcar/gen3/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2023 EPAM Systems - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c b/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c index c59be6cfe6fdf4f..2d5c02316efcedc 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 c130dd510a83406..b219e626e440fd5 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 92f7aa507a44f37..0b80eb466342367 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/arm64/rockchip/Kconfig b/soc/arm64/rockchip/Kconfig index 668d1e9785a4291..e0b4b937c79a81e 100644 --- a/soc/arm64/rockchip/Kconfig +++ b/soc/arm64/rockchip/Kconfig @@ -17,5 +17,6 @@ source "soc/arm64/rockchip/*/Kconfig.soc" config SOC_PART_NUMBER default "RK3399" if SOC_SERIES_RK3399 + default "RK3568" if SOC_SERIES_RK3568 endif # SOC_FAMILY_ROCKCHIP diff --git a/soc/arm64/rockchip/rk3399/CMakeLists.txt b/soc/arm64/rockchip/rk3399/CMakeLists.txt index 2cf9a407f84e019..22fc2aa11bee468 100644 --- a/soc/arm64/rockchip/rk3399/CMakeLists.txt +++ b/soc/arm64/rockchip/rk3399/CMakeLists.txt @@ -1,3 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/rockchip/rk3399/linker.ld b/soc/arm64/rockchip/rk3399/linker.ld deleted file mode 100644 index 1826843d11779af..000000000000000 --- a/soc/arm64/rockchip/rk3399/linker.ld +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2022 Huawei France Technologies SASU - * - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include diff --git a/soc/arm64/rockchip/rk3568/CMakeLists.txt b/soc/arm64/rockchip/rk3568/CMakeLists.txt new file mode 100644 index 000000000000000..2cf9a407f84e019 --- /dev/null +++ b/soc/arm64/rockchip/rk3568/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) diff --git a/soc/arm64/rockchip/rk3568/Kconfig.defconfig.rk3568 b/soc/arm64/rockchip/rk3568/Kconfig.defconfig.rk3568 new file mode 100644 index 000000000000000..13dca55c6e9eca4 --- /dev/null +++ b/soc/arm64/rockchip/rk3568/Kconfig.defconfig.rk3568 @@ -0,0 +1,24 @@ +# Copyright 2022 HNU-ESNL +# Copyright 2022 openEuler SIG-Zephyr +# SPDX-License-Identifier: Apache-2.0 + +if SOC_RK3568 + +config SOC + default "rk3568" + +config FLASH_SIZE + default 0 + +config FLASH_BASE_ADDRESS + default 0 + +config NUM_IRQS + int + default 240 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + int + default 24000000 + +endif diff --git a/soc/arm64/rockchip/rk3568/Kconfig.defconfig.series b/soc/arm64/rockchip/rk3568/Kconfig.defconfig.series new file mode 100644 index 000000000000000..96279038e4a197f --- /dev/null +++ b/soc/arm64/rockchip/rk3568/Kconfig.defconfig.series @@ -0,0 +1,12 @@ +# Copyright 2022 HNU-ESNL +# Copyright 2022 openEuler SIG-Zephyr +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_RK3568 + +config SOC_SERIES + default "rk3568" + +source "soc/arm64/rockchip/rk3568/Kconfig.defconfig.rk3568" + +endif # SOC_SERIES_RK3568 diff --git a/soc/arm64/rockchip/rk3568/Kconfig.series b/soc/arm64/rockchip/rk3568/Kconfig.series new file mode 100644 index 000000000000000..15909e5bff01892 --- /dev/null +++ b/soc/arm64/rockchip/rk3568/Kconfig.series @@ -0,0 +1,10 @@ +# Copyright 2022 HNU-ESNL +# Copyright 2022 openEuler SIG-Zephyrs +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_RK3568 + bool "Rockchip RK3568 Series" + select ARM64 + select SOC_FAMILY_ROCKCHIP + help + Enable support for RK3568 Series. diff --git a/soc/arm64/rockchip/rk3568/Kconfig.soc b/soc/arm64/rockchip/rk3568/Kconfig.soc new file mode 100644 index 000000000000000..7bb2be41909c990 --- /dev/null +++ b/soc/arm64/rockchip/rk3568/Kconfig.soc @@ -0,0 +1,16 @@ +# Copyright 2022 HNU-ESNL +# Copyright 2022 openEuler SIG-Zephyr +# SPDX-License-Identifier: Apache-2.0 + +choice +prompt "Rockchip RK3568 SoC" +depends on SOC_SERIES_RK3568 + +config SOC_RK3568 + bool "Rockchip rk3568" + select ARM64 + select CPU_CORTEX_A55 + select ARM_ARCH_TIMER + select GIC_V3 + +endchoice diff --git a/soc/arm64/rockchip/rk3568/linker.ld b/soc/arm64/rockchip/rk3568/linker.ld new file mode 100644 index 000000000000000..f1b07809e1f7d83 --- /dev/null +++ b/soc/arm64/rockchip/rk3568/linker.ld @@ -0,0 +1,7 @@ +/* + * Copyright 2020 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/soc/arm64/rockchip/rk3568/mmu_regions.c b/soc/arm64/rockchip/rk3568/mmu_regions.c new file mode 100644 index 000000000000000..73b615cab80c359 --- /dev/null +++ b/soc/arm64/rockchip/rk3568/mmu_regions.c @@ -0,0 +1,29 @@ +/* + * Copyright 2020 NXP + * Copyright 2022 HNU-ESNL + * Copyright 2022 openEuler SIG-Zephyr + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +static const struct arm_mmu_region mmu_regions[] = { + + MMU_REGION_FLAT_ENTRY("GIC", + DT_REG_ADDR_BY_IDX(DT_NODELABEL(gic), 0), + DT_REG_SIZE_BY_IDX(DT_NODELABEL(gic), 0), + MT_DEVICE_nGnRnE | MT_P_RW_U_RW | MT_NS), + + MMU_REGION_FLAT_ENTRY("GIC", + DT_REG_ADDR_BY_IDX(DT_NODELABEL(gic), 1), + DT_REG_SIZE_BY_IDX(DT_NODELABEL(gic), 1), + MT_DEVICE_nGnRnE | MT_P_RW_U_RW | MT_NS), + +}; + +const struct arm_mmu_config mmu_config = { + .num_regions = ARRAY_SIZE(mmu_regions), + .mmu_regions = mmu_regions, +}; diff --git a/soc/arm64/ti_k3/am6x/CMakeLists.txt b/soc/arm64/ti_k3/am6x/CMakeLists.txt index 6c961dd280116d3..491cafbec22ff26 100644 --- a/soc/arm64/ti_k3/am6x/CMakeLists.txt +++ b/soc/arm64/ti_k3/am6x/CMakeLists.txt @@ -2,3 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/ti_k3/am6x/linker.ld b/soc/arm64/ti_k3/am6x/linker.ld deleted file mode 100644 index 849a1199eb45568..000000000000000 --- a/soc/arm64/ti_k3/am6x/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2023 Enphase Energy - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm64/xenvm/CMakeLists.txt b/soc/arm64/xenvm/CMakeLists.txt index ac596106c283cf4..7ffbb965792a3d1 100644 --- a/soc/arm64/xenvm/CMakeLists.txt +++ b/soc/arm64/xenvm/CMakeLists.txt @@ -1,3 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_library_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm64/xenvm/linker.ld b/soc/arm64/xenvm/linker.ld deleted file mode 100644 index 6f57b480eb8d367..000000000000000 --- a/soc/arm64/xenvm/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright 2020 EPAM Systems - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/mips/qemu_malta/CMakeLists.txt b/soc/mips/qemu_malta/CMakeLists.txt index 49a74924cdc19f6..351ffebf5b5123c 100644 --- a/soc/mips/qemu_malta/CMakeLists.txt +++ b/soc/mips/qemu_malta/CMakeLists.txt @@ -15,3 +15,5 @@ zephyr_ld_options( -mips32 ${TOOLCHAIN_LD_FLAGS} ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/mips/linker.ld CACHE INTERNAL "") diff --git a/soc/mips/qemu_malta/linker.ld b/soc/mips/qemu_malta/linker.ld deleted file mode 100644 index f6baabc0aa6a9a5..000000000000000 --- a/soc/mips/qemu_malta/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2020 Antony Pavlov - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/nios2/nios2-qemu/CMakeLists.txt b/soc/nios2/nios2-qemu/CMakeLists.txt index 1097b991ed2c04f..b6dd454d035ebf0 100644 --- a/soc/nios2/nios2-qemu/CMakeLists.txt +++ b/soc/nios2/nios2-qemu/CMakeLists.txt @@ -1,3 +1,4 @@ # SPDX-License-Identifier: Apache-2.0 -# intentionally left empty +zephyr_include_directories(include) +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/nios2/nios2f-zephyr/CMakeLists.txt b/soc/nios2/nios2f-zephyr/CMakeLists.txt index 1097b991ed2c04f..789c4c81fc98ec3 100644 --- a/soc/nios2/nios2f-zephyr/CMakeLists.txt +++ b/soc/nios2/nios2f-zephyr/CMakeLists.txt @@ -1,3 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# intentionally left empty +zephyr_include_directories(include) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/posix/inf_clock/CMakeLists.txt b/soc/posix/inf_clock/CMakeLists.txt index b256d67daa98546..5bc6ab3c428c6dd 100644 --- a/soc/posix/inf_clock/CMakeLists.txt +++ b/soc/posix/inf_clock/CMakeLists.txt @@ -13,3 +13,5 @@ zephyr_library_include_directories( ${ZEPHYR_BASE}/kernel/include ${ZEPHYR_BASE}/arch/posix/include ) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/posix/linker.ld CACHE INTERNAL "") diff --git a/soc/posix/inf_clock/Kconfig b/soc/posix/inf_clock/Kconfig index 9e5f5ccc89f7d01..27a5d511ec5bee1 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/linker.ld b/soc/posix/inf_clock/linker.ld deleted file mode 100644 index e33a35202396f5e..000000000000000 --- a/soc/posix/inf_clock/linker.ld +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2017 Oticon A/S - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @brief Linker script for the POSIX ARCH & INF_CLOCK SOC - */ - -#include diff --git a/soc/posix/inf_clock/posix_board_if.h b/soc/posix/inf_clock/posix_board_if.h index 1d851fb3935c177..49384530e14e41c 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 cb6fded1ccd3274..3cb5e310ee1c953 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 b826da926caf128..79d115704b2943c 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 000000000000000..69b2926358e5cf8 --- /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 000000000000000..f3c78ab7f813c6b --- /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 000000000000000..6213f28d2cb38e7 --- /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 000000000000000..9efb478193444cc --- /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 000000000000000..b8eac026dfbb4eb --- /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 5d652057a38b7ce..fee73684b7150c2 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 000000000000000..7b9bbc3eadbbc0b --- /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 000000000000000..c2e9b40bfb7f5b8 --- /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 000000000000000..1731cc08f51c98f --- /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 69e8d00b9473bf6..83a048ca8965428 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 000000000000000..041d0aad530710c --- /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 000000000000000..f057cd8804fccf0 --- /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 84e0d91cb91bf67..9f0ac85caa35d97 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 000000000000000..91ef5c975b919aa --- /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 000000000000000..91f2c5cf80a4346 --- /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 000000000000000..80be64cf2a976db --- /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 000000000000000..10c2e37712bbcee --- /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/common/riscv-privileged/soc_common_irq.c b/soc/riscv/common/riscv-privileged/soc_common_irq.c new file mode 100644 index 000000000000000..24aee37bdafacec --- /dev/null +++ b/soc/riscv/common/riscv-privileged/soc_common_irq.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief interrupt management code for riscv SOCs supporting the riscv + privileged architecture specification + */ +#include +#include + +#include +#include + +#if defined(CONFIG_RISCV_HAS_CLIC) + +void arch_irq_enable(unsigned int irq) +{ + riscv_clic_irq_enable(irq); +} + +void arch_irq_disable(unsigned int irq) +{ + riscv_clic_irq_disable(irq); +} + +int arch_irq_is_enabled(unsigned int irq) +{ + return riscv_clic_irq_is_enabled(irq); +} + +void z_riscv_irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags) +{ + riscv_clic_irq_priority_set(irq, prio, flags); +} + +#else /* PLIC + HLINT/CLINT or HLINT/CLINT only */ + +void arch_irq_enable(unsigned int irq) +{ + uint32_t mie; + +#if defined(CONFIG_RISCV_HAS_PLIC) + unsigned int level = irq_get_level(irq); + + if (level == 2) { + riscv_plic_irq_enable(irq); + return; + } +#endif + + /* + * CSR mie register is updated using atomic instruction csrrs + * (atomic read and set bits in CSR register) + */ + mie = csr_read_set(mie, 1 << irq); +} + +void arch_irq_disable(unsigned int irq) +{ + uint32_t mie; + +#if defined(CONFIG_RISCV_HAS_PLIC) + unsigned int level = irq_get_level(irq); + + if (level == 2) { + riscv_plic_irq_disable(irq); + return; + } +#endif + + /* + * Use atomic instruction csrrc to disable device interrupt in mie CSR. + * (atomic read and clear bits in CSR register) + */ + mie = csr_read_clear(mie, 1 << irq); +} + +int arch_irq_is_enabled(unsigned int irq) +{ + uint32_t mie; + +#if defined(CONFIG_RISCV_HAS_PLIC) + unsigned int level = irq_get_level(irq); + + if (level == 2) { + return riscv_plic_irq_is_enabled(irq); + } +#endif + + mie = csr_read(mie); + + return !!(mie & (1 << irq)); +} + +#if defined(CONFIG_RISCV_HAS_PLIC) +void z_riscv_irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags) +{ + unsigned int level = irq_get_level(irq); + + if (level == 2) { + riscv_plic_set_priority(irq, prio); + } +} +#endif /* CONFIG_RISCV_HAS_PLIC */ +#endif /* CONFIG_RISCV_HAS_CLIC */ + +#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT) +__weak void soc_interrupt_init(void) +{ + /* ensure that all interrupts are disabled */ + (void)arch_irq_lock(); + + csr_write(mie, 0); + csr_write(mip, 0); +} +#endif 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 000000000000000..acf7e724aea4700 --- /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/riscv-privileged/common/vector.S b/soc/riscv/common/riscv-privileged/vector.S similarity index 88% rename from soc/riscv/riscv-privileged/common/vector.S rename to soc/riscv/common/riscv-privileged/vector.S index 5883bdcca853d74..bb11345787481ba 100644 --- a/soc/riscv/riscv-privileged/common/vector.S +++ b/soc/riscv/common/riscv-privileged/vector.S @@ -76,6 +76,14 @@ SECTION_FUNC(vectors, __start) #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 * @@ -85,6 +93,8 @@ SECTION_FUNC(vectors, __start) la t0, _isr_wrapper csrw mtvec, t0 +#endif /* CONFIG_RISCV_HAS_CLIC&& !CONFIG_LEGACY_CLIC */ + #endif /* CONFIG_RISCV_VECTORED_MODE */ /* Jump to __reset */ diff --git a/soc/riscv/efinix_sapphire/CMakeLists.txt b/soc/riscv/efinix_sapphire/CMakeLists.txt new file mode 100644 index 000000000000000..9edb7c3afe58c4d --- /dev/null +++ b/soc/riscv/efinix_sapphire/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Efinix Inc. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/efinix_sapphire/Kconfig.defconfig b/soc/riscv/efinix_sapphire/Kconfig.defconfig new file mode 100644 index 000000000000000..95a33b4ab829062 --- /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 000000000000000..4bad3b5cb79f993 --- /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 4dd457b68016c0b..d6772eacbfc95d6 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 @@ -94,3 +93,9 @@ endif() board_finalize_runner_args(esp32 "--esp-boot-address=${boot_off}") board_finalize_runner_args(esp32 "--esp-app-address=${img_0_off}") + +if(CONFIG_MCUBOOT) + set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/mcuboot.ld CACHE INTERNAL "") +else() + set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default.ld CACHE INTERNAL "") +endif() diff --git a/soc/riscv/espressif_esp32/esp32c3/default.ld b/soc/riscv/espressif_esp32/esp32c3/default.ld index 0965036fb4239e1..65984b4fd7b2699 100644 --- a/soc/riscv/espressif_esp32/esp32c3/default.ld +++ b/soc/riscv/espressif_esp32/esp32c3/default.ld @@ -130,6 +130,7 @@ SECTIONS SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) { + _rodata_reserved_start = ABSOLUTE(.); _rodata_start = ABSOLUTE(.); *(.rodata_desc .rodata_desc.*) @@ -141,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.*) @@ -174,19 +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(.); - _rodata_reserved_end = ABSOLUTE(.); . = ALIGN(4); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) @@ -197,12 +191,14 @@ SECTIONS #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,,) { + _rodata_reserved_end = ABSOLUTE(.); . = ALIGN(4); _image_rodata_end = ABSOLUTE(.); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) @@ -232,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.*) @@ -402,7 +399,6 @@ SECTIONS { . = SIZEOF(_RODATA_SECTION_NAME); . = ALIGN(0x10000) + 0x20; - _rodata_reserved_start = .; } GROUP_LINK_IN(FLASH_CODE_REGION) .flash.text : ALIGN(IROM_SEG_ALIGN) diff --git a/soc/riscv/espressif_esp32/esp32c3/idle.c b/soc/riscv/espressif_esp32/esp32c3/idle.c deleted file mode 100644 index 1bfb2832187716d..000000000000000 --- 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/linker.ld b/soc/riscv/espressif_esp32/esp32c3/linker.ld deleted file mode 100644 index 934088ca7280542..000000000000000 --- a/soc/riscv/espressif_esp32/esp32c3/linker.ld +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - */ - -#if defined(CONFIG_MCUBOOT) - /* Using mcuboot as ESP32C3 2nd stage bootloader */ - #include "mcuboot.ld" - -#else - /* Application default linker script */ - #include "default.ld" - -#endif /* CONFIG_MCUBOOT */ diff --git a/soc/riscv/espressif_esp32/esp32c3/soc.c b/soc/riscv/espressif_esp32/esp32c3/soc.c index 8bb32a5febdd88e..c125450a4d9bc9f 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 a3709819abc5880..68fb6fdb1ceca2e 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 c1ad164c1536b27..6ce11ae6a818764 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 000000000000000..69b2926358e5cf8 --- /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 000000000000000..46f2dd0b1d6b01b --- /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 000000000000000..2be284db7eac4cf --- /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 000000000000000..09d7d5d627ea5f3 --- /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 000000000000000..9fa5868a2a6a4df --- /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 1e93f2703b239f0..d37b27ffbf02aed 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 000000000000000..17ab7a87c392f0c --- /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 000000000000000..e50567e07980a49 --- /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 000000000000000..10e29a4ba3e2723 --- /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 000000000000000..0feb828931ba87a --- /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 000000000000000..69b2926358e5cf8 --- /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 000000000000000..b841d19c9227590 --- /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 000000000000000..2afa0f7e0e60599 --- /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 000000000000000..8567429c61f6c43 --- /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/intel_niosv/niosv/CMakeLists.txt b/soc/riscv/intel_niosv/niosv/CMakeLists.txt new file mode 100644 index 000000000000000..e7a753a2db33a17 --- /dev/null +++ b/soc/riscv/intel_niosv/niosv/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (C) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") 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 000000000000000..15e98314c8937b2 --- /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 000000000000000..9d7aa4926921cba --- /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 000000000000000..54628029a4ece11 --- /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 000000000000000..8994f47abd9c873 --- /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 000000000000000..13f951c04666c32 --- /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 100% rename from soc/riscv/riscv-ite/common/check_regs.c rename to soc/riscv/ite_ec/common/check_regs.c 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 000000000000000..240a8bb82348e91 --- /dev/null +++ b/soc/riscv/ite_ec/common/chip_chipregs.h @@ -0,0 +1,2223 @@ +/* + * 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) + +/* --- 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_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, + 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; +}; +#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 000000000000000..b7e0cdd5e55f190 --- /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/ite_ec/common/soc_common_irq.c b/soc/riscv/ite_ec/common/soc_common_irq.c new file mode 100644 index 000000000000000..d2625c2766d0b15 --- /dev/null +++ b/soc/riscv/ite_ec/common/soc_common_irq.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief interrupt management code for riscv SOCs supporting the riscv + privileged architecture specification + */ +#include + +#include + +void arch_irq_enable(unsigned int irq) +{ + if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) { + ite_intc_irq_enable(irq); + } +} + +void arch_irq_disable(unsigned int irq) +{ + if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) { + ite_intc_irq_disable(irq); + } +}; + +int arch_irq_is_enabled(unsigned int irq) +{ + /* + * Return true from arch_irq_is_enabled() when external interrupt-enable + * bit, and SOC's IER are both true. + */ + if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) { + return ((csr_read(mie) & BIT(IRQ_M_EXT)) && + ite_intc_irq_is_enable(irq)); + } else { + return 0; + } +} 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 000000000000000..ceb0f3afecb7e00 --- /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/ite_ec/it8xxx2/CMakeLists.txt b/soc/riscv/ite_ec/it8xxx2/CMakeLists.txt new file mode 100644 index 000000000000000..df4d9021745f960 --- /dev/null +++ b/soc/riscv/ite_ec/it8xxx2/CMakeLists.txt @@ -0,0 +1,9 @@ +zephyr_sources( + soc.c +) +zephyr_library_sources_ifndef(CONFIG_RISCV_ISA_EXT_M __arithmetic.S) +zephyr_sources_ifdef(CONFIG_SOC_IT8XXX2_USE_ILM ilm.c) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld + CACHE INTERNAL "SoC Linker script ${SOC_NAME}" +) 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/ite_ec/it8xxx2/Kconfig.defconfig.it82002aw b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it82002aw new file mode 100644 index 000000000000000..1edba5f674eafe8 --- /dev/null +++ b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it82002aw @@ -0,0 +1,12 @@ +# Copyright (c) 2023 ITE Corporation. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_IT82002_AW + +config SOC + default "it82002aw" + +config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN + default y + +endif 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 000000000000000..0ed7358b631db01 --- /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 000000000000000..265bf855f12c30b --- /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 000000000000000..800a2a9dafd7da6 --- /dev/null +++ b/soc/riscv/ite_ec/it8xxx2/Kconfig.soc @@ -0,0 +1,161 @@ +# 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 + +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/__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/ite_ec/it8xxx2/linker.ld b/soc/riscv/ite_ec/it8xxx2/linker.ld new file mode 100644 index 000000000000000..5c13ee2ecce29aa --- /dev/null +++ b/soc/riscv/ite_ec/it8xxx2/linker.ld @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2020 ITE Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#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 4 + #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 + +#ifdef CONFIG_SOC_IT8XXX2_SHA256_HW_ACCELERATE +#define SHA256_BLOCK_SIZE 0x200 +#endif + +#include + +MEMORY +{ +#ifdef CONFIG_XIP + ROM (rx) : ORIGIN = ROM_BASE, LENGTH = ROM_SIZE +#endif + RAM (rwx) : ORIGIN = RAM_BASE, LENGTH = RAM_SIZE + +#if defined(CONFIG_LINKER_DEVNULL_MEMORY) + DEVNULL_ROM (rx) : ORIGIN = DEVNULL_ADDR, LENGTH = DEVNULL_SIZE +#endif + + 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) + __rom_region_start = ROM_BASE; + + SECTION_PROLOGUE(rom_start,,) + { + . = ALIGN(16); +/* 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) + +#ifndef CONFIG_SOC_IT8XXX2_EXCEPTIONS_IN_RAM + SECTION_PROLOGUE(_EXCEPTION_SECTION_NAME,,) + { + KEEP(*(".exception.entry.*")) + *(".exception.other.*") + } GROUP_LINK_IN(ROMABLE_REGION) +#endif + + SECTION_PROLOGUE(_TEXT_SECTION_NAME,,) + { + . = ALIGN(4); + KEEP(*(.openocd_debug)) + KEEP(*(".openocd_debug.*")) + + __text_region_start = .; + + *(.text) + *(".text.*") + *(.gnu.linkonce.t.*) +#include + + /* IT8xxx2 requires memory mappings be configured for execution + * out of RAM, which refer to contiguous blocks of RAM. Place + * all relevant sections together to minimize RAM waste. */ + . = ALIGN(0x1000); + /* Mapping base address must be 4k-aligned */ + __ilm_flash_start = .; +#ifdef CONFIG_SOC_IT8XXX2_SHA256_HW_ACCELERATE + /* Pad to match allocation of block in RAM, + * maintaining code alignment against ILM */ + __sha256_pad_block_start = .; + . = . + SHA256_BLOCK_SIZE; +#endif + /* Specially-tagged functions in SoC sources */ + KEEP(*(.__ram_code)) + *(.__ram_code.*) +#ifdef CONFIG_SOC_IT8XXX2_EXCEPTIONS_IN_RAM + KEEP(*(".exception.entry.*")) + *(".exception.other.*") +#endif + __ilm_flash_end = .; + /* ILM mapping is always a multiple of 4k size; ensure following + * sections won't incorrectly redirect to RAM. */ + . = ALIGN(0x1000); + + } 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); +#ifdef CONFIG_QEMU_TARGET + /* + * QEMU doesn't vet each instruction fetch individually. + * Instead, it grabs a whole page and perform dynamic + * transation on it in a batch. It therefore validates + * PMP permissions using page-sized and -aligned chunks. + */ + . = ALIGN(0x1000); +#endif + } 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; + + /* Claim RAM for ILM mappings; must be 4k-aligned and each mapping is 4k in + * size, but mapped regions can still be accessed as data so don't need to be + * padded out to 4k size. This doesn't load any sections because code in ILM + * is still accessed at its VMA in ROM. */ + SECTION_PROLOGUE(ilm_ram,(NOLOAD),ALIGN(0x1000)) + { + __ilm_ram_start = .; + +#ifdef CONFIG_SOC_IT8XXX2_SHA256_HW_ACCELERATE + __sha256_ram_block_start = .; + KEEP(*(.__sha256_ram_block)) + __sha256_ram_block_size = \ + ABSOLUTE(. - __sha256_ram_block_start); + __sha256_ram_block_end = .; + ASSERT((__sha256_ram_block_size == SHA256_BLOCK_SIZE), \ + "We need 512bytes for HW sha256 module"); + ASSERT((__sha256_ram_block_end < (RAM_BASE + 0x1000)), \ + "512bytes must in SRAM first 4kbytes"); + ASSERT(((ABSOLUTE(__sha256_ram_block_start) & 0xfff) == \ + (ABSOLUTE(__sha256_pad_block_start) & 0xfff)), \ + "sha256 ram block needs the same offset with sha256 rom block"); +#endif + . += __ilm_flash_end - __ilm_flash_start; + __ilm_ram_end = .; + } GROUP_LINK_IN(RAMABLE_REGION) + + _image_ram_start = .; +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + +#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 = .; + + SECTION_DATA_PROLOGUE(.h2ram_pool,(NOLOAD),) + { + /* + * Since __sha256_ram_block section must in the first 4KB, + * h2ram_pool section is no longer included first inside the + * RAMABLE_REGION. + * Append h2ram_pool section at the end of used memory, so gap + * due to alignment is still available for newly added variables + */ + . = ALIGN(0x1000); + _h2ram_pool_start = .; + KEEP(*(.h2ram_pool)) + _h2ram_pool_end = .; + } GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) + _h2ram_pool_size = ABSOLUTE(_h2ram_pool_end - _h2ram_pool_start); + + __kernel_ram_end = .; + __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; + +/* 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,(NOLOAD),) +{ +} GROUP_LINK_IN(ROMABLE_REGION) + +/* To provide the image size as a const expression, + * calculate this value here. */ +__rom_region_end = LOADADDR(.last_section); +__rom_region_size = __rom_region_end - __rom_region_start; +#endif + +} diff --git a/soc/riscv/ite_ec/it8xxx2/soc.c b/soc/riscv/ite_ec/it8xxx2/soc.c new file mode 100644 index 000000000000000..48e9360e2086cdc --- /dev/null +++ b/soc/riscv/ite_ec/it8xxx2/soc.c @@ -0,0 +1,396 @@ +/* + * 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, + .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; + +#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 000000000000000..527152601d51487 --- /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 34d6046ab684cb6..000000000000000 --- a/soc/riscv/litex-vexriscv/CMakeLists.txt +++ /dev/null @@ -1,10 +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 -) diff --git a/soc/riscv/litex-vexriscv/Kconfig.defconfig b/soc/riscv/litex-vexriscv/Kconfig.defconfig deleted file mode 100644 index 9447948b56764b1..000000000000000 --- 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/linker.ld b/soc/riscv/litex-vexriscv/linker.ld deleted file mode 100644 index 424ee50014f019d..000000000000000 --- a/soc/riscv/litex-vexriscv/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2018 - 2019 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/riscv/litex-vexriscv/soc.h b/soc/riscv/litex-vexriscv/soc.h deleted file mode 100644 index b738deec771372b..000000000000000 --- 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 000000000000000..98386f6b57a60de --- /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 000000000000000..0088420459f025b --- /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 000000000000000..4334be4ec1ca8c2 --- /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 000000000000000..69b2926358e5cf8 --- /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 000000000000000..46616636aa1277a --- /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 000000000000000..2fe508bddbac0ef --- /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 000000000000000..8677f1ba44875a0 --- /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/microchip_miv/miv/CMakeLists.txt b/soc/riscv/microchip_miv/miv/CMakeLists.txt new file mode 100644 index 000000000000000..316f08474bab7d2 --- /dev/null +++ b/soc/riscv/microchip_miv/miv/CMakeLists.txt @@ -0,0 +1,5 @@ +# 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/microchip_miv/miv/Kconfig.defconfig.series b/soc/riscv/microchip_miv/miv/Kconfig.defconfig.series new file mode 100644 index 000000000000000..35f4365b02b6bdc --- /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 000000000000000..9f3486196246c6a --- /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 000000000000000..0a48c2e0524e41d --- /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/microchip_miv/polarfire/CMakeLists.txt b/soc/riscv/microchip_miv/polarfire/CMakeLists.txt new file mode 100644 index 000000000000000..316f08474bab7d2 --- /dev/null +++ b/soc/riscv/microchip_miv/polarfire/CMakeLists.txt @@ -0,0 +1,5 @@ +# 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/microchip_miv/polarfire/Kconfig.defconfig.series b/soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series new file mode 100644 index 000000000000000..53e88f1096efa9f --- /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 000000000000000..59ec4dbdd7a98f8 --- /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 000000000000000..101e8b4d02940b9 --- /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/neorv32/CMakeLists.txt b/soc/riscv/neorv32/CMakeLists.txt new file mode 100644 index 000000000000000..42731316d8460ca --- /dev/null +++ b/soc/riscv/neorv32/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2021 Henrik Brix Andersen +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources( + reset.S + soc_irq.S + soc.c +) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/neorv32/Kconfig.defconfig b/soc/riscv/neorv32/Kconfig.defconfig new file mode 100644 index 000000000000000..bc37ea74727dceb --- /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 000000000000000..3155d1b7c31c2cf --- /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 000000000000000..a97daa0fc153bce --- /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/openisa_rv32m1/CMakeLists.txt b/soc/riscv/openisa_rv32m1/CMakeLists.txt index 37f4d9c7488d3d8..a7a722279c34207 100644 --- a/soc/riscv/openisa_rv32m1/CMakeLists.txt +++ b/soc/riscv/openisa_rv32m1/CMakeLists.txt @@ -20,3 +20,5 @@ zephyr_sources( ) zephyr_linker_sources(ROM_START SORT_KEY 0x0vectors vector_table.ld) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/openisa_rv32m1/Kconfig.defconfig b/soc/riscv/openisa_rv32m1/Kconfig.defconfig index 3976c9940c56258..52d652a061e64a6 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 2d99535bd9c8ffb..95edf0c5383273b 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 1b2643d0b664c7f..75011d362833fdc 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 23222ea2c70941b..d3059d2bd2809f6 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 8e0efdc7d62ff5b..7e7ac08de78d62a 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 27ebcbe6f35c3d3..d9158935e088a1a 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 d5fa48297f76f94..43cd144823a0702 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/opentitan/CMakeLists.txt b/soc/riscv/opentitan/CMakeLists.txt new file mode 100644 index 000000000000000..3502022cbedf8c0 --- /dev/null +++ b/soc/riscv/opentitan/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(soc.c rom_header.S) + +zephyr_linker_sources(ROM_START SORT_KEY 000romheader rom_header.ld) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/opentitan/Kconfig.defconfig b/soc/riscv/opentitan/Kconfig.defconfig new file mode 100644 index 000000000000000..4b067ef76afba3b --- /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 000000000000000..c76cfe013b18ce8 --- /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 000000000000000..d627356c58f5af2 --- /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 000000000000000..56d36b84ec8bbcc --- /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 000000000000000..fab59719595056b --- /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 000000000000000..ba42c40c28d1e8a --- /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 f25c53d1ffb670d..000000000000000 --- 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 ae18beac098b4e1..000000000000000 --- 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 925edb1543ce660..000000000000000 --- 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 17e1fa11b7ae0f1..000000000000000 --- 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_CHSEF 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_CHSAB ECREG(IT8XXX2_SMB_BASE + 0x20) -#define IT8XXX2_SMB_CHSCD 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_SMB4CHS 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 5b9817831646d48..000000000000000 --- 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_common_irq.c b/soc/riscv/riscv-ite/common/soc_common_irq.c deleted file mode 100644 index aff5fe0d4b53541..000000000000000 --- a/soc/riscv/riscv-ite/common/soc_common_irq.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2017 Jean-Paul Etienne - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief interrupt management code for riscv SOCs supporting the riscv - privileged architecture specification - */ -#include - -void arch_irq_enable(unsigned int irq) -{ - if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) { - ite_intc_irq_enable(irq); - } -} - -void arch_irq_disable(unsigned int irq) -{ - if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) { - ite_intc_irq_disable(irq); - } -}; - -int arch_irq_is_enabled(unsigned int irq) -{ - /* - * Return true from arch_irq_is_enabled() when external interrupt-enable - * bit, and SOC's IER are both true. - */ - if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) { - return ((csr_read(mie) & BIT(IRQ_M_EXT)) && - ite_intc_irq_is_enable(irq)); - } else { - return 0; - } -} 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 a412ca6a7966c3f..000000000000000 --- 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/CMakeLists.txt b/soc/riscv/riscv-ite/it8xxx2/CMakeLists.txt deleted file mode 100644 index b7eff43b09693f2..000000000000000 --- a/soc/riscv/riscv-ite/it8xxx2/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -zephyr_sources( - soc.c -) -zephyr_library_sources_ifndef(CONFIG_RISCV_ISA_EXT_M __arithmetic.S) -zephyr_sources_ifdef(CONFIG_SOC_IT8XXX2_USE_ILM ilm.c) 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 4e6b7c18cca32ff..000000000000000 --- 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 ebed0fcd120ef4d..000000000000000 --- 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 c33fe0f376f55cb..000000000000000 --- a/soc/riscv/riscv-ite/it8xxx2/Kconfig.soc +++ /dev/null @@ -1,157 +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 - -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/linker.ld b/soc/riscv/riscv-ite/it8xxx2/linker.ld deleted file mode 100644 index e285147f6903f29..000000000000000 --- a/soc/riscv/riscv-ite/it8xxx2/linker.ld +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (c) 2020 ITE Corporation. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#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 4 - #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 - -#ifdef CONFIG_SOC_IT8XXX2_SHA256_HW_ACCELERATE -#define SHA256_BLOCK_SIZE 0x200 -#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) - __rom_region_start = ROM_BASE; - - SECTION_PROLOGUE(rom_start,,) - { - . = ALIGN(16); -/* 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) - -#ifndef CONFIG_SOC_IT8XXX2_EXCEPTIONS_IN_RAM - SECTION_PROLOGUE(_EXCEPTION_SECTION_NAME,,) - { - KEEP(*(".exception.entry.*")) - *(".exception.other.*") - } GROUP_LINK_IN(ROMABLE_REGION) -#endif - - SECTION_PROLOGUE(_TEXT_SECTION_NAME,,) - { - . = ALIGN(4); - KEEP(*(.openocd_debug)) - KEEP(*(".openocd_debug.*")) - - __text_region_start = .; - - *(.text) - *(".text.*") - *(.gnu.linkonce.t.*) -#include - - /* IT8xxx2 requires memory mappings be configured for execution - * out of RAM, which refer to contiguous blocks of RAM. Place - * all relevant sections together to minimize RAM waste. */ - . = ALIGN(0x1000); - /* Mapping base address must be 4k-aligned */ - __ilm_flash_start = .; -#ifdef CONFIG_SOC_IT8XXX2_SHA256_HW_ACCELERATE - /* Pad to match allocation of block in RAM, - * maintaining code alignment against ILM */ - __sha256_pad_block_start = .; - . = . + SHA256_BLOCK_SIZE; -#endif - /* Specially-tagged functions in SoC sources */ - KEEP(*(.__ram_code)) - *(.__ram_code.*) -#ifdef CONFIG_SOC_IT8XXX2_EXCEPTIONS_IN_RAM - KEEP(*(".exception.entry.*")) - *(".exception.other.*") -#endif - __ilm_flash_end = .; - /* ILM mapping is always a multiple of 4k size; ensure following - * sections won't incorrectly redirect to RAM. */ - . = ALIGN(0x1000); - - } 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); -#ifdef CONFIG_QEMU_TARGET - /* - * QEMU doesn't vet each instruction fetch individually. - * Instead, it grabs a whole page and perform dynamic - * transation on it in a batch. It therefore validates - * PMP permissions using page-sized and -aligned chunks. - */ - . = ALIGN(0x1000); -#endif - } 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; - - /* Claim RAM for ILM mappings; must be 4k-aligned and each mapping is 4k in - * size, but mapped regions can still be accessed as data so don't need to be - * padded out to 4k size. This doesn't load any sections because code in ILM - * is still accessed at its VMA in ROM. */ - SECTION_PROLOGUE(ilm_ram,(NOLOAD),ALIGN(0x1000)) - { - __ilm_ram_start = .; - -#ifdef CONFIG_SOC_IT8XXX2_SHA256_HW_ACCELERATE - __sha256_ram_block_start = .; - KEEP(*(.__sha256_ram_block)) - __sha256_ram_block_size = \ - ABSOLUTE(. - __sha256_ram_block_start); - __sha256_ram_block_end = .; - ASSERT((__sha256_ram_block_size == SHA256_BLOCK_SIZE), \ - "We need 512bytes for HW sha256 module"); - ASSERT((__sha256_ram_block_end < (RAM_BASE + 0x1000)), \ - "512bytes must in SRAM first 4kbytes"); - ASSERT(((ABSOLUTE(__sha256_ram_block_start) & 0xfff) == \ - (ABSOLUTE(__sha256_pad_block_start) & 0xfff)), \ - "sha256 ram block needs the same offset with sha256 rom block"); -#endif - . += __ilm_flash_end - __ilm_flash_start; - __ilm_ram_end = .; - } GROUP_LINK_IN(RAMABLE_REGION) - - _image_ram_start = .; -/* Located in generated directory. This file is populated by the - * zephyr_linker_sources() Cmake function. - */ -#include - -#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 = .; - - SECTION_DATA_PROLOGUE(.h2ram_pool,(NOLOAD),) - { - /* - * Since __sha256_ram_block section must in the first 4KB, - * h2ram_pool section is no longer included first inside the - * RAMABLE_REGION. - * Append h2ram_pool section at the end of used memory, so gap - * due to alignment is still available for newly added variables - */ - . = ALIGN(0x1000); - _h2ram_pool_start = .; - KEEP(*(.h2ram_pool)) - _h2ram_pool_end = .; - } GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) - _h2ram_pool_size = ABSOLUTE(_h2ram_pool_end - _h2ram_pool_start); - - __kernel_ram_end = .; - __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; - -/* 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,(NOLOAD),) -{ -} GROUP_LINK_IN(ROMABLE_REGION) - -/* To provide the image size as a const expression, - * calculate this value here. */ -__rom_region_end = LOADADDR(.last_section); -__rom_region_size = __rom_region_end - __rom_region_start; -#endif - -} diff --git a/soc/riscv/riscv-ite/it8xxx2/soc.c b/soc/riscv/riscv-ite/it8xxx2/soc.c deleted file mode 100644 index 7bf213ad695ec0b..000000000000000 --- 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 bc7907683692c6f..000000000000000 --- 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 c5f97039eb75b46..000000000000000 --- 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 f94eabd96a7ac89..000000000000000 --- a/soc/riscv/riscv-privileged/Kconfig +++ /dev/null @@ -1,37 +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 - -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 6793d72a385bd20..000000000000000 --- 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 14d141223e0a434..000000000000000 --- 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 3de7b8c8841a0c4..000000000000000 --- a/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt +++ /dev/null @@ -1,25 +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() 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 c6436807825f55c..000000000000000 --- 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 9a99711b04c633a..000000000000000 --- 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 19f215e2c5ac766..000000000000000 --- 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 a47aceb60389409..000000000000000 --- 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 95ea7486fd3b25a..000000000000000 --- 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/linker.ld b/soc/riscv/riscv-privileged/andes_v5/linker.ld deleted file mode 100644 index 5f92edc75a95df3..000000000000000 --- a/soc/riscv/riscv-privileged/andes_v5/linker.ld +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2021 Andes Technology Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * linker script for andes_v5 SoC Series - */ - - -#if defined(CONFIG_SOC_RISCV_ANDES_AE350) -# include -#endif 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 459285c12819514..000000000000000 --- 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 50ee91a2c33bd1f..000000000000000 --- 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 e61ce72b28069f3..000000000000000 --- 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 79f458924c6e59c..000000000000000 --- 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_common_irq.c b/soc/riscv/riscv-privileged/common/soc_common_irq.c deleted file mode 100644 index c407bc8e20cc1eb..000000000000000 --- a/soc/riscv/riscv-privileged/common/soc_common_irq.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2017 Jean-Paul Etienne - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief interrupt management code for riscv SOCs supporting the riscv - privileged architecture specification - */ -#include - -#include -#include - -#if defined(CONFIG_RISCV_HAS_CLIC) - -void arch_irq_enable(unsigned int irq) -{ - riscv_clic_irq_enable(irq); -} - -void arch_irq_disable(unsigned int irq) -{ - riscv_clic_irq_disable(irq); -} - -int arch_irq_is_enabled(unsigned int irq) -{ - return riscv_clic_irq_is_enabled(irq); -} - -void z_riscv_irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags) -{ - riscv_clic_irq_priority_set(irq, prio, flags); -} - -#else /* PLIC + HLINT/CLINT or HLINT/CLINT only */ - -void arch_irq_enable(unsigned int irq) -{ - uint32_t mie; - -#if defined(CONFIG_RISCV_HAS_PLIC) - unsigned int level = irq_get_level(irq); - - if (level == 2) { - irq = irq_from_level_2(irq); - riscv_plic_irq_enable(irq); - return; - } -#endif - - /* - * CSR mie register is updated using atomic instruction csrrs - * (atomic read and set bits in CSR register) - */ - mie = csr_read_set(mie, 1 << irq); -} - -void arch_irq_disable(unsigned int irq) -{ - uint32_t mie; - -#if defined(CONFIG_RISCV_HAS_PLIC) - unsigned int level = irq_get_level(irq); - - if (level == 2) { - irq = irq_from_level_2(irq); - riscv_plic_irq_disable(irq); - return; - } -#endif - - /* - * Use atomic instruction csrrc to disable device interrupt in mie CSR. - * (atomic read and clear bits in CSR register) - */ - mie = csr_read_clear(mie, 1 << irq); -} - -int arch_irq_is_enabled(unsigned int irq) -{ - uint32_t mie; - -#if defined(CONFIG_RISCV_HAS_PLIC) - unsigned int level = irq_get_level(irq); - - if (level == 2) { - irq = irq_from_level_2(irq); - return riscv_plic_irq_is_enabled(irq); - } -#endif - - mie = csr_read(mie); - - return !!(mie & (1 << irq)); -} - -#if defined(CONFIG_RISCV_HAS_PLIC) -void z_riscv_irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags) -{ - unsigned int level = irq_get_level(irq); - - if (level == 2) { - irq = irq_from_level_2(irq); - riscv_plic_set_priority(irq, prio); - } -} -#endif /* CONFIG_RISCV_HAS_PLIC */ -#endif /* CONFIG_RISCV_HAS_CLIC */ - -#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT) -__weak void soc_interrupt_init(void) -{ - /* ensure that all interrupts are disabled */ - (void)arch_irq_lock(); - - csr_write(mie, 0); - csr_write(mip, 0); -} -#endif 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 73fc24431d58d26..000000000000000 --- 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/efinix-sapphire/CMakeLists.txt b/soc/riscv/riscv-privileged/efinix-sapphire/CMakeLists.txt deleted file mode 100644 index 9fc8063593792dd..000000000000000 --- a/soc/riscv/riscv-privileged/efinix-sapphire/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) 2023 Efinix Inc. -# SPDX-License-Identifier: Apache-2.0 - -zephyr_include_directories(.) 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 233428931a38c40..000000000000000 --- 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 8505cf1318a6d4b..000000000000000 --- 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 dba8491b8bdab3a..000000000000000 --- 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/linker.ld b/soc/riscv/riscv-privileged/efinix-sapphire/linker.ld deleted file mode 100644 index 4cfd67a53f5009e..000000000000000 --- a/soc/riscv/riscv-privileged/efinix-sapphire/linker.ld +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -#include 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 1d566e2f293da70..000000000000000 --- 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 a3cabd57ab1d99e..000000000000000 --- a/soc/riscv/riscv-privileged/gd32vf103/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2021 Tokita, Hiroshi -# SPDX-License-Identifier: Apache-2.0 - -zephyr_sources(entry.S) -zephyr_sources(soc.c) 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 061b53b2514ead7..000000000000000 --- 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 3922bf19bdda08d..000000000000000 --- 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 5f8af0d691f5fce..000000000000000 --- 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/linker.ld b/soc/riscv/riscv-privileged/gd32vf103/linker.ld deleted file mode 100644 index 849c94ebe96647b..000000000000000 --- a/soc/riscv/riscv-privileged/gd32vf103/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2021 Tokita, Hiroshi - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/riscv/riscv-privileged/gd32vf103/soc.h b/soc/riscv/riscv-privileged/gd32vf103/soc.h deleted file mode 100644 index 14cdd6b733c1501..000000000000000 --- 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/CMakeLists.txt b/soc/riscv/riscv-privileged/miv/CMakeLists.txt deleted file mode 100644 index 55fc3999fd7b294..000000000000000 --- a/soc/riscv/riscv-privileged/miv/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_sources() 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 81b224ed3971db6..000000000000000 --- 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 00a6f129f9faaf3..000000000000000 --- 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 189abb6879ce962..000000000000000 --- 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/linker.ld b/soc/riscv/riscv-privileged/miv/linker.ld deleted file mode 100644 index 0d220a25c735453..000000000000000 --- a/soc/riscv/riscv-privileged/miv/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2018 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/riscv/riscv-privileged/miv/soc.h b/soc/riscv/riscv-privileged/miv/soc.h deleted file mode 100644 index 1608c9e6773eb3d..000000000000000 --- 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/CMakeLists.txt b/soc/riscv/riscv-privileged/mpfs/CMakeLists.txt deleted file mode 100644 index 55fc3999fd7b294..000000000000000 --- a/soc/riscv/riscv-privileged/mpfs/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_sources() 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 fb9f6d2d3af337f..000000000000000 --- 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 ca37731f1925132..000000000000000 --- 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 7f20dc703c2275b..000000000000000 --- 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/linker.ld b/soc/riscv/riscv-privileged/mpfs/linker.ld deleted file mode 100644 index 4e3ca81bfbb7681..000000000000000 --- a/soc/riscv/riscv-privileged/mpfs/linker.ld +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2021-2022 Microchip Technology Inc - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/riscv/riscv-privileged/mpfs/soc.h b/soc/riscv/riscv-privileged/mpfs/soc.h deleted file mode 100644 index d6a7d2d2e374318..000000000000000 --- 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/CMakeLists.txt b/soc/riscv/riscv-privileged/neorv32/CMakeLists.txt deleted file mode 100644 index 7f7c334feddff35..000000000000000 --- a/soc/riscv/riscv-privileged/neorv32/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2021 Henrik Brix Andersen -# SPDX-License-Identifier: Apache-2.0 - -zephyr_sources( - reset.S - soc_irq.S - soc.c -) 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 11bd7ef7d337f8c..000000000000000 --- 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 98c7f34024d2601..000000000000000 --- 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 93c9da8cc3d46cb..000000000000000 --- 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 a1e721923a428c5..000000000000000 --- 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/CMakeLists.txt b/soc/riscv/riscv-privileged/niosv/CMakeLists.txt deleted file mode 100644 index c740850bc77417f..000000000000000 --- a/soc/riscv/riscv-privileged/niosv/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (C) 2023, Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -zephyr_include_directories(.) 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 532a67959d2c3c9..000000000000000 --- 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 7de17cf2db09a66..000000000000000 --- 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 8c10fec45405335..000000000000000 --- 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/CMakeLists.txt b/soc/riscv/riscv-privileged/opentitan/CMakeLists.txt deleted file mode 100644 index 05e59ca70719ba8..000000000000000 --- a/soc/riscv/riscv-privileged/opentitan/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_sources(soc.c rom_header.S) - -zephyr_linker_sources(ROM_START SORT_KEY 000romheader rom_header.ld) 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 c9e7f8396a0f431..000000000000000 --- 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 f8bbc2840fed7a5..000000000000000 --- 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 098b1844e52e08c..000000000000000 --- 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/linker.ld b/soc/riscv/riscv-privileged/opentitan/linker.ld deleted file mode 100644 index 8eeb9c50af370fa..000000000000000 --- a/soc/riscv/riscv-privileged/opentitan/linker.ld +++ /dev/null @@ -1,3 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ - -#include diff --git a/soc/riscv/riscv-privileged/opentitan/soc.c b/soc/riscv/riscv-privileged/opentitan/soc.c deleted file mode 100644 index 0b04079233a0f2b..000000000000000 --- 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 13bb5c43b54a573..000000000000000 --- 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 f5f6c539efdd393..000000000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/CMakeLists.txt +++ /dev/null @@ -1,6 +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) 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 0c3cd5417734990..000000000000000 --- 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 523f6a4ffe97d9f..000000000000000 --- 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 7840f8a09ba79e5..000000000000000 --- 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 0b642f3e8b2203f..000000000000000 --- 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 07e088fbd822437..000000000000000 --- 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 bc68a502f5989d4..000000000000000 --- 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 6709d4bfad2469d..000000000000000 --- 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 e6bbee93689f7bf..000000000000000 --- 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 00d529388c8abfc..000000000000000 --- 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/linker.ld b/soc/riscv/riscv-privileged/sifive-freedom/linker.ld deleted file mode 100644 index 96720f18a2e433d..000000000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/linker.ld +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2017 Jean-Paul Etienne - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @brief Linker script for the SiFive Freedom processor - */ - -#include 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 958891a9d6a1ec3..000000000000000 --- 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 c488c614b7d2f08..000000000000000 --- 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 b360f78b77b413b..000000000000000 --- 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/linker.ld b/soc/riscv/riscv-privileged/starfive_jh71xx/linker.ld deleted file mode 100644 index 4e63d62344deb1f..000000000000000 --- a/soc/riscv/riscv-privileged/starfive_jh71xx/linker.ld +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright (c) 2020 Cobham Gaisler AB - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include 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 796f07201d9dd96..000000000000000 --- 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/CMakeLists.txt b/soc/riscv/riscv-privileged/telink_b91/CMakeLists.txt deleted file mode 100644 index c91adf6a993a6d1..000000000000000 --- a/soc/riscv/riscv-privileged/telink_b91/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2021 Telink Semiconductor -# SPDX-License-Identifier: Apache-2.0 - -zephyr_sources( - start.S - soc_irq.S - soc.c -) - -# Force using BFD-LD -zephyr_ld_options(-fuse-ld=bfd) - -# Set compile options -zephyr_compile_options_ifdef(CONFIG_TELINK_B91_HWDSP -mext-dsp) -zephyr_compile_options_ifndef(CONFIG_RISCV_GP -mno-relax) -zephyr_linker_sources(ROM_START SORT_KEY 0x0 init.ld) 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 986b62407505e92..000000000000000 --- 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 a966dfe447bd993..000000000000000 --- 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 3f4f96c332e593f..000000000000000 --- 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 a46b4c620c78096..000000000000000 --- 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/CMakeLists.txt b/soc/riscv/riscv-privileged/virt/CMakeLists.txt deleted file mode 100644 index 9486f25591264b0..000000000000000 --- a/soc/riscv/riscv-privileged/virt/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_sources(soc.c) 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 231d4519d6771e9..000000000000000 --- 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 e9846764f6baebd..000000000000000 --- 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 35a2853eb50089a..000000000000000 --- 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/linker.ld b/soc/riscv/riscv-privileged/virt/linker.ld deleted file mode 100644 index 4e63d62344deb1f..000000000000000 --- a/soc/riscv/riscv-privileged/virt/linker.ld +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright (c) 2020 Cobham Gaisler AB - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include diff --git a/soc/riscv/riscv-privileged/virt/soc.c b/soc/riscv/riscv-privileged/virt/soc.c deleted file mode 100644 index 581f4116c9b8ee9..000000000000000 --- 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 8fd5e2108ce4019..000000000000000 --- 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 000000000000000..6a5b10545ff103e --- /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 000000000000000..0fed11158afca52 --- /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 000000000000000..5adf8fc437e54c0 --- /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 000000000000000..54274defd919aad --- /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/riscv-privileged/starfive_jh71xx/CMakeLists.txt b/soc/riscv/sifive_freedom/common/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/starfive_jh71xx/CMakeLists.txt rename to soc/riscv/sifive_freedom/common/CMakeLists.txt 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 000000000000000..baf01a6b0473772 --- /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 000000000000000..cb0131f142706ac --- /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 000000000000000..eaa43e68e705e9a --- /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 000000000000000..81634da000d4b35 --- /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 000000000000000..e53b84c08907d11 --- /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 000000000000000..8fde8121db95fb7 --- /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 000000000000000..6c2da210aad9fcc --- /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 000000000000000..3b4c4b54f8e77e0 --- /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 000000000000000..baf01a6b0473772 --- /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 000000000000000..d306b60252a708b --- /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 000000000000000..f559f5914b3f094 --- /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 000000000000000..7335a1a529366ca --- /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 000000000000000..0a88ccf8cc1ffd8 --- /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 000000000000000..87929892f77d083 --- /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 000000000000000..4e80b7a131d35ee --- /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 000000000000000..5ae3f5f00bd8978 --- /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 000000000000000..baf01a6b0473772 --- /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 000000000000000..a0e730d608f86ca --- /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 000000000000000..ca935f772eb0021 --- /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 000000000000000..04bdc1fb9b2bcaa --- /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 000000000000000..1eec9b4bb17a715 --- /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 000000000000000..5c3fa5673432bc1 --- /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 000000000000000..ed78e9249399aee --- /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 000000000000000..dcd37dfdc4400a0 --- /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 000000000000000..69b2926358e5cf8 --- /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 000000000000000..65694c07eff78ff --- /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 000000000000000..b399e38b3406df0 --- /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 000000000000000..1ff54faa97013dc --- /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/starfive_jh71xx/jh71xx/CMakeLists.txt b/soc/riscv/starfive_jh71xx/jh71xx/CMakeLists.txt new file mode 100644 index 000000000000000..f79d0b3255d3da8 --- /dev/null +++ b/soc/riscv/starfive_jh71xx/jh71xx/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") 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 000000000000000..6f38d61dd4e5ce8 --- /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 000000000000000..0f058cb6c252d18 --- /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 000000000000000..f392a5d1f9726ae --- /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 000000000000000..69b2926358e5cf8 --- /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 000000000000000..144751311ba963f --- /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 000000000000000..04a888381fa9c1d --- /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 000000000000000..db09c69d1f4ec0f --- /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/telink_tlsr/tlsr951x/CMakeLists.txt b/soc/riscv/telink_tlsr/tlsr951x/CMakeLists.txt new file mode 100644 index 000000000000000..8c489ac6dd7985a --- /dev/null +++ b/soc/riscv/telink_tlsr/tlsr951x/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright (c) 2021 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources( + start.S + soc_irq.S + soc.c +) + +# Force using BFD-LD +zephyr_ld_options(-fuse-ld=bfd) + +# Set compile options +zephyr_compile_options_ifdef(CONFIG_TELINK_B91_HWDSP -mext-dsp) +zephyr_compile_options_ifndef(CONFIG_RISCV_GP -mno-relax) +zephyr_linker_sources(ROM_START SORT_KEY 0x0 init.ld) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") 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 000000000000000..2b72ad9960cc2c4 --- /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 000000000000000..4ffdebdaf6b6ec4 --- /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 000000000000000..5d5fc3226e5bd2e --- /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 000000000000000..2abc12cc58c5b7a --- /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 000000000000000..6acfd63dd02d8be --- /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/virt/CMakeLists.txt b/soc/riscv/virt/CMakeLists.txt new file mode 100644 index 000000000000000..6a1826b29f92bc7 --- /dev/null +++ b/soc/riscv/virt/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/virt/Kconfig.defconfig b/soc/riscv/virt/Kconfig.defconfig new file mode 100644 index 000000000000000..bed5ff8bec7bffb --- /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 000000000000000..59e553a9d7bc5e1 --- /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 000000000000000..0bdcf6e80f2fe50 --- /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/Kconfig b/soc/sparc/Kconfig index 0d975d46c327809..de68a73004895b3 100644 --- a/soc/sparc/Kconfig +++ b/soc/sparc/Kconfig @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 config SPARC_CASA - default y + default y if SPARC config SOC_SPARC_LEON bool diff --git a/soc/sparc/gr716a/CMakeLists.txt b/soc/sparc/gr716a/CMakeLists.txt index 746570b05c7cd27..888e386817e6bc3 100644 --- a/soc/sparc/gr716a/CMakeLists.txt +++ b/soc/sparc/gr716a/CMakeLists.txt @@ -1,3 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_sources(../leon3/idle.c) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/sparc/leon3/CMakeLists.txt b/soc/sparc/leon3/CMakeLists.txt index 53b77ee8a37fe10..722526c00cf8ae7 100644 --- a/soc/sparc/leon3/CMakeLists.txt +++ b/soc/sparc/leon3/CMakeLists.txt @@ -1,3 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_sources(idle.c) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/x86/alder_lake/CMakeLists.txt b/soc/x86/alder_lake/CMakeLists.txt index 67d93138e14aca2..47325b7a8091ff8 100644 --- a/soc/x86/alder_lake/CMakeLists.txt +++ b/soc/x86/alder_lake/CMakeLists.txt @@ -6,3 +6,5 @@ zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) zephyr_cc_option(-march=goldmont) zephyr_library_sources(cpu.c) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/x86/apollo_lake/CMakeLists.txt b/soc/x86/apollo_lake/CMakeLists.txt index 67d93138e14aca2..47325b7a8091ff8 100644 --- a/soc/x86/apollo_lake/CMakeLists.txt +++ b/soc/x86/apollo_lake/CMakeLists.txt @@ -6,3 +6,5 @@ zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) zephyr_cc_option(-march=goldmont) zephyr_library_sources(cpu.c) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/x86/atom/CMakeLists.txt b/soc/x86/atom/CMakeLists.txt index 9881313609aae2c..66d55c6ba96466f 100644 --- a/soc/x86/atom/CMakeLists.txt +++ b/soc/x86/atom/CMakeLists.txt @@ -1 +1,3 @@ # SPDX-License-Identifier: Apache-2.0 + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/x86/elkhart_lake/CMakeLists.txt b/soc/x86/elkhart_lake/CMakeLists.txt index 67d93138e14aca2..47325b7a8091ff8 100644 --- a/soc/x86/elkhart_lake/CMakeLists.txt +++ b/soc/x86/elkhart_lake/CMakeLists.txt @@ -6,3 +6,5 @@ zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) zephyr_cc_option(-march=goldmont) zephyr_library_sources(cpu.c) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/x86/ia32/CMakeLists.txt b/soc/x86/ia32/CMakeLists.txt index 9881313609aae2c..66d55c6ba96466f 100644 --- a/soc/x86/ia32/CMakeLists.txt +++ b/soc/x86/ia32/CMakeLists.txt @@ -1 +1,3 @@ # SPDX-License-Identifier: Apache-2.0 + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/x86/intel_ish/intel_ish5/CMakeLists.txt b/soc/x86/intel_ish/intel_ish5/CMakeLists.txt index 6d4f911744ad520..3c253ac264835d3 100644 --- a/soc/x86/intel_ish/intel_ish5/CMakeLists.txt +++ b/soc/x86/intel_ish/intel_ish5/CMakeLists.txt @@ -8,4 +8,6 @@ zephyr_cc_option(-march=pentium -mtune=i486) zephyr_sources(soc.c) add_subdirectory_ifdef(CONFIG_PM pm) +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") + include(../utils/build_ish_firmware.cmake) diff --git a/soc/x86/lakemont/CMakeLists.txt b/soc/x86/lakemont/CMakeLists.txt index 6f44c89f7ad6f80..4527b084519e342 100644 --- a/soc/x86/lakemont/CMakeLists.txt +++ b/soc/x86/lakemont/CMakeLists.txt @@ -3,3 +3,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_cc_option(-march=pentium) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/x86/raptor_lake/CMakeLists.txt b/soc/x86/raptor_lake/CMakeLists.txt index 3be2e750b6156bf..06c46752f818fbb 100644 --- a/soc/x86/raptor_lake/CMakeLists.txt +++ b/soc/x86/raptor_lake/CMakeLists.txt @@ -1,3 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_cc_option(-march=goldmont) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/x86/raptor_lake/soc_gpio.h b/soc/x86/raptor_lake/soc_gpio.h index 544df564a081bfe..6901cab92211fb0 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/CMakeLists.txt b/soc/xtensa/dc233c/CMakeLists.txt index 52a6e84baa99fcd..8012661a4371b94 100644 --- a/soc/xtensa/dc233c/CMakeLists.txt +++ b/soc/xtensa/dc233c/CMakeLists.txt @@ -1,3 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_include_directories(include) zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU mmu.c) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/include/xtensa-dc233c.ld CACHE INTERNAL "") diff --git a/soc/xtensa/dc233c/Kconfig.defconfig b/soc/xtensa/dc233c/Kconfig.defconfig index c78c8cd73370a3a..dc5be860b4a55d1 100644 --- a/soc/xtensa/dc233c/Kconfig.defconfig +++ b/soc/xtensa/dc233c/Kconfig.defconfig @@ -22,7 +22,8 @@ config XTENSA_MMU_NUM_L2_TABLES # via TLB way 4 (which covers 1MB). config SRAM_OFFSET hex - default 0x100000 + default 0x100000 if XTENSA_MMU + default 0x2400 config KERNEL_VM_OFFSET hex diff --git a/soc/xtensa/dc233c/Kconfig.soc b/soc/xtensa/dc233c/Kconfig.soc index 89b814da4d2bd95..ecbe77a9febb145 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 65f47f5ce9b8f48..b77effc032bd3fb 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,51 +304,52 @@ 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 .text) - *libarch__xtensa__core.a:crt1.S.obj(.literal) - *libarch__xtensa__core.a:crt1.S.obj(.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,*) + + *libarch__xtensa__core.a:debug_helpers_asm.S.obj(.iram1.literal .iram1) - *libkernel.a:fatal.c.obj(.literal.*) - *libkernel.a:fatal.c.obj(.text.*) + /* 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 */ +#ifdef CONFIG_CODE_DATA_RELOCATION +#include +#endif + .ResetVector.text : ALIGN(4) { __rom_region_start = ABSOLUTE(.); @@ -363,6 +367,7 @@ SECTIONS *(.entry.text) *(.init.literal) *(.iram0.literal .iram.literal .iram.text.literal .iram0.text .iram.text) + *(.iram1.literal .iram1) KEEP(*(.init)) *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) *(.fini.literal) @@ -375,7 +380,7 @@ SECTIONS _text_end = ABSOLUTE(.); _etext = .; - } >RAM :sram0_phdr + } >RAMABLE_REGION __text_region_end = .; .rodata : HDR_MMU_PAGE_ALIGN @@ -389,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) @@ -399,19 +413,26 @@ SECTIONS MMU_PAGE_ALIGN __rodata_region_end = ABSOLUTE(.); - } >RAM :sram0_phdr - -#include + } >RAMABLE_REGION -#include +#ifdef CONFIG_USERSPACE +#define SMEM_PARTITION_ALIGN(size) MMU_PAGE_ALIGN +#define APP_SHARED_ALIGN MMU_PAGE_ALIGN -#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.*) @@ -433,7 +454,9 @@ SECTIONS MMU_PAGE_ALIGN __data_end = ABSOLUTE(.); - } >RAM :sram0_phdr + } >RAMABLE_REGION + +#include #include diff --git a/soc/xtensa/dc233c/linker.ld b/soc/xtensa/dc233c/linker.ld deleted file mode 100644 index 1f8e9eadd1a78ca..000000000000000 --- a/soc/xtensa/dc233c/linker.ld +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (c) 2016 Cadence Design Systems, Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * Linker script for the Xtensa platform. - */ -#include diff --git a/soc/xtensa/dc233c/mmu.c b/soc/xtensa/dc233c/mmu.c index 4b8d6b154b84c68..ed6818b3efb38ae 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 6468d1545dcf8c2..c71c016a706ed98 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,6 +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) + + 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() -board_finalize_runner_args(esp32 "--esp-app-address=${img_0_off}") +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 2189f7b2dd95573..858386e4fd089ac 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 7371c49ed9403f5..6b53076770391f5 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 20dc3c28ef57998..d0eb9b46f4ae4ce 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 000000000000000..a28399f57c4fd98 --- /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 db166677f2d5962..7922e6f18cdcef3 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 f7962b618513a4b..c8913b7f5a27df0 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/linker.ld b/soc/xtensa/espressif_esp32/esp32/linker.ld deleted file mode 100644 index 981d25bf18af620..000000000000000 --- a/soc/xtensa/espressif_esp32/esp32/linker.ld +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - */ - -#if defined(CONFIG_MCUBOOT) - /* Using mcuboot as ESP32 2nd stage bootloader */ - #include "mcuboot.ld" - -#else - /* Application default linker script */ - #include "default.ld" - -#endif /* CONFIG_MCUBOOT */ diff --git a/soc/xtensa/espressif_esp32/esp32/soc.c b/soc/xtensa/espressif_esp32/esp32/soc.c index 2abd0f6a88ac313..16df3aca6452bff 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 000000000000000..a8ff116a58a1fdd --- /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 9be4cbc549dabf7..000000000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/CMakeLists.txt +++ /dev/null @@ -1,21 +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() 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 8193bbb6149a7e3..000000000000000 --- 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 55f794f96e05677..000000000000000 --- 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 975b777b7907689..000000000000000 --- 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 63d6eef4c8195ea..000000000000000 --- 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 03e0c5df0b2fcda..000000000000000 --- 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 69a4c48ef78d4bf..000000000000000 --- 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 b0a0efcc4e60c4e..000000000000000 --- 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 ac53ccb7e741e87..000000000000000 --- 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 7bd495bffb8c794..000000000000000 --- 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/CMakeLists.txt b/soc/xtensa/espressif_esp32/esp32s2/CMakeLists.txt index 2b023ede856c870..b9f361d1d5c094b 100644 --- a/soc/xtensa/espressif_esp32/esp32s2/CMakeLists.txt +++ b/soc/xtensa/espressif_esp32/esp32s2/CMakeLists.txt @@ -93,3 +93,9 @@ endif() board_finalize_runner_args(esp32 "--esp-boot-address=${boot_off}") board_finalize_runner_args(esp32 "--esp-app-address=${img_0_off}") + +if(CONFIG_MCUBOOT) + set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/mcuboot.ld CACHE INTERNAL "") +else() + set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default.ld CACHE INTERNAL "") +endif() diff --git a/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series b/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series index c1618783ae598cb..177c5184e9806a6 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 4ef27a6384c2cc0..8a78bb89ac2d1e9 100644 --- a/soc/xtensa/espressif_esp32/esp32s2/default.ld +++ b/soc/xtensa/espressif_esp32/esp32s2/default.ld @@ -135,6 +135,7 @@ SECTIONS */ SECTION_PROLOGUE(_RODATA_SECTION_NAME,,ALIGN(4)) { + _rodata_reserved_start = ABSOLUTE(.); __rodata_region_start = ABSOLUTE(.); . = ALIGN(4); @@ -174,15 +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(.); - _rodata_reserved_end = ABSOLUTE(.); . = ALIGN(4); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) @@ -192,12 +186,14 @@ SECTIONS #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(0x10)) { + _rodata_reserved_end = ABSOLUTE(.); . = ALIGN(4); _image_rodata_end = ABSOLUTE(.); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) diff --git a/soc/xtensa/espressif_esp32/esp32s2/linker.ld b/soc/xtensa/espressif_esp32/esp32s2/linker.ld deleted file mode 100644 index dc2d891834ed743..000000000000000 --- a/soc/xtensa/espressif_esp32/esp32s2/linker.ld +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - */ - -#if defined(CONFIG_MCUBOOT) - /* Using mcuboot as ESP32S2 2nd stage bootloader */ - #include "mcuboot.ld" - -#else - /* Application default linker script */ - #include "default.ld" - -#endif /* CONFIG_MCUBOOT */ diff --git a/soc/xtensa/espressif_esp32/esp32s2/soc.c b/soc/xtensa/espressif_esp32/esp32s2/soc.c index 45edde47178546b..5e1ec21c07547cf 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/CMakeLists.txt b/soc/xtensa/espressif_esp32/esp32s3/CMakeLists.txt index dc9e86d66048491..cb5291614bcb812 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/CMakeLists.txt +++ b/soc/xtensa/espressif_esp32/esp32s3/CMakeLists.txt @@ -112,3 +112,11 @@ else() 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_ESP32S3_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/esp32s3/Kconfig.defconfig.series b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series index 31f7bdbff50cc94..30d0480cad28e06 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 b8cc95b62cb5a00..ad8b4b4234b8a93 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 36944d69c60a342..4076ea7c1af13ee 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/default.ld +++ b/soc/xtensa/espressif_esp32/esp32s3/default.ld @@ -167,6 +167,7 @@ SECTIONS */ SECTION_PROLOGUE(_RODATA_SECTION_NAME,,ALIGN(0x10)) { + _rodata_reserved_start = ABSOLUTE(.); _rodata_start = ABSOLUTE(.); *(.rodata_desc .rodata_desc.*) /* Should be the first. App version info. DO NOT PUT ANYTHING BEFORE IT! */ @@ -210,15 +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(.); - _rodata_reserved_end = ABSOLUTE(.); . = ALIGN(4); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) @@ -229,12 +223,14 @@ SECTIONS #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(0x10)) { + _rodata_reserved_end = ABSOLUTE(.); . = ALIGN(16); _image_rodata_end = ABSOLUTE(.); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) @@ -494,7 +490,6 @@ SECTIONS { . = SIZEOF(_RODATA_SECTION_NAME); . = ALIGN(IROM_SEG_ALIGN) + 0x20; - _rodata_reserved_start = .; } GROUP_LINK_IN(FLASH_CODE_REGION) .flash.text : ALIGN(IROM_SEG_ALIGN) diff --git a/soc/xtensa/espressif_esp32/esp32s3/linker.ld b/soc/xtensa/espressif_esp32/esp32s3/linker.ld deleted file mode 100644 index 9303f5a325d96aa..000000000000000 --- a/soc/xtensa/espressif_esp32/esp32s3/linker.ld +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - */ - -#if defined(CONFIG_MCUBOOT) - /* Using mcuboot as ESP32S3 2nd stage bootloader */ - #include "mcuboot.ld" - -#else - - /* Application default linker script */ - #if defined(CONFIG_SOC_ESP32S3_APPCPU) - #include "default_appcpu.ld" - #else - #include "default.ld" - #endif - -#endif /* CONFIG_MCUBOOT */ diff --git a/soc/xtensa/espressif_esp32/esp32s3/soc.c b/soc/xtensa/espressif_esp32/esp32s3/soc.c index ad971b907b27193..d250657c49ef963 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/CMakeLists.txt b/soc/xtensa/intel_adsp/CMakeLists.txt index 8a3b1f01f25b578..2cee15bbcf6b9b4 100644 --- a/soc/xtensa/intel_adsp/CMakeLists.txt +++ b/soc/xtensa/intel_adsp/CMakeLists.txt @@ -10,3 +10,4 @@ endif() if(CONFIG_INTEL_ADSP_CAVS) add_subdirectory(cavs) endif() +zephyr_include_directories(common/include) diff --git a/soc/xtensa/intel_adsp/Kconfig b/soc/xtensa/intel_adsp/Kconfig index f04286ccae12b4d..ed491015fac31a0 100644 --- a/soc/xtensa/intel_adsp/Kconfig +++ b/soc/xtensa/intel_adsp/Kconfig @@ -113,4 +113,24 @@ config ADSP_IMR_CONTEXT_SAVE entering D3 state. Later this context can be used to FW restore when Host power up DSP again. +config XTENSA_CPU_IDLE_SPIN + bool "Use busy loop for k_cpu_idle" + help + Use a spin loop instead of WAITI for the CPU idle state. + +config XTENSA_WAITI_BUG + bool "Workaround sequence for WAITI bug on LX6" + help + SOF traditionally contains this workaround on its ADSP + 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 43e812cbabb393d..28626787c5e68bb 100644 --- a/soc/xtensa/intel_adsp/ace/CMakeLists.txt +++ b/soc/xtensa/intel_adsp/ace/CMakeLists.txt @@ -11,7 +11,12 @@ zephyr_library_sources( power_down.S power.c boot.c + timestamp.c ) +zephyr_include_directories(include) +zephyr_include_directories(include/${SOC_NAME}) zephyr_library_sources_ifdef(CONFIG_SOC_INTEL_COMM_WIDGET comm_widget.c) zephyr_library_sources_ifdef(CONFIG_SOC_INTEL_COMM_WIDGET comm_widget_messages.c) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series b/soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series index 198f0b35f708eab..5057e5cb16a03d3 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 000000000000000..4c7796a5ae4f8c7 --- /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_memory.h b/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_memory.h index 7290b1ef6cc6fd1..56e78cdca5fdfa2 100644 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_memory.h +++ b/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_memory.h @@ -147,6 +147,17 @@ struct ace_hpsram_regs { uint8_t HSxPGISTS; uint8_t reserved1[3]; }; + +struct ace_lpsram_regs { + /** @brief power gating control */ + uint8_t USxPGCTL; + /** @brief retention mode control */ + uint8_t USxRMCTL; + uint8_t reserved[2]; + /** @brief power gating status */ + uint8_t USxPGISTS; + uint8_t reserved1[3]; +}; #endif /* These registers are for the L2 HP SRAM bank power management control and status.*/ @@ -156,4 +167,11 @@ struct ace_hpsram_regs { #define HPSRAM_REGS(block_idx) ((volatile struct ace_hpsram_regs *const) \ (L2HSBPM_REG + L2HSBPM_REG_SIZE * (block_idx))) +/* These registers are for the L2 LP SRAM bank power management control and status.*/ +#define L2LSBPM_REG 0x71D80 +#define L2LSBPM_REG_SIZE 0x0008 + +#define LPSRAM_REGS(block_idx) ((volatile struct ace_lpsram_regs *const) \ + (L2LSBPM_REG + L2LSBPM_REG_SIZE * (block_idx))) + #endif /* ZEPHYR_SOC_INTEL_ADSP_MEMORY_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 6efcde4a4913001..4da0e07508c1a60 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 56997ee84d10a1c..521dc4e5fb16c76 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 6e953991a81a356..000000000000000 --- 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_memory.h b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_memory.h index 165831207f1901f..a45a8ae590d2131 100644 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_memory.h +++ b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_memory.h @@ -145,6 +145,17 @@ struct ace_hpsram_regs { uint8_t HSxPGISTS; uint8_t reserved1[3]; }; + +struct ace_lpsram_regs { + /** @brief power gating control */ + uint8_t USxPGCTL; + /** @brief retention mode control */ + uint8_t USxRMCTL; + uint8_t reserved[2]; + /** @brief power gating status */ + uint8_t USxPGISTS; + uint8_t reserved1[3]; +}; #endif /* These registers are for the L2 HP SRAM bank power management control and status.*/ @@ -154,4 +165,11 @@ struct ace_hpsram_regs { #define HPSRAM_REGS(block_idx) ((volatile struct ace_hpsram_regs *const) \ (L2HSBPM_REG + L2HSBPM_REG_SIZE * (block_idx))) +/* These registers are for the L2 LP SRAM bank power management control and status.*/ +#define L2LSBPM_REG 0x71D80 +#define L2LSBPM_REG_SIZE 0x0008 + +#define LPSRAM_REGS(block_idx) ((volatile struct ace_lpsram_regs *const) \ + (L2LSBPM_REG + L2LSBPM_REG_SIZE * (block_idx))) + #endif /* ZEPHYR_SOC_INTEL_ADSP_MEMORY_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 60631945da30cc7..5d12c79fdcb1aa3 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 363feb14fa0ec98..f640a0a9f59bc96 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 e762245e669ecbe..8e5657f033fdd69 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(!arch_xtensa_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 7fe33c3feaf8714..878d6a58bc273cf 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" @@ -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/sram.c b/soc/xtensa/intel_adsp/ace/sram.c index d2f7bb6c27a5845..fb3348e0f33a825 100644 --- a/soc/xtensa/intel_adsp/ace/sram.c +++ b/soc/xtensa/intel_adsp/ace/sram.c @@ -20,15 +20,14 @@ __imr void hp_sram_init(uint32_t memory_size) ARG_UNUSED(memory_size); uint32_t hpsram_ebb_quantity = ace_hpsram_get_bank_count(); - volatile uint32_t *l2hsbpmptr = (volatile uint32_t *)ACE_L2MM->l2hsbpmptr; - volatile uint8_t *status = (volatile uint8_t *)l2hsbpmptr + 4; uint32_t idx; for (idx = 0; idx < hpsram_ebb_quantity; ++idx) { - *(l2hsbpmptr + idx * 2) = 0; + HPSRAM_REGS(idx)->HSxPGCTL = 0; + HPSRAM_REGS(idx)->HSxRMCTL = 1; } for (idx = 0; idx < hpsram_ebb_quantity; ++idx) { - while (*(status + idx * 8) != 0) { + while (HPSRAM_REGS(idx)->HSxPGISTS != 0) { } } @@ -38,15 +37,14 @@ __imr void hp_sram_init(uint32_t memory_size) __imr void lp_sram_init(void) { uint32_t lpsram_ebb_quantity = ace_lpsram_get_bank_count(); - volatile uint32_t *l2usbpmptr = (volatile uint32_t *)ACE_L2MM->l2usbpmptr; - volatile uint8_t *status = (volatile uint8_t *)l2usbpmptr + 4; uint32_t idx; for (idx = 0; idx < lpsram_ebb_quantity; ++idx) { - *(l2usbpmptr + idx * 2) = 0; + LPSRAM_REGS(idx)->USxPGCTL = 0; + LPSRAM_REGS(idx)->USxRMCTL = 1; } for (idx = 0; idx < lpsram_ebb_quantity; ++idx) { - while (*(status + idx * 8) != 0) { + while (LPSRAM_REGS(idx)->USxPGISTS != 0) { } } diff --git a/soc/xtensa/intel_adsp/ace/timestamp.c b/soc/xtensa/intel_adsp/ace/timestamp.c new file mode 100644 index 000000000000000..7f3168d87f4a2c9 --- /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/CMakeLists.txt b/soc/xtensa/intel_adsp/cavs/CMakeLists.txt index 2a0cbdc463c6adf..5226f1b0535200e 100644 --- a/soc/xtensa/intel_adsp/cavs/CMakeLists.txt +++ b/soc/xtensa/intel_adsp/cavs/CMakeLists.txt @@ -3,7 +3,8 @@ # Copyright (c) 2022 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -zephyr_library_include_directories(include) +zephyr_include_directories(include) +zephyr_include_directories(include/${SOC_NAME}) zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) zephyr_library_sources( @@ -17,3 +18,5 @@ if(CONFIG_SMP OR CONFIG_MP_MAX_NUM_CPUS GREATER 1) endif() zephyr_library_sources_ifdef(CONFIG_CAVS_ICTL irq.c) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/include/xtensa-cavs-linker.ld CACHE INTERNAL "") diff --git a/soc/xtensa/intel_adsp/cavs/Kconfig.series b/soc/xtensa/intel_adsp/cavs/Kconfig.series index adbc1f39e1d49f6..a88bec1ec2e4312 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 c273e5252bb794b..dc9a573a3b132a6 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/linker.ld b/soc/xtensa/intel_adsp/cavs/linker.ld deleted file mode 100644 index 7c5566067b64715..000000000000000 --- a/soc/xtensa/intel_adsp/cavs/linker.ld +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2019 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * Linker script for the intel_apl_adsp platform - */ - -#include diff --git a/soc/xtensa/intel_adsp/cavs/multiprocessing.c b/soc/xtensa/intel_adsp/cavs/multiprocessing.c index bc48764515a5155..5b13b8138585527 100644 --- a/soc/xtensa/intel_adsp/cavs/multiprocessing.c +++ b/soc/xtensa/intel_adsp/cavs/multiprocessing.c @@ -7,6 +7,7 @@ #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, @@ -71,7 +72,22 @@ void soc_start_core(int cpu_num) }; memcpy(lpsram, tramp, ARRAY_SIZE(tramp)); +#if CONFIG_PM + extern void dsp_restore_vector(void); + + /* We need to find out what type of booting is taking place here. Secondary cores + * can be disabled and enabled multiple times during runtime. During kernel + * initialization, the next pm state is set to ACTIVE. This way we can determine + * whether the core is being turned on again or for the first time. + */ + if (pm_state_next_get(cpu_num)->state == PM_STATE_ACTIVE) + lpsram[1] = z_soc_mp_asm_entry; + else + lpsram[1] = dsp_restore_vector; +#else lpsram[1] = z_soc_mp_asm_entry; +#endif + /* Disable automatic power and clock gating for that CPU, so * it won't just go back to sleep. Note that after startup, @@ -98,7 +114,7 @@ void soc_start_core(int cpu_num) * available, so it's sent shifted). The write to ITC * triggers the interrupt, so that comes last. */ - uint32_t ietc = ((long) z_soc_mp_asm_entry) >> 2; + uint32_t ietc = ((long)lpsram[1]) >> 2; IDC[curr_cpu].core[cpu_num].ietc = ietc; IDC[curr_cpu].core[cpu_num].itc = IDC_MSG_POWER_UP; @@ -170,19 +186,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 e5b9f73285d88aa..f21a09910d327ad 100644 --- a/soc/xtensa/intel_adsp/cavs/power.c +++ b/soc/xtensa/intel_adsp/cavs/power.c @@ -52,8 +52,12 @@ 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; + uint32_t a1; + uint32_t excsave2; uint32_t intenable; }; @@ -76,6 +80,56 @@ static inline void __sparse_cache *uncache_to_cache(void *address) return (void __sparse_cache *)((uintptr_t)(address) | SRAM_ALIAS_OFFSET); } +static ALWAYS_INLINE void _save_core_context(void) +{ + uint32_t core_id = arch_proc_id(); + + core_desc[core_id].excsave2 = XTENSA_RSR(ZSR_CPU_STR); + __asm__ volatile("mov %0, a0" : "=r"(core_desc[core_id].a0)); + __asm__ volatile("mov %0, a1" : "=r"(core_desc[core_id].a1)); + sys_cache_data_flush_range(&core_desc[core_id], sizeof(struct core_state)); +} + +static ALWAYS_INLINE void _restore_core_context(void) +{ + uint32_t core_id = arch_proc_id(); + + XTENSA_WSR(ZSR_CPU_STR, core_desc[core_id].excsave2); + __asm__ volatile("mov a0, %0" :: "r"(core_desc[core_id].a0)); + __asm__ volatile("mov a1, %0" :: "r"(core_desc[core_id].a1)); + __asm__ volatile("rsync"); +} + +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" + ".global dsp_restore_vector\n\t" + "dsp_restore_vector:\n\t" + " movi a0, 0\n\t" + " movi a1, 1\n\t" + " movi a2, 0x40020\n\t"/* PS_UM|PS_WOE */ + " wsr a2, PS\n\t" + " wsr a1, WINDOWSTART\n\t" + " wsr a0, WINDOWBASE\n\t" + " rsync\n\t" + " movi a1, z_interrupt_stacks\n\t" + " rsr a2, PRID\n\t" + " movi a3, " STRINGIFY(CONFIG_ISR_STACK_SIZE) "\n\t" + " mull a2, a2, a3\n\t" + " add a2, a2, a3\n\t" + " add a1, a1, a2\n\t" + " call0 power_gate_exit\n\t"); + void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -84,6 +138,8 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) if (state == PM_STATE_SOFT_OFF) { core_desc[cpu].intenable = XTENSA_RSR("INTENABLE"); z_xt_ints_off(0xffffffff); + xthal_window_spill(); + _save_core_context(); soc_cpus_active[cpu] = false; sys_cache_data_flush_and_invd_all(); if (cpu == 0) { @@ -107,8 +163,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 { - z_xt_ints_on(core_desc[cpu].intenable); - k_cpu_idle(); + k_cpu_atomic_idle(arch_irq_lock()); } } else { __ASSERT(false, "invalid argument - unsupported power state"); @@ -128,9 +183,60 @@ 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 */ +#ifdef CONFIG_ARCH_CPU_IDLE_CUSTOM +/* xt-clang removes any NOPs more than 8. So we need to set + * no optimization to avoid those NOPs from being removed. + * + * This function is simply enough and full of hand written + * assembly that optimization is not really meaningful + * anyway. So we can skip optimization unconditionally. + * Re-evalulate its use and add #ifdef if this assumption + * is no longer valid. + */ +__no_optimization +void arch_cpu_idle(void) +{ + sys_trace_idle(); + + /* Just spin forever with interrupts unmasked, for platforms + * where WAITI can't be used or where its behavior is + * complicated (Intel DSPs will power gate on idle entry under + * some circumstances) + */ + if (IS_ENABLED(CONFIG_XTENSA_CPU_IDLE_SPIN)) { + __asm__ volatile("rsil a0, 0"); + __asm__ volatile("loop_forever: j loop_forever"); + return; + } + + /* Cribbed from SOF: workaround for a bug in some versions of + * the LX6 IP. Preprocessor ugliness avoids the need to + * figure out how to get the compiler to unroll a loop. + */ + if (IS_ENABLED(CONFIG_XTENSA_WAITI_BUG)) { +#define NOP4 __asm__ volatile("nop; nop; nop; nop"); +#define NOP32 NOP4 NOP4 NOP4 NOP4 NOP4 NOP4 NOP4 NOP4 +#define NOP128() NOP32 NOP32 NOP32 NOP32 + NOP128(); +#undef NOP128 +#undef NOP32 +#undef NOP4 + __asm__ volatile("isync; extw"); + } + +__asm__ volatile ("waiti 0"); +} +#endif + __imr void power_init(void) { /* Request HP ring oscillator and diff --git a/soc/xtensa/intel_adsp/common/CMakeLists.txt b/soc/xtensa/intel_adsp/common/CMakeLists.txt index ff09b1e4ea80921..c463e4453fcddfe 100644 --- a/soc/xtensa/intel_adsp/common/CMakeLists.txt +++ b/soc/xtensa/intel_adsp/common/CMakeLists.txt @@ -6,7 +6,7 @@ zephyr_interface_library_named(INTEL_ADSP_COMMON) zephyr_library_named(intel_adsp_common) -zephyr_library_include_directories(include) +zephyr_include_directories(include) zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) zephyr_library_sources_ifdef(CONFIG_INTEL_ADSP_IPC ipc.c) 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 2b403eb17a4fb73..0b3f86890a1c8dc 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)) @@ -158,14 +161,14 @@ static inline int intel_adsp_hda_set_buffer(uint32_t base, */ uint32_t addr = (uint32_t)arch_xtensa_cached_ptr(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/intel_adsp_ipc.h b/soc/xtensa/intel_adsp/common/include/intel_adsp_ipc.h index 2bca8c9c5b808e9..ca1ddfb573be98d 100644 --- a/soc/xtensa/intel_adsp/common/include/intel_adsp_ipc.h +++ b/soc/xtensa/intel_adsp/common/include/intel_adsp_ipc.h @@ -7,10 +7,7 @@ #include #include #include -#ifdef CONFIG_PM_DEVICE_RUNTIME #include -#include -#endif struct intel_adsp_ipc_config { volatile struct intel_adsp_ipc *regs; diff --git a/soc/xtensa/intel_adsp/common/ipc.c b/soc/xtensa/intel_adsp/common/ipc.c index cdb5757d3560473..6ae1956ffac3892 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 de76fa37eac0cb5..79d7d1883e0651a 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 000000000000000..0d0897c02342583 --- /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/CMakeLists.txt b/soc/xtensa/nxp_adsp/CMakeLists.txt index f317b0b7054d856..a0ab21fb6a8c1e4 100644 --- a/soc/xtensa/nxp_adsp/CMakeLists.txt +++ b/soc/xtensa/nxp_adsp/CMakeLists.txt @@ -1,9 +1,14 @@ -# NXP i.MX8 SoC family CMake file +# NXP i.MX8/RT SoC family CMake file # # Copyright (c) 2021 NXP # SPDX-License-Identifier: Apache-2.0 +if(CONFIG_SOC_NXP_RT595) + zephyr_compile_definitions(CPU_MIMXRT595SFFOC_dsp) +endif() + add_subdirectory(common) +zephyr_include_directories(${SOC_SERIES}/include) # west sign @@ -18,3 +23,5 @@ add_custom_command( COMMAND west sign --if-tool-available --tool rimage --build-dir ${CMAKE_BINARY_DIR} ${WEST_SIGN_OPTS} DEPENDS ${CMAKE_BINARY_DIR}/zephyr/${KERNEL_ELF_NAME} ) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/${SOC_SERIES}/linker.ld CACHE INTERNAL "") diff --git a/soc/xtensa/nxp_adsp/Kconfig.defconfig b/soc/xtensa/nxp_adsp/Kconfig.defconfig index 4c8e3f9c83c438a..cdee20c75f53059 100644 --- a/soc/xtensa/nxp_adsp/Kconfig.defconfig +++ b/soc/xtensa/nxp_adsp/Kconfig.defconfig @@ -1,9 +1,33 @@ -# NXP i.MX8 SoC family default configuration options +# NXP i.MX8/RT SoC family default configuration options # # Copyright (c) 2021 NXP # SPDX-License-Identifier: Apache-2.0 +if SOC_FAMILY_NXP_ADSP + source "soc/xtensa/nxp_adsp/*/Kconfig.defconfig.series" config CACHE_MANAGEMENT - def_bool y + default y + +config SMP + default n + +config XTENSA_TIMER + default y + +config KERNEL_ENTRY + default "__start" + +config MULTI_LEVEL_INTERRUPTS + default n + +config 2ND_LEVEL_INTERRUPTS + default n + +# To prevent test uses TEST_LOGGING_MINIMAL +config TEST_LOGGING_DEFAULTS + default n + depends on TEST + +endif diff --git a/soc/xtensa/nxp_adsp/common/CMakeLists.txt b/soc/xtensa/nxp_adsp/common/CMakeLists.txt index 8d6294a67771683..5c53c771f0841df 100644 --- a/soc/xtensa/nxp_adsp/common/CMakeLists.txt +++ b/soc/xtensa/nxp_adsp/common/CMakeLists.txt @@ -3,15 +3,4 @@ # Copyright (c) 2021 NXP # SPDX-License-Identifier: Apache-2.0 -zephyr_interface_library_named(NXP_ADSP_COMMON) - -zephyr_library_named(nxp_adsp_common) -zephyr_library_include_directories(include) -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) +zephyr_include_directories(include) diff --git a/soc/xtensa/nxp_adsp/common/soc.c b/soc/xtensa/nxp_adsp/common/soc.c deleted file mode 100644 index 8c80ff77308b053..000000000000000 --- 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/imx8/Kconfig.defconfig.imx8qm b/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8qm new file mode 100644 index 000000000000000..e678be835925a29 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8qm @@ -0,0 +1,9 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_MIMX8QM_ADSP + +config SOC + default "mimx8qm6" + +endif # SOC_MIMX8QM_ADSP diff --git a/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8qxp b/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8qxp new file mode 100644 index 000000000000000..e4fcdd92fd05580 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8qxp @@ -0,0 +1,9 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_MIMX8QXP_ADSP + +config SOC + default "mimx8qx6" + +endif # SOC_MIMX8QXP_ADSP diff --git a/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.series b/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.series index 7431522e867ebd3..a5f4597f06917ab 100644 --- a/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.series +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.series @@ -11,40 +11,18 @@ config SOC_TOOLCHAIN_NAME string default "nxp_imx_adsp" -config SOC - string - default "nxp_imx8" - -config SMP - default n - -config XTENSA_TIMER - default y - config SYS_CLOCK_HW_CYCLES_PER_SEC default 666000000 if XTENSA_TIMER config SYS_CLOCK_TICKS_PER_SEC default 50000 -config KERNEL_ENTRY - default "__start" +config DCACHE_LINE_SIZE + default 128 -config MULTI_LEVEL_INTERRUPTS +config GEN_IRQ_VECTOR_TABLE default n -config 2ND_LEVEL_INTERRUPTS - default n - -config DYNAMIC_INTERRUPTS - default y - -config LOG - default y - -# To prevent test uses TEST_LOGGING_MINIMAL -config TEST_LOGGING_DEFAULTS - default n - depends on TEST +source "soc/xtensa/nxp_adsp/imx8/Kconfig.defconfig.imx8q*" endif # SOC_SERIES_NXP_IMX8 diff --git a/soc/xtensa/nxp_adsp/imx8/Kconfig.series b/soc/xtensa/nxp_adsp/imx8/Kconfig.series index 396607a484709ca..003784e842b144b 100644 --- a/soc/xtensa/nxp_adsp/imx8/Kconfig.series +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.series @@ -9,5 +9,7 @@ config SOC_SERIES_NXP_IMX8 select XTENSA_RESET_VECTOR select XTENSA_USE_CORE_CRT1 select ATOMIC_OPERATIONS_BUILTIN + select GEN_ISR_TABLES + select XTENSA_SMALL_VECTOR_TABLE_ENTRY help NXP i.MX8 diff --git a/soc/xtensa/nxp_adsp/imx8/Kconfig.soc b/soc/xtensa/nxp_adsp/imx8/Kconfig.soc index 16c36eb8a6eeb1e..33794a85c2be708 100644 --- a/soc/xtensa/nxp_adsp/imx8/Kconfig.soc +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.soc @@ -3,9 +3,26 @@ choice prompt "NXP i.MX SoC Selection" + depends on SOC_SERIES_NXP_IMX8 - config SOC_NXP_IMX8 - bool "i.MX8 SoC" + config SOC_MIMX8QM_ADSP + bool "NXP i.MX8QM Audio DSP" depends on SOC_SERIES_NXP_IMX8 + select HAS_MCUX + config SOC_MIMX8QXP_ADSP + bool "NXP i.MX8QXP Audio DSP" + depends on SOC_SERIES_NXP_IMX8 + select HAS_MCUX endchoice + +if SOC_SERIES_NXP_IMX8 + +config SOC_PART_NUMBER + string + default SOC_PART_NUMBER_MIMX8QM_DSP if SOC_MIMX8QM_ADSP + default SOC_PART_NUMBER_MIMX8QXP_DSP if SOC_MIMX8QXP_ADSP + +source "soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8q*" + +endif # SOC_SERIES_NXP_IMX8 diff --git a/soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qm b/soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qm new file mode 100644 index 000000000000000..fd5334cfee5d3b4 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qm @@ -0,0 +1,17 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_MIMX8QM_ADSP + +config SOC_PART_NUMBER_MIMX8QM6AVUFF + bool + +config SOC_PART_NUMBER_MIMX8QM_DSP + string + default "MIMX8QM6AVUFF_dsp" if SOC_PART_NUMBER_MIMX8QM6AVUFF + 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. + +endif # SOC_MIMX8QM_ADSP diff --git a/soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qxp b/soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qxp new file mode 100644 index 000000000000000..20f0a13e11724fe --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8/Kconfig.soc.imx8qxp @@ -0,0 +1,21 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_MIMX8QXP_ADSP + +config SOC_PART_NUMBER_MIMX8QX6AVLFZ + bool + +config SOC_PART_NUMBER_MIMX8QX6CVLDZ + bool + +config SOC_PART_NUMBER_MIMX8QXP_DSP + string + default "MIMX8QX6AVLFZ_dsp" if SOC_PART_NUMBER_MIMX8QX6AVLFZ + default "MIMX8QX6CVLDZ_dsp" if SOC_PART_NUMBER_MIMX8QX6CVLDZ + 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. + +endif # SOC_MIMX8QXP_ADSP diff --git a/soc/xtensa/nxp_adsp/imx8/include/memory.h b/soc/xtensa/nxp_adsp/imx8/include/memory.h new file mode 100644 index 000000000000000..56bac21c780b148 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8/include/memory.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2021 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 0x596f8000 +#define IRAM_SIZE 0x800 + +#define SDRAM0_BASE 0x92400000 +#define SDRAM0_SIZE 0x800000 + +#define SDRAM1_BASE 0x92C00000 +#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 0x596F8000 + +/* 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 0x596f8000 +#define IRAM_SIZE 0x800 + +#define DRAM0_BASE 0x596e8000 +#define DRAM0_SIZE 0x8000 + +#define DRAM1_BASE 0x596f0000 +#define DRAM1_SIZE 0x8000 + +#define SDRAM0_BASE 0x92400000 +#define SDRAM0_SIZE 0x800000 + +#define SDRAM1_BASE 0x92C00000 +#define SDRAM1_SIZE 0x800000 + +#define XSHAL_MU13_SIDEB_BYPASS_PADDR 0x5D310000 +#define MU_BASE XSHAL_MU13_SIDEB_BYPASS_PADDR + +#define EDMA0_BASE 0x59200000 +#define EDMA0_SIZE 0x10000 + +#define ESAI_BASE 0x59010000 +#define ESAI_SIZE 0x00010000 + +#define SAI_1_BASE 0x59050000 +#define SAI_1_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 0x800 +#define SRAM_DEBUG_OFFSET (SRAM_INBOX_OFFSET + SRAM_INBOX_SIZE) + +#define SRAM_EXCEPT_BASE (SRAM_DEBUG_BASE + SRAM_DEBUG_SIZE) +#define SRAM_EXCEPT_SIZE 0x800 +#define SRAM_EXCEPT_OFFSET (SRAM_DEBUG_OFFSET + SRAM_DEBUG_SIZE) + +#define SRAM_STREAM_BASE (SRAM_EXCEPT_BASE + SRAM_EXCEPT_SIZE) +#define SRAM_STREAM_SIZE 0x1000 +#define SRAM_STREAM_OFFSET (SRAM_EXCEPT_OFFSET + SRAM_EXCEPT_SIZE) + +#define SRAM_TRACE_BASE (SRAM_STREAM_BASE + SRAM_STREAM_SIZE) +#define SRAM_TRACE_SIZE 0x1000 +#define SRAM_TRACE_OFFSET (SRAM_STREAM_OFFSET + SRAM_STREAM_SIZE) + +#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/imx8/include/soc/memory.h b/soc/xtensa/nxp_adsp/imx8/include/soc/memory.h deleted file mode 100644 index ee4785995a89c9a..000000000000000 --- a/soc/xtensa/nxp_adsp/imx8/include/soc/memory.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2021 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __INC_MEMORY_H -#define __INC_MEMORY_H - -#define PLATFORM_CORE_COUNT 1 - -/** Id of master DSP core */ -#define PLATFORM_PRIMARY_CORE_ID 0 - -#define IRAM_RESERVE_HEADER_SPACE 0x400 - -#define IRAM_BASE 0x596f8000 -#define IRAM_SIZE 0x800 - -#define SDRAM0_BASE 0x92400000 -#define SDRAM0_SIZE 0x800000 - -#define SDRAM1_BASE 0x92C00000 -#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 0x596F8000 - -/* 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 0x596f8000 -#define IRAM_SIZE 0x800 - -#define DRAM0_BASE 0x596e8000 -#define DRAM0_SIZE 0x8000 - -#define DRAM1_BASE 0x596f0000 -#define DRAM1_SIZE 0x8000 - -#define SDRAM0_BASE 0x92400000 -#define SDRAM0_SIZE 0x800000 - -#define SDRAM1_BASE 0x92C00000 -#define SDRAM1_SIZE 0x800000 - -#define XSHAL_MU13_SIDEB_BYPASS_PADDR 0x5D310000 -#define MU_BASE XSHAL_MU13_SIDEB_BYPASS_PADDR - -#define EDMA0_BASE 0x59200000 -#define EDMA0_SIZE 0x10000 - -#define ESAI_BASE 0x59010000 -#define ESAI_SIZE 0x00010000 - -#define SAI_1_BASE 0x59050000 -#define SAI_1_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 0x800 -#define SRAM_DEBUG_OFFSET (SRAM_INBOX_OFFSET + SRAM_INBOX_SIZE) - -#define SRAM_EXCEPT_BASE (SRAM_DEBUG_BASE + SRAM_DEBUG_SIZE) -#define SRAM_EXCEPT_SIZE 0x800 -#define SRAM_EXCEPT_OFFSET (SRAM_DEBUG_OFFSET + SRAM_DEBUG_SIZE) - -#define SRAM_STREAM_BASE (SRAM_EXCEPT_BASE + SRAM_EXCEPT_SIZE) -#define SRAM_STREAM_SIZE 0x1000 -#define SRAM_STREAM_OFFSET (SRAM_EXCEPT_OFFSET + SRAM_EXCEPT_SIZE) - -#define SRAM_TRACE_BASE (SRAM_STREAM_BASE + SRAM_STREAM_SIZE) -#define SRAM_TRACE_SIZE 0x1000 -#define SRAM_TRACE_OFFSET (SRAM_STREAM_OFFSET + SRAM_STREAM_SIZE) - -#define SOF_MAILBOX_SIZE (SRAM_INBOX_SIZE + SRAM_OUTBOX_SIZE \ - + SRAM_DEBUG_SIZE + SRAM_EXCEPT_SIZE \ - + SRAM_STREAM_SIZE + SRAM_TRACE_SIZE) - -/* Heap section sizes for module pool */ -#define HEAP_RT_COUNT8 0 -#define HEAP_RT_COUNT16 48 -#define HEAP_RT_COUNT32 48 -#define HEAP_RT_COUNT64 32 -#define HEAP_RT_COUNT128 32 -#define HEAP_RT_COUNT256 32 -#define HEAP_RT_COUNT512 4 -#define HEAP_RT_COUNT1024 4 -#define HEAP_RT_COUNT2048 4 - -/* Heap section sizes for system runtime heap */ -#define HEAP_SYS_RT_COUNT64 128 -#define HEAP_SYS_RT_COUNT512 16 -#define HEAP_SYS_RT_COUNT1024 8 - -/* Heap configuration */ -#define HEAP_SYSTEM_BASE SDRAM1_BASE + SOF_MAILBOX_SIZE -#define HEAP_SYSTEM_SIZE 0xe000 - -#define HEAP_SYS_RUNTIME_BASE (HEAP_SYSTEM_BASE + HEAP_SYSTEM_SIZE) -#define HEAP_SYS_RUNTIME_SIZE \ - (HEAP_SYS_RT_COUNT64 * 64 + HEAP_SYS_RT_COUNT512 * 512 + \ - HEAP_SYS_RT_COUNT1024 * 1024) - -#define HEAP_RUNTIME_BASE (HEAP_SYS_RUNTIME_BASE + HEAP_SYS_RUNTIME_SIZE) -#define HEAP_RUNTIME_SIZE \ - (HEAP_RT_COUNT8 * 8 + HEAP_RT_COUNT16 * 16 + \ - HEAP_RT_COUNT32 * 32 + HEAP_RT_COUNT64 * 64 + \ - HEAP_RT_COUNT128 * 128 + HEAP_RT_COUNT256 * 256 + \ - HEAP_RT_COUNT512 * 512 + HEAP_RT_COUNT1024 * 1024 + \ - HEAP_RT_COUNT2048 * 2048) - -#define HEAP_BUFFER_BASE (HEAP_RUNTIME_BASE + HEAP_RUNTIME_SIZE) -#define HEAP_BUFFER_SIZE \ - (SDRAM1_SIZE - SOF_MAILBOX_SIZE - HEAP_RUNTIME_SIZE - SOF_STACK_TOTAL_SIZE -\ - HEAP_SYS_RUNTIME_SIZE - HEAP_SYSTEM_SIZE) - -/* Stack configuration */ -#define SOF_STACK_SIZE 0x1000 -#define SOF_STACK_TOTAL_SIZE SOF_STACK_SIZE -#define SOF_STACK_BASE (SDRAM1_BASE + SDRAM1_SIZE) -#define SOF_STACK_END (SOF_STACK_BASE - SOF_STACK_TOTAL_SIZE) - -/* Host page size */ -#define HOST_PAGE_SIZE 4096 - -#endif /* __INC_MEMORY_H */ diff --git a/soc/xtensa/nxp_adsp/imx8/include/soc/platform.h b/soc/xtensa/nxp_adsp/imx8/include/soc/platform.h deleted file mode 100644 index 44d8f46d1d41276..000000000000000 --- a/soc/xtensa/nxp_adsp/imx8/include/soc/platform.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2021 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __PLATFORM_PLATFORM_H__ -#define __PLATFORM_PLATFORM_H__ - -#define PLATFORM_PRIMARY_CORE_ID 0 - -#define MAX_CORE_COUNT 1 - -#if PLATFORM_CORE_COUNT > MAX_CORE_COUNT -#error "Invalid core count - exceeding core limit" -/* IPC Interrupt */ -#define PLATFORM_IPC_INTERRUPT IRQ_NUM_MU -#define PLATFORM_IPC_INTERRUPT_NAME NULL -#endif - -#endif /* __PLATFORM_PLATFORM_H__ */ diff --git a/soc/xtensa/nxp_adsp/imx8/linker.ld b/soc/xtensa/nxp_adsp/imx8/linker.ld index 599ef7339b802ec..52d3a46b2381a95 100644 --- a/soc/xtensa/nxp_adsp/imx8/linker.ld +++ b/soc/xtensa/nxp_adsp/imx8/linker.ld @@ -15,7 +15,7 @@ OUTPUT_ARCH(xtensa) #include #include -#include +#include #include #include @@ -346,7 +346,7 @@ SECTIONS .text : ALIGN(4) { _stext = .; - _text_start = ABSOLUTE(.); + __text_region_start = ABSOLUTE(.); KEEP (*(.ResetVector.text)) *(.ResetVector.literal) *(.entry.text) @@ -356,7 +356,7 @@ SECTIONS *(.fini.literal) KEEP(*(.fini)) *(.gnu.version) - _text_end = ABSOLUTE(.); + __text_region_end = ABSOLUTE(.); _etext = .; } >sdram0 :sdram0_phdr diff --git a/soc/xtensa/nxp_adsp/imx8/pinctrl_soc.h b/soc/xtensa/nxp_adsp/imx8/pinctrl_soc.h new file mode 100644 index 000000000000000..ac748220b560559 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8/pinctrl_soc.h @@ -0,0 +1,41 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_XTENSA_NXP_ADSP_IMX8_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_XTENSA_NXP_ADSP_IMX8_PINCTRL_SOC_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct pinctrl_soc_pinmux { + uint32_t pad; + uint32_t mux; +}; + +typedef struct pinctrl_soc_pinmux pinctrl_soc_pin_t; + +#define IMX8_PINMUX(n) \ +{ \ + .pad = DT_PROP_BY_IDX(n, pinmux, 0), \ + .mux = DT_PROP_BY_IDX(n, pinmux, 1), \ +}, + +#define Z_PINCTRL_PINMUX(group_id, pin_prop, idx)\ + IMX8_PINMUX(DT_PHANDLE_BY_IDX(group_id, pin_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_PINMUX) }; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_SOC_XTENSA_NXP_ADSP_IMX8_PINCTRL_SOC_H_ */ diff --git a/soc/xtensa/nxp_adsp/imx8m/Kconfig.defconfig.series b/soc/xtensa/nxp_adsp/imx8m/Kconfig.defconfig.series index 03967cb74e4336e..2d00a5e93d96f14 100644 --- a/soc/xtensa/nxp_adsp/imx8m/Kconfig.defconfig.series +++ b/soc/xtensa/nxp_adsp/imx8m/Kconfig.defconfig.series @@ -11,44 +11,27 @@ config SOC_TOOLCHAIN_NAME string default "nxp_imx8m_adsp" -# if SOC_MIMX8M_ADSP +if SOC_MIMX8M_ADSP config SOC string default "mimx8ml8" -config SMP - default n - -config XTENSA_TIMER - default y - config SYS_CLOCK_HW_CYCLES_PER_SEC default 800000000 if XTENSA_TIMER config SYS_CLOCK_TICKS_PER_SEC default 50000 -config KERNEL_ENTRY - default "__start" - -config MULTI_LEVEL_INTERRUPTS - default n - -config 2ND_LEVEL_INTERRUPTS - default n +config DCACHE_LINE_SIZE + default 128 config DYNAMIC_INTERRUPTS default y -config LOG - default y - -# To prevent test uses TEST_LOGGING_MINIMAL -config TEST_LOGGING_DEFAULTS +config GEN_IRQ_VECTOR_TABLE default n - depends on TEST -# endif # SOC_MIMX8M_ADSP +endif # SOC_MIMX8M_ADSP endif # SOC_SERIES_NXP_IMX8M diff --git a/soc/xtensa/nxp_adsp/imx8m/Kconfig.series b/soc/xtensa/nxp_adsp/imx8m/Kconfig.series index eda7d03ae5e2a85..3847f52d2dad1b8 100644 --- a/soc/xtensa/nxp_adsp/imx8m/Kconfig.series +++ b/soc/xtensa/nxp_adsp/imx8m/Kconfig.series @@ -9,5 +9,7 @@ config SOC_SERIES_NXP_IMX8M 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.MX8M Audio DSP diff --git a/soc/xtensa/nxp_adsp/imx8m/include/memory.h b/soc/xtensa/nxp_adsp/imx8m/include/memory.h new file mode 100644 index 000000000000000..e882f49a43512d4 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8m/include/memory.h @@ -0,0 +1,169 @@ +/* + * Copyright 2021, 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_NXP_ADSP_MEMORY_H_ +#define ZEPHYR_SOC_NXP_ADSP_MEMORY_H_ + +#define PLATFORM_CORE_COUNT 1 + +/** Id of master DSP core */ +#define PLATFORM_PRIMARY_CORE_ID 0 + +#define IRAM_RESERVE_HEADER_SPACE 0x400 + +#define IRAM_BASE 0x3B6F8000 +#define IRAM_SIZE 0x800 + +#define SDRAM0_BASE 0x92400000 +#define SDRAM0_SIZE 0x800000 + +#define SDRAM1_BASE 0x92C00000 +#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 0x3B6F8000 + +/* 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 0x3B6F8000 +#define IRAM_SIZE 0x800 + +#define DRAM0_BASE 0x3B6E8000 +#define DRAM0_SIZE 0x8000 + +#define DRAM1_BASE 0x3B6F0000 +#define DRAM1_SIZE 0x8000 + +#define SDRAM0_BASE 0x92400000 +#define SDRAM0_SIZE 0x800000 + +#define SDRAM1_BASE 0x92C00000 +#define SDRAM1_SIZE 0x800000 + +#define XSHAL_MU2_SIDEB_BYPASS_PADDR 0x30E70000 +#define MU_BASE XSHAL_MU2_SIDEB_BYPASS_PADDR + +#define SDMA2_BASE 0x30E10000 +#define SDMA2_SIZE 0x10000 + +#define SDMA3_BASE 0x30E00000 +#define SDMA3_SIZE 0x10000 + +#define SAI_1_BASE 0x30C10000 +#define SAI_1_SIZE 0x00010000 + +#define SAI_3_BASE 0x30C30000 +#define SAI_3_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 0x800 +#define SRAM_DEBUG_OFFSET (SRAM_INBOX_OFFSET + SRAM_INBOX_SIZE) + +#define SRAM_EXCEPT_BASE (SRAM_DEBUG_BASE + SRAM_DEBUG_SIZE) +#define SRAM_EXCEPT_SIZE 0x800 +#define SRAM_EXCEPT_OFFSET (SRAM_DEBUG_OFFSET + SRAM_DEBUG_SIZE) + +#define SRAM_STREAM_BASE (SRAM_EXCEPT_BASE + SRAM_EXCEPT_SIZE) +#define SRAM_STREAM_SIZE 0x1000 +#define SRAM_STREAM_OFFSET (SRAM_EXCEPT_OFFSET + SRAM_EXCEPT_SIZE) + +#define SRAM_TRACE_BASE (SRAM_STREAM_BASE + SRAM_STREAM_SIZE) +#define SRAM_TRACE_SIZE 0x1000 +#define SRAM_TRACE_OFFSET (SRAM_STREAM_OFFSET + SRAM_STREAM_SIZE) + +#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/imx8m/include/soc/memory.h b/soc/xtensa/nxp_adsp/imx8m/include/soc/memory.h deleted file mode 100644 index e93617addb50cd6..000000000000000 --- a/soc/xtensa/nxp_adsp/imx8m/include/soc/memory.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (c) 2021 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __INC_MEMORY_H -#define __INC_MEMORY_H - -#define PLATFORM_CORE_COUNT 1 - -/** Id of master DSP core */ -#define PLATFORM_PRIMARY_CORE_ID 0 - -#define IRAM_RESERVE_HEADER_SPACE 0x400 - -#define IRAM_BASE 0x3B6F8000 -#define IRAM_SIZE 0x800 - -#define SDRAM0_BASE 0x92400000 -#define SDRAM0_SIZE 0x800000 - -#define SDRAM1_BASE 0x92C00000 -#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 0x3B6F8000 - -/* 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 0x3B6F8000 -#define IRAM_SIZE 0x800 - -#define DRAM0_BASE 0x3B6E8000 -#define DRAM0_SIZE 0x8000 - -#define DRAM1_BASE 0x3B6F0000 -#define DRAM1_SIZE 0x8000 - -#define SDRAM0_BASE 0x92400000 -#define SDRAM0_SIZE 0x800000 - -#define SDRAM1_BASE 0x92C00000 -#define SDRAM1_SIZE 0x800000 - -#define XSHAL_MU2_SIDEB_BYPASS_PADDR 0x30E70000 -#define MU_BASE XSHAL_MU2_SIDEB_BYPASS_PADDR - -#define SDMA2_BASE 0x30E10000 -#define SDMA2_SIZE 0x10000 - -#define SDMA3_BASE 0x30E00000 -#define SDMA3_SIZE 0x10000 - -#define SAI_1_BASE 0x30C10000 -#define SAI_1_SIZE 0x00010000 - -#define SAI_3_BASE 0x30C30000 -#define SAI_3_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 0x800 -#define SRAM_DEBUG_OFFSET (SRAM_INBOX_OFFSET + SRAM_INBOX_SIZE) - -#define SRAM_EXCEPT_BASE (SRAM_DEBUG_BASE + SRAM_DEBUG_SIZE) -#define SRAM_EXCEPT_SIZE 0x800 -#define SRAM_EXCEPT_OFFSET (SRAM_DEBUG_OFFSET + SRAM_DEBUG_SIZE) - -#define SRAM_STREAM_BASE (SRAM_EXCEPT_BASE + SRAM_EXCEPT_SIZE) -#define SRAM_STREAM_SIZE 0x1000 -#define SRAM_STREAM_OFFSET (SRAM_EXCEPT_OFFSET + SRAM_EXCEPT_SIZE) - -#define SRAM_TRACE_BASE (SRAM_STREAM_BASE + SRAM_STREAM_SIZE) -#define SRAM_TRACE_SIZE 0x1000 -#define SRAM_TRACE_OFFSET (SRAM_STREAM_OFFSET + SRAM_STREAM_SIZE) - -#define SOF_MAILBOX_SIZE (SRAM_INBOX_SIZE + SRAM_OUTBOX_SIZE \ - + SRAM_DEBUG_SIZE + SRAM_EXCEPT_SIZE \ - + SRAM_STREAM_SIZE + SRAM_TRACE_SIZE) - -/* Heap section sizes for module pool */ -#define HEAP_RT_COUNT8 0 -#define HEAP_RT_COUNT16 48 -#define HEAP_RT_COUNT32 48 -#define HEAP_RT_COUNT64 32 -#define HEAP_RT_COUNT128 32 -#define HEAP_RT_COUNT256 32 -#define HEAP_RT_COUNT512 4 -#define HEAP_RT_COUNT1024 4 -#define HEAP_RT_COUNT2048 4 -#define HEAP_RT_COUNT4096 4 - -/* Heap section sizes for system runtime heap */ -#define HEAP_SYS_RT_COUNT64 128 -#define HEAP_SYS_RT_COUNT512 16 -#define HEAP_SYS_RT_COUNT1024 8 - -/* Heap configuration */ -#define HEAP_SYSTEM_BASE SDRAM1_BASE + SOF_MAILBOX_SIZE -#define HEAP_SYSTEM_SIZE 0xe000 -#define HEAP_SYSTEM_0_BASE HEAP_SYSTEM_BASE - -#define HEAP_SYS_RUNTIME_BASE (HEAP_SYSTEM_BASE + HEAP_SYSTEM_SIZE) -#define HEAP_SYS_RUNTIME_SIZE \ - (HEAP_SYS_RT_COUNT64 * 64 + HEAP_SYS_RT_COUNT512 * 512 + \ - HEAP_SYS_RT_COUNT1024 * 1024) - -#define HEAP_RUNTIME_BASE (HEAP_SYS_RUNTIME_BASE + HEAP_SYS_RUNTIME_SIZE) -#define HEAP_RUNTIME_SIZE \ - (HEAP_RT_COUNT8 * 8 + HEAP_RT_COUNT16 * 16 + \ - HEAP_RT_COUNT32 * 32 + HEAP_RT_COUNT64 * 64 + \ - HEAP_RT_COUNT128 * 128 + HEAP_RT_COUNT256 * 256 + \ - HEAP_RT_COUNT512 * 512 + HEAP_RT_COUNT1024 * 1024 + \ - HEAP_RT_COUNT2048 * 2048 + HEAP_RT_COUNT4096 * 4096) - -#define HEAP_BUFFER_BASE (HEAP_RUNTIME_BASE + HEAP_RUNTIME_SIZE) -#define HEAP_BUFFER_SIZE \ - (SDRAM1_SIZE - SOF_MAILBOX_SIZE - HEAP_RUNTIME_SIZE - SOF_STACK_TOTAL_SIZE -\ - HEAP_SYS_RUNTIME_SIZE - HEAP_SYSTEM_SIZE) - -/* Stack configuration */ -#define SOF_STACK_SIZE 0x1000 -#define SOF_STACK_TOTAL_SIZE SOF_STACK_SIZE -#define SOF_STACK_BASE (SDRAM1_BASE + SDRAM1_SIZE) -#define SOF_STACK_END (SOF_STACK_BASE - SOF_STACK_TOTAL_SIZE) - -/* Host page size */ -#define HOST_PAGE_SIZE 4096 - -#endif /* __INC_MEMORY_H */ diff --git a/soc/xtensa/nxp_adsp/imx8m/include/soc/platform.h b/soc/xtensa/nxp_adsp/imx8m/include/soc/platform.h deleted file mode 100644 index 2af652c0cc875d6..000000000000000 --- a/soc/xtensa/nxp_adsp/imx8m/include/soc/platform.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2021 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __PLATFORM_PLATFORM_H__ -#define __PLATFORM_PLATFORM_H__ - -#define PLATFORM_PRIMARY_CORE_ID 0 - -#define MAX_CORE_COUNT 1 - -#if PLATFORM_CORE_COUNT > MAX_CORE_COUNT -#error "Invalid core count - exceeding core limit" -/* IPC Interrupt */ -#define PLATFORM_IPC_INTERRUPT IRQ_NUM_MU -#define PLATFORM_IPC_INTERRUPT_NAME NULL -#endif - -#endif /* __PLATFORM_PLATFORM_H__ */ diff --git a/soc/xtensa/nxp_adsp/imx8m/linker.ld b/soc/xtensa/nxp_adsp/imx8m/linker.ld index aab0a0b6548fc1e..9687b604d6c5435 100644 --- a/soc/xtensa/nxp_adsp/imx8m/linker.ld +++ b/soc/xtensa/nxp_adsp/imx8m/linker.ld @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 NXP + * Copyright 2021, 2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,7 +15,7 @@ OUTPUT_ARCH(xtensa) #include #include -#include +#include #include #include @@ -352,7 +352,7 @@ SECTIONS .text : ALIGN(4) { _stext = .; - _text_start = ABSOLUTE(.); + __text_region_start = ABSOLUTE(.); KEEP (*(.ResetVector.text)) *(.ResetVector.literal) *(.entry.text) @@ -362,7 +362,7 @@ SECTIONS *(.fini.literal) KEEP(*(.fini)) *(.gnu.version) - _text_end = ABSOLUTE(.); + __text_region_end = ABSOLUTE(.); _etext = .; } >sdram0 :sdram0_phdr @@ -415,6 +415,11 @@ SECTIONS #include + /* Used for C++ build */ + .tm_clone_table : { + *(.tm_clone_table) + } >sdram0 :sdram0_phdr + .bss (NOLOAD) : ALIGN(8) { . = ALIGN (8); @@ -448,6 +453,8 @@ SECTIONS _end = ALIGN (8); PROVIDE(end = ALIGN (8)); + /* Mostly unused, though newlib likes them */ + _heap_sentry = .; __stack = SDRAM1_BASE + SDRAM1_SIZE; .comment 0 : { *(.comment) } .debug 0 : { *(.debug) } @@ -520,4 +527,6 @@ SECTIONS KEEP (*(.fw_metadata)) . = ALIGN(_EXT_MAN_ALIGN_); } >fw_metadata_seg :metadata_entries_phdr + + #include } 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 000000000000000..ebd9377660b018b --- /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 000000000000000..34e9b3a1a1dbc38 --- /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 000000000000000..b90fada22d4a4fd --- /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 000000000000000..28129b6575816e1 --- /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 000000000000000..d6384477e71e490 --- /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 000000000000000..4b5aec29742a732 --- /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/soc/xtensa/nxp_adsp/rt5xx/Kconfig.defconfig.series b/soc/xtensa/nxp_adsp/rt5xx/Kconfig.defconfig.series new file mode 100644 index 000000000000000..b5a56658c7da20a --- /dev/null +++ b/soc/xtensa/nxp_adsp/rt5xx/Kconfig.defconfig.series @@ -0,0 +1,46 @@ +# Copyright (c) 2023 Google LLC. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_NXP_RT5XX + +config SOC_SERIES + string + default "rt5xx" + +config SOC_TOOLCHAIN_NAME + string + default "nxp_rt500_adsp" + +config SOC + string + default "nxp_rt5xx" + +config SOC_PART_NUMBER + string + default "MIMXRT595SFFOC_dsp" if SOC_NXP_RT595 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 198000000 + +config XTENSA_CCOUNT_HZ + default SYS_CLOCK_HW_CYCLES_PER_SEC + +config SYS_CLOCK_TICKS_PER_SEC + default 1000 + +config DYNAMIC_INTERRUPTS + default n + +config CACHE + default n + +config DCACHE + default n + +config CACHE_MANAGEMENT + default n + +config LOG + default n + +endif # SOC_SERIES_NXP_RT5XX diff --git a/soc/xtensa/nxp_adsp/rt5xx/Kconfig.series b/soc/xtensa/nxp_adsp/rt5xx/Kconfig.series new file mode 100644 index 000000000000000..5135b881638a365 --- /dev/null +++ b/soc/xtensa/nxp_adsp/rt5xx/Kconfig.series @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Google LLC. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_NXP_RT5XX + bool "NXP RT5xx 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 + help + NXP RT5xx ADSP Series diff --git a/soc/xtensa/nxp_adsp/rt5xx/Kconfig.soc b/soc/xtensa/nxp_adsp/rt5xx/Kconfig.soc new file mode 100644 index 000000000000000..e5b598c4f57089d --- /dev/null +++ b/soc/xtensa/nxp_adsp/rt5xx/Kconfig.soc @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Google LLC. +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "NXP RT5xx ADSP SoC Selection" + + config SOC_NXP_RT595 + bool "NXP RT595" + depends on SOC_SERIES_NXP_RT5XX +endchoice diff --git a/soc/xtensa/nxp_adsp/rt5xx/include/_soc_inthandlers.h b/soc/xtensa/nxp_adsp/rt5xx/include/_soc_inthandlers.h new file mode 100644 index 000000000000000..0919a03d9ce16c4 --- /dev/null +++ b/soc/xtensa/nxp_adsp/rt5xx/include/_soc_inthandlers.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2023 Google LLC. + * SPDX-License-Identifier: Apache-2.0 + */ + +#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_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 != 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_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 +#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_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 + +/* + * Interrupt masks for every level (RT595 ADSP): + * XCHAL_INTLEVEL1_MASK: 0x0000FFE0 + * XCHAL_INTLEVEL2_MASK: 0x00FF0006 + * XCHAL_INTLEVEL3_MASK: 0xFF000018 + * XCHAL_INTLEVEL4_MASK: 0x00000000 + * XCHAL_INTLEVEL5_MASK: 0x00000001 + */ + +static inline int _xtensa_handle_one_int1(unsigned int mask) +{ + int irq; + + mask &= XCHAL_INTLEVEL1_MASK; + for (int i = 5; i <= 31; i++) { + if (mask & BIT(i)) { + mask = BIT(i); + irq = i; + 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; + + mask &= XCHAL_INTLEVEL2_MASK; + for (int i = 1; i <= 31; i++) { + if (mask & BIT(i)) { + mask = BIT(i); + irq = i; + 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; + + mask &= XCHAL_INTLEVEL3_MASK; + for (int i = 3; i <= 31; i++) { + if (mask & BIT(i)) { + mask = BIT(i); + irq = i; + 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) +{ + return 0; +} + +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; +} diff --git a/soc/xtensa/nxp_adsp/rt5xx/include/soc/memory.h b/soc/xtensa/nxp_adsp/rt5xx/include/soc/memory.h new file mode 100644 index 000000000000000..af9e1888e1ca5d5 --- /dev/null +++ b/soc/xtensa/nxp_adsp/rt5xx/include/soc/memory.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Google LLC. + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#define IRAM_BASE (CONFIG_RT595_ADSP_TEXT_MEM_ADDR) +#define IRAM_SIZE (CONFIG_RT595_ADSP_TEXT_MEM_SIZE) + +#define SDRAM0_BASE (CONFIG_RT595_ADSP_DATA_MEM_ADDR) +#define SDRAM0_SIZE (CONFIG_RT595_ADSP_DATA_MEM_SIZE - CONFIG_RT595_ADSP_STACK_SIZE) + +/* The reset vector address in SRAM and its size. */ +#define XCHAL_RESET_VECTOR0_PADDR_IRAM (CONFIG_RT595_ADSP_RESET_MEM_ADDR) +#define MEM_RESET_TEXT_SIZE (0x2e0) +#define MEM_RESET_LIT_SIZE (0x120) + +/* Base address of all interrupt vectors in IRAM. */ +#define XCHAL_VECBASE_RESET_PADDR_IRAM (IRAM_BASE) +#define MEM_VECBASE_LIT_SIZE (0x178) + +/* Vector and literal sizes. */ +#define MEM_VECT_LIT_SIZE (0x4) +#define MEM_VECT_TEXT_SIZE (0x1C) + +/* Addresses of the interrupt vectors. */ +#define XCHAL_INT_VECTOR_ADDR(x) (XCHAL_VECBASE_RESET_PADDR_IRAM + (x)) +#define XCHAL_INTLEVEL2_VECTOR_PADDR_IRAM (XCHAL_INT_VECTOR_ADDR(0x17C)) +#define XCHAL_INTLEVEL3_VECTOR_PADDR_IRAM (XCHAL_INT_VECTOR_ADDR(0x19C)) +#define XCHAL_INTLEVEL4_VECTOR_PADDR_IRAM (XCHAL_INT_VECTOR_ADDR(0x1BC)) +#define XCHAL_INTLEVEL5_VECTOR_PADDR_IRAM (XCHAL_INT_VECTOR_ADDR(0x1DC)) +#define XCHAL_KERNEL_VECTOR_PADDR_IRAM (XCHAL_INT_VECTOR_ADDR(0x1FC)) +#define XCHAL_USER_VECTOR_PADDR_IRAM (XCHAL_INT_VECTOR_ADDR(0x21C)) +#define XCHAL_DOUBLEEXC_VECTOR_PADDR_IRAM (XCHAL_INT_VECTOR_ADDR(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) diff --git a/soc/xtensa/nxp_adsp/rt5xx/linker.ld b/soc/xtensa/nxp_adsp/rt5xx/linker.ld new file mode 100644 index 000000000000000..adc8b87fb621361 --- /dev/null +++ b/soc/xtensa/nxp_adsp/rt5xx/linker.ld @@ -0,0 +1,464 @@ +/* + * Copyright (c) 2021 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +OUTPUT_ARCH(xtensa) + +#include +#include + +#include +#include +#include + +#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 +#ifdef CONFIG_GEN_ISR_TABLES + IDT_LIST : + org = IDT_BASE, + len = IDT_SIZE +#endif +} + +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; +} + +PROVIDE(_memmap_reset_vector = XCHAL_RESET_VECTOR0_PADDR_IRAM); +PROVIDE(_memmap_vecbase_reset = XCHAL_VECBASE_RESET_PADDR_IRAM); + +ENTRY(CONFIG_KERNEL_ENTRY) + +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000012; +_memmap_cacheattr_wt_base = 0x00000012; +_memmap_cacheattr_bp_base = 0x00000022; +_memmap_cacheattr_unused_mask = 0xFFFFFF00; +_memmap_cacheattr_wb_trapnull = 0x22222212; +_memmap_cacheattr_wba_trapnull = 0x22222212; +_memmap_cacheattr_wbna_trapnull = 0x22222212; +_memmap_cacheattr_wt_trapnull = 0x22222212; +_memmap_cacheattr_bp_trapnull = 0x22222222; +_memmap_cacheattr_wb_strict = 0xFFFFFF12; +_memmap_cacheattr_wt_strict = 0xFFFFFF12; +_memmap_cacheattr_bp_strict = 0xFFFFFF22; +_memmap_cacheattr_wb_allvalid = 0x22222212; +_memmap_cacheattr_wt_allvalid = 0x22222212; +_memmap_cacheattr_bp_allvalid = 0x22222222; +_memmap_region_map = 0x00000003; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +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_region_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_region_end = ABSOLUTE(.); + _etext = .; + } >iram_text_start :iram_text_start_phdr + +#include + + .fw_ready : ALIGN(4) + { + KEEP(*(".fw_ready")); + KEEP (*(.fw_ready_metadata)) + } >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 + + .noinit (NOLOAD) : ALIGN(4) + { + *(.noinit) + *(.noinit.*) + } >sdram0 :sdram0_phdr + + .heap_mem (NOLOAD) : ALIGN(8) + { + . = ALIGN (8); + _heap_mem_start = ABSOLUTE(.); + *(*.heap_mem) + _heap_mem_end = ABSOLUTE(.); + + } >sdram0 :sdram0_phdr + + /* stack */ + _end = ALIGN (8); + + /DISCARD/ : { *(.note.GNU-stack) } + _heap_sentry = SDRAM0_BASE + SDRAM0_SIZE; + __stack = SDRAM0_BASE + SDRAM0_SIZE + CONFIG_RT595_ADSP_STACK_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 +} diff --git a/soc/xtensa/sample_controller/CMakeLists.txt b/soc/xtensa/sample_controller/CMakeLists.txt index 1097b991ed2c04f..20e40128eeb14c5 100644 --- a/soc/xtensa/sample_controller/CMakeLists.txt +++ b/soc/xtensa/sample_controller/CMakeLists.txt @@ -1,3 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# intentionally left empty +zephyr_include_directories(include) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/include/xtensa-sample-controller.ld CACHE INTERNAL "") diff --git a/soc/xtensa/sample_controller/linker.ld b/soc/xtensa/sample_controller/linker.ld deleted file mode 100644 index 08639c8908b4b11..000000000000000 --- a/soc/xtensa/sample_controller/linker.ld +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (c) 2016 Cadence Design Systems, Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * Linker script for the Xtensa platform. - */ -#include diff --git a/submanifests/optional.yaml b/submanifests/optional.yaml index ef40d0201fb5a08..a15d0fd6be5ab29 100644 --- a/submanifests/optional.yaml +++ b/submanifests/optional.yaml @@ -3,8 +3,14 @@ manifest: - name: upstream url-base: https://github.com/zephyrproject-rtos projects: + - name: canopennode + revision: dec12fa3f0d790cafa8414a4c2930ea71ab72ffd + path: modules/lib/canopennode + remote: upstream + groups: + - optional - name: chre - revision: b7955c27e50485b7dafdc3888d7d6afdc2ac6d96 + revision: 3b32c76efee705af146124fb4190f71be5a4e36e path: modules/lib/chre remote: upstream groups: @@ -22,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: c0f20b69daa44e3563f970b366e49ccfcfa1b71c + revision: 7a0ff76e05cab6b1d99767258680a7b8711dd476 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: @@ -54,7 +60,7 @@ manifest: - optional - name: zscilib path: modules/lib/zscilib - revision: 34c3432e81085bb717e4871d21ca419ae0058ec5 + revision: a4bb6cfd6800e14373261904825f7f34a3a7f2e5 remote: upstream groups: - optional diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index bef01e0f24a73d0..ccd2c8c88bff70d 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -11,6 +11,7 @@ add_subdirectory_ifdef(CONFIG_LORAWAN lorawan) # FIXME: SHADOW_VARS: Remove this once we have enabled -Wshadow globally. add_compile_options($) +# zephyr-keep-sorted-start add_subdirectory(canbus) add_subdirectory(debug) add_subdirectory(fb) @@ -32,6 +33,7 @@ add_subdirectory(testsuite) add_subdirectory(tracing) add_subdirectory(usb) +add_subdirectory_ifdef(CONFIG_ARM_SIP_SVC_SUBSYS sip_svc) add_subdirectory_ifdef(CONFIG_BINDESC bindesc) add_subdirectory_ifdef(CONFIG_BT bluetooth) add_subdirectory_ifdef(CONFIG_CONSOLE_SUBSYS console) @@ -42,8 +44,8 @@ add_subdirectory_ifdef(CONFIG_EMUL emul) add_subdirectory_ifdef(CONFIG_IMG_MANAGER dfu) add_subdirectory_ifdef(CONFIG_INPUT input) add_subdirectory_ifdef(CONFIG_JWT jwt) -add_subdirectory_ifdef(CONFIG_MODEM_MODULES modem) add_subdirectory_ifdef(CONFIG_LLEXT llext) +add_subdirectory_ifdef(CONFIG_MODEM_MODULES modem) add_subdirectory_ifdef(CONFIG_NET_BUF net) add_subdirectory_ifdef(CONFIG_RETENTION retention) add_subdirectory_ifdef(CONFIG_SENSING sensing) @@ -51,4 +53,4 @@ add_subdirectory_ifdef(CONFIG_SETTINGS settings) add_subdirectory_ifdef(CONFIG_SHELL shell) add_subdirectory_ifdef(CONFIG_TIMING_FUNCTIONS timing) add_subdirectory_ifdef(CONFIG_ZBUS zbus) -add_subdirectory_ifdef(CONFIG_ARM_SIP_SVC_SUBSYS sip_svc) +# zephyr-keep-sorted-stop diff --git a/subsys/Kconfig b/subsys/Kconfig index e4fa9212ab04255..2e083fb4c89cd5c 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -6,6 +6,7 @@ menu "Subsystems and OS Services" +# zephyr-keep-sorted-start source "subsys/bindesc/Kconfig" source "subsys/bluetooth/Kconfig" source "subsys/canbus/Kconfig" @@ -38,6 +39,7 @@ source "subsys/sd/Kconfig" source "subsys/sensing/Kconfig" source "subsys/settings/Kconfig" source "subsys/shell/Kconfig" +source "subsys/sip_svc/Kconfig" source "subsys/stats/Kconfig" source "subsys/storage/Kconfig" source "subsys/task_wdt/Kconfig" @@ -49,6 +51,16 @@ source "subsys/usb/device_next/Kconfig" source "subsys/usb/host/Kconfig" source "subsys/usb/usb_c/Kconfig" source "subsys/zbus/Kconfig" -source "subsys/sip_svc/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/bindesc/CMakeLists.txt b/subsys/bindesc/CMakeLists.txt index 7419a78e5a9b73b..9dcb467208d923c 100644 --- a/subsys/bindesc/CMakeLists.txt +++ b/subsys/bindesc/CMakeLists.txt @@ -66,7 +66,7 @@ if(CONFIG_BINDESC_DEFINE_BUILD_TIME) bindesc_time_force_rebuild COMMAND ${CMAKE_COMMAND} ${CMAKE_BINARY_DIR} ) - add_dependencies(${ZEPHYR_CURRENT_LIBRARY} bindesc_time_force_rebuild) + zephyr_library_add_dependencies(bindesc_time_force_rebuild) endif() endif() diff --git a/subsys/bindesc/Kconfig b/subsys/bindesc/Kconfig index 0f55564d46063e9..e8c158b8c84f515 100644 --- a/subsys/bindesc/Kconfig +++ b/subsys/bindesc/Kconfig @@ -3,7 +3,7 @@ menuconfig BINDESC bool "Binary Descriptors" - depends on ARCH_SUPPORTS_ROM_START || BOARD_NATIVE_POSIX + depends on ARCH_SUPPORTS_ROM_START || ARCH_POSIX help Binary Descriptors - constant data accessible outside of the executable image diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index e02901cd90661d2..c8f71afb2074daa 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 @@ -175,6 +175,14 @@ config BT_SCA_UPDATE depends on !BT_CTLR || BT_CTLR_SCA_UPDATE_SUPPORT help Enable support for Bluetooth 5.1 Sleep Clock Accuracy Update Procedure + +config BT_TRANSMIT_POWER_CONTROL + bool "LE Power Control" + depends on !BT_CTLR || BT_CTLR_LE_POWER_CONTROL_SUPPORT + help + Enable support for LE Power Control Request feature that is defined in the + Bluetooth Core specification, Version 5.4 | Vol 6, Part B, Section 4.6.31. + endif # BT_CONN rsource "Kconfig.iso" diff --git a/subsys/bluetooth/Kconfig.iso b/subsys/bluetooth/Kconfig.iso index 304c408f42f5a32..0fc4be1401b9976 100644 --- a/subsys/bluetooth/Kconfig.iso +++ b/subsys/bluetooth/Kconfig.iso @@ -120,8 +120,8 @@ config BT_ISO_RX_MTU This is the actual data payload. It doesn't include the optional HCI ISO Data packet fields (e.g. `struct bt_hci_iso_ts_data_hdr`) -config BT_ISO_ADVANCED - bool "Advanced ISO parameters" +config BT_ISO_TEST_PARAMS + bool "ISO test parameters support" help Enabling advanced ISO parameters will allow the use of the ISO test parameters for creating a CIG or a BIG. These test parameters were diff --git a/subsys/bluetooth/Kconfig.logging b/subsys/bluetooth/Kconfig.logging index addf8eb65fe0e8c..c103a42c31656ec 100644 --- a/subsys/bluetooth/Kconfig.logging +++ b/subsys/bluetooth/Kconfig.logging @@ -469,56 +469,56 @@ config BT_MESH_DEBUG_NET select DEPRECATED help Use this option to enable Network layer debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_RPL bool "[DEPRECATED] Replay protection list debug" select DEPRECATED help Use this option to enable Replay protection list debug logs - for the Bluetooth mesh functionality. + for the Bluetooth Mesh functionality. config BT_MESH_DEBUG_TRANS bool "[DEPRECATED] Transport layer debug" select DEPRECATED help Use this option to enable Transport layer debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_BEACON bool "[DEPRECATED] Beacon debug" select DEPRECATED help Use this option to enable Beacon-related debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_CRYPTO bool "[DEPRECATED] Crypto debug" select DEPRECATED help Use this option to enable cryptographic debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_KEYS bool "[DEPRECATED] Key management debug" select DEPRECATED help Use this option to enable key management debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_PROV bool "[DEPRECATED] Provisioning debug" select DEPRECATED help Use this option to enable Provisioning debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_PROVISIONER bool "[DEPRECATED] Provisioner debug" select DEPRECATED help Use this option to enable Provisioner debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_PROV_DEVICE bool "[DEPRECATED] Provisioning device debug" @@ -532,7 +532,7 @@ config BT_MESH_DEBUG_ACCESS select DEPRECATED help Use this option to enable Access layer and device composition - related debug logs for Bluetooth mesh. + related debug logs for Bluetooth Mesh. config BT_MESH_DEBUG_MODEL bool "[DEPRECATED] Foundation model debug" @@ -546,21 +546,21 @@ config BT_MESH_DEBUG_ADV select DEPRECATED help Use this option to enable advertising debug logs for - the Bluetooth mesh functionality. + the Bluetooth Mesh functionality. config BT_MESH_DEBUG_LOW_POWER bool "[DEPRECATED] Low Power debug" select DEPRECATED help Use this option to enable Low Power debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_FRIEND bool "[DEPRECATED] Friend debug" select DEPRECATED help Use this option to enable Friend debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. config BT_MESH_DEBUG_PROXY bool "[DEPRECATED] Proxy debug" @@ -588,7 +588,7 @@ config BT_MESH_DEBUG_CFG select DEPRECATED help Use this option to enable node configuration debug logs for the - Bluetooth mesh functionality. + Bluetooth Mesh functionality. endmenu # [DEPRECATED] Mesh @@ -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" @@ -716,6 +721,16 @@ legacy-debug-sym = BT_DEBUG_CAP_INITIATOR module-str = "Common Audio Profile Initiator" source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +parent-module = BT +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" @@ -831,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" @@ -997,7 +1018,7 @@ legacy-debug-sym = BT_MESH_DEBUG_PROVISIONER module-str = "Provisioner" source "subsys/bluetooth/common/Kconfig.template.log_config_bt" -module = BT_MESH_PROV_DEVICE +module = BT_MESH_PROVISIONEE legacy-debug-sym = BT_MESH_DEBUG_PROV_DEVICE module-str = "Provisioning device" source "subsys/bluetooth/common/Kconfig.template.log_config_bt" diff --git a/subsys/bluetooth/audio/CMakeLists.txt b/subsys/bluetooth/audio/CMakeLists.txt index 8f24c50233b62b6..293498fbd404a1d 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) @@ -60,4 +61,10 @@ zephyr_library_sources_ifdef(CONFIG_BT_HAS_CLIENT has_client.c) 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 7e7bbfd09516e63..b60475c02e26611 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 64c07ca60d7c2b9..6921cf2c8c06d90 100644 --- a/subsys/bluetooth/audio/Kconfig.bap +++ b/subsys/bluetooth/audio/Kconfig.bap @@ -277,5 +277,17 @@ config BT_BAP_STREAM default y if BT_ASCS || BT_BAP_UNICAST_CLIENT || \ BT_BAP_BROADCAST_SOURCE || BT_BAP_BROADCAST_SINK +config BT_BAP_DEBUG_STREAM_SEQ_NUM + bool "Bluetooth Audio Stream sequence number debug" + depends on BT_BAP_STREAM_LOG_LEVEL >= BT_BAP_STREAM_LOG_LEVEL_WRN + default y + help + Use this option to enable Bluetooth Audio Stream sequence number debugging logs for + 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 9fdc1506c3d1322..2a130f53d9a61bd 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 @@ -35,3 +38,16 @@ config BT_CAP_INITIATOR select EXPERIMENTAL help Enabling this will enable the CAP Initiator role. + + +config BT_CAP_COMMANDER + bool "Common Audio Profile Initiator Role Support [EXPERIMENTAL]" + depends on (BT_BAP_BROADCAST_ASSISTANT && BT_BAP_SCAN_DELEGATOR && BT_CSIP_SET_COORDINATOR) || \ + (BT_BAP_SCAN_DELEGATOR && BT_CSIP_SET_COORDINATOR) || \ + (BT_VCP_VOL_CTLR && BT_CSIP_SET_COORDINATOR) || \ + (BT_MICP_MIC_CTLR && BT_CSIP_SET_COORDINATOR) || \ + BT_TBS_CLIENT || \ + BT_MCC + select EXPERIMENTAL + help + Enabling this will enable the CAP Initiator role. diff --git a/subsys/bluetooth/audio/Kconfig.gmap b/subsys/bluetooth/audio/Kconfig.gmap new file mode 100644 index 000000000000000..a9bd3024aa36661 --- /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.pbp b/subsys/bluetooth/audio/Kconfig.pbp new file mode 100644 index 000000000000000..cb24845b202b752 --- /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 f4ff95cac06d960..1e42cc73da52dff 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/ascs.c b/subsys/bluetooth/audio/ascs.c index 94cff37f6b71ab8..229eb90edb8904a 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -61,7 +61,7 @@ static struct bt_ascs_ase { struct bt_bap_ep ep; const struct bt_gatt_attr *attr; struct k_work_delayable disconnect_work; - struct k_work state_transition_work; + struct k_work_delayable state_transition_work; enum bt_bap_ep_state state_pending; bool unexpected_iso_link_loss; } ase_pool[CONFIG_BT_ASCS_MAX_ACTIVE_ASES]; @@ -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); @@ -124,56 +170,51 @@ static void ase_free(struct bt_ascs_ase *ase) bt_conn_unref(ase->conn); ase->conn = NULL; - (void)k_work_cancel(&ase->state_transition_work); + (void)k_work_cancel_delayable(&ase->disconnect_work); + (void)k_work_cancel_delayable(&ase->state_transition_work); } -static void ase_status_changed(struct bt_ascs_ase *ase, uint8_t state) +static int ase_state_notify(struct bt_ascs_ase *ase) { + const uint8_t att_ntf_header_size = 3; /* opcode (1) + handle (2) */ struct bt_conn *conn = ase->conn; + struct bt_conn_info conn_info; + uint16_t max_ntf_size; + uint16_t ntf_size; + int err; - LOG_DBG("ase %p id 0x%02x %s -> %s", ase, ase->ep.status.id, - bt_bap_ep_state_str(ascs_ep_get_state(&ase->ep)), bt_bap_ep_state_str(state)); - - ase->ep.status.state = state; + __ASSERT_NO_MSG(conn != NULL); - if (conn != NULL) { - struct bt_conn_info conn_info; - int err; + err = bt_conn_get_info(conn, &conn_info); + __ASSERT_NO_MSG(err == 0); - err = bt_conn_get_info(conn, &conn_info); - if (err != 0) { - LOG_ERR("Failed to get conn %p info: %d", (void *)conn, err); + if (conn_info.state != BT_CONN_STATE_CONNECTED || + !bt_gatt_is_subscribed(conn, ase->attr, BT_GATT_CCC_NOTIFY)) { + return 0; + } - return; - } + err = k_sem_take(&ase_buf_sem, ASE_BUF_SEM_TIMEOUT); + if (err != 0) { + LOG_WRN("Failed to take ase_buf_sem: %d", err); - if (conn_info.state == BT_CONN_STATE_CONNECTED && - bt_gatt_is_subscribed(conn, ase->attr, BT_GATT_CCC_NOTIFY)) { - const uint8_t att_ntf_header_size = 3; /* opcode (1) + handle (2) */ - const uint16_t max_ntf_size = bt_gatt_get_mtu(conn) - att_ntf_header_size; - uint16_t ntf_size; + return err; + } - err = k_sem_take(&ase_buf_sem, ASE_BUF_SEM_TIMEOUT); - if (err != 0) { - LOG_DBG("Failed to take ase_buf_sem: %d", err); + ascs_ep_get_status(&ase->ep, &ase_buf); - return; - } + max_ntf_size = bt_gatt_get_mtu(conn) - att_ntf_header_size; - ascs_ep_get_status(&ase->ep, &ase_buf); + ntf_size = MIN(max_ntf_size, ase_buf.len); + if (ntf_size < ase_buf.len) { + LOG_DBG("Sending truncated notification (%u / %u)", + ntf_size, ase_buf.len); + } - ntf_size = MIN(max_ntf_size, ase_buf.len); - if (ntf_size < ase_buf.len) { - LOG_DBG("Sending truncated notification (%u / %u)", - ntf_size, ase_buf.len); - } + err = bt_gatt_notify(conn, ase->attr, ase_buf.data, ntf_size); - err = bt_gatt_notify(conn, ase->attr, ase_buf.data, ntf_size); - __ASSERT_NO_MSG(err == 0); + k_sem_give(&ase_buf_sem); - k_sem_give(&ase_buf_sem); - } - } + return err; } static void ascs_disconnect_stream_work_handler(struct k_work *work) @@ -243,7 +284,7 @@ static int ascs_disconnect_stream(struct bt_bap_stream *stream) K_MSEC(CONFIG_BT_ASCS_ISO_DISCONNECT_DELAY)); } -static void ase_set_state_idle(struct bt_ascs_ase *ase) +static void ase_enter_state_idle(struct bt_ascs_ase *ase) { struct bt_bap_stream *stream = ase->ep.stream; struct bt_bap_stream_ops *ops; @@ -252,8 +293,6 @@ static void ase_set_state_idle(struct bt_ascs_ase *ase) ase->ep.receiver_ready = false; - ase_status_changed(ase, BT_BAP_EP_STATE_IDLE); - if (stream->conn != NULL) { bt_conn_unref(stream->conn); stream->conn = NULL; @@ -267,7 +306,7 @@ static void ase_set_state_idle(struct bt_ascs_ase *ase) ase_free(ase); } -static void ase_set_state_codec_configured(struct bt_ascs_ase *ase) +static void ase_enter_state_codec_configured(struct bt_ascs_ase *ase) { struct bt_bap_stream *stream = ase->ep.stream; struct bt_bap_stream_ops *ops; @@ -276,15 +315,13 @@ static void ase_set_state_codec_configured(struct bt_ascs_ase *ase) ase->ep.receiver_ready = false; - ase_status_changed(ase, BT_BAP_EP_STATE_CODEC_CONFIGURED); - ops = stream->ops; if (ops != NULL && ops->configured != NULL) { ops->configured(stream, &ase->ep.qos_pref); } } -static void ase_set_state_qos_configured(struct bt_ascs_ase *ase) +static void ase_enter_state_qos_configured(struct bt_ascs_ase *ase) { struct bt_bap_stream *stream = ase->ep.stream; struct bt_bap_stream_ops *ops; @@ -293,29 +330,22 @@ static void ase_set_state_qos_configured(struct bt_ascs_ase *ase) ase->ep.receiver_ready = false; - ase_status_changed(ase, BT_BAP_EP_STATE_QOS_CONFIGURED); - ops = stream->ops; if (ops != NULL && ops->qos_set != NULL) { ops->qos_set(stream); } } -static void ase_set_state_enabling(struct bt_ascs_ase *ase) +static void ase_enter_state_enabling(struct bt_ascs_ase *ase) { - const bool state_changed = ascs_ep_get_state(&ase->ep) != BT_BAP_EP_STATE_ENABLING; struct bt_bap_stream *stream = ase->ep.stream; struct bt_bap_stream_ops *ops; __ASSERT_NO_MSG(stream != NULL); - ase_status_changed(ase, BT_BAP_EP_STATE_ENABLING); - ops = stream->ops; - if (state_changed && ops != NULL && ops->enabled != NULL) { + if (ops != NULL && ops->enabled != NULL) { ops->enabled(stream); - } else if (!state_changed && ops != NULL && ops->metadata_updated != NULL) { - ops->metadata_updated(stream); } /* SINK ASEs can autonomously go into the streaming state if the CIS is connected */ @@ -325,34 +355,99 @@ static void ase_set_state_enabling(struct bt_ascs_ase *ase) } } -static void ase_set_state_streaming(struct bt_ascs_ase *ase) +static void ase_enter_state_streaming(struct bt_ascs_ase *ase) { - const bool state_changed = ascs_ep_get_state(&ase->ep) != BT_BAP_EP_STATE_STREAMING; struct bt_bap_stream *stream = ase->ep.stream; struct bt_bap_stream_ops *ops; __ASSERT_NO_MSG(stream != NULL); - ase_status_changed(ase, BT_BAP_EP_STATE_STREAMING); - ops = stream->ops; - if (state_changed && ops != NULL && ops->started != NULL) { + if (ops != NULL && ops->started != NULL) { ops->started(stream); - } else if (!state_changed && ops != NULL && ops->metadata_updated != NULL) { + } +} + +static void ase_metadata_updated(struct bt_ascs_ase *ase) +{ + struct bt_bap_stream *stream = ase->ep.stream; + struct bt_bap_stream_ops *ops; + + __ASSERT_NO_MSG(stream != NULL); + + ops = stream->ops; + if (ops != NULL && ops->metadata_updated != NULL) { ops->metadata_updated(stream); } } -static void ase_set_state_disabling(struct bt_ascs_ase *ase) +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); - ase->ep.receiver_ready = false; + if (reason == BT_HCI_ERR_SUCCESS) { + /* Default to BT_HCI_ERR_UNSPECIFIED if no other reason is set */ + reason = BT_HCI_ERR_UNSPECIFIED; + } + + 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 { + LOG_WRN("No callback for stopped set"); + } +} + +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"); + } + } +} - ase_status_changed(ase, BT_BAP_EP_STATE_DISABLING); +static void ase_enter_state_disabling(struct bt_ascs_ase *ase) +{ + struct bt_bap_stream *stream = ase->ep.stream; + struct bt_bap_stream_ops *ops; + + __ASSERT_NO_MSG(stream != NULL); + + ase->ep.receiver_ready = false; ops = stream->ops; if (ops != NULL && ops->disabled != NULL) { @@ -360,7 +455,7 @@ static void ase_set_state_disabling(struct bt_ascs_ase *ase) } } -static void ase_set_state_releasing(struct bt_ascs_ase *ase) +static void ase_enter_state_releasing(struct bt_ascs_ase *ase) { struct bt_bap_stream *stream = ase->ep.stream; @@ -368,8 +463,6 @@ static void ase_set_state_releasing(struct bt_ascs_ase *ase) ase->ep.receiver_ready = false; - ase_status_changed(ase, BT_BAP_EP_STATE_RELEASING); - /* Either the client or the server may disconnect the CISes when entering the releasing * state. */ @@ -387,52 +480,91 @@ static void ase_set_state_releasing(struct bt_ascs_ase *ase) static void state_transition_work_handler(struct k_work *work) { - struct bt_ascs_ase *ase = CONTAINER_OF(work, struct bt_ascs_ase, state_transition_work); + struct k_work_delayable *d_work = k_work_delayable_from_work(work); + struct bt_ascs_ase *ase = CONTAINER_OF(d_work, struct bt_ascs_ase, state_transition_work); const enum bt_bap_ep_state old_state = ascs_ep_get_state(&ase->ep); const enum bt_bap_ep_state new_state = ase->state_pending; - struct bt_bap_stream *stream = ase->ep.stream; - struct bt_bap_ep *ep = &ase->ep; + int err; - __ASSERT_NO_MSG(stream != NULL); + ase->ep.status.state = new_state; + + /* Notify ASE state */ + if (ase->conn != NULL) { + err = ase_state_notify(ase); + if (err == -ENOMEM) { + struct bt_conn_info info; + uint32_t retry_delay_ms; - /* We left the streaming state, let the upper layers know that the stream is stopped */ - if (old_state != new_state && old_state == BT_BAP_EP_STATE_STREAMING) { - struct bt_bap_stream_ops *ops = stream->ops; - uint8_t reason = ep->reason; + /* Revert back to old state */ + ase->ep.status.state = old_state; - if (reason == BT_HCI_ERR_SUCCESS) { - /* Default to BT_HCI_ERR_UNSPECIFIED if no other reason is set */ - reason = BT_HCI_ERR_UNSPECIFIED; + err = bt_conn_get_info(ase->conn, &info); + __ASSERT_NO_MSG(err == 0); + + retry_delay_ms = BT_CONN_INTERVAL_TO_MS(info.le.interval); + + /* Reschedule the state transition */ + err = k_work_reschedule(d_work, K_MSEC(retry_delay_ms)); + if (err >= 0) { + LOG_WRN("Out of buffers for ase state notification. " + "Will retry in %dms", retry_delay_ms); + return; + } } - if (ops != NULL && ops->stopped != NULL) { - ops->stopped(stream, reason); - } else { - LOG_WRN("No callback for stopped set"); + if (err < 0) { + LOG_ERR("Failed to notify ASE state (err %d)", err); } } + 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) { + switch (new_state) { + case BT_BAP_EP_STATE_ENABLING: + case BT_BAP_EP_STATE_STREAMING: + ase_metadata_updated(ase); + return; + default: + break; + } + } + + /* Actions needed for exiting the old state */ + switch (old_state) { + 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; + } + + /* Actions needed for entering the new state */ switch (new_state) { case BT_BAP_EP_STATE_IDLE: - ase_set_state_idle(ase); + ase_enter_state_idle(ase); break; case BT_BAP_EP_STATE_CODEC_CONFIGURED: - ase_set_state_codec_configured(ase); + ase_enter_state_codec_configured(ase); break; case BT_BAP_EP_STATE_QOS_CONFIGURED: - ase_set_state_qos_configured(ase); + ase_enter_state_qos_configured(ase); break; case BT_BAP_EP_STATE_ENABLING: - ase_set_state_enabling(ase); + ase_enter_state_enabling(ase); break; case BT_BAP_EP_STATE_STREAMING: - ase_set_state_streaming(ase); + ase_enter_state_streaming(ase); break; case BT_BAP_EP_STATE_DISABLING: - ase_set_state_disabling(ase); + ase_enter_state_disabling(ase); break; case BT_BAP_EP_STATE_RELEASING: - ase_set_state_releasing(ase); + ase_enter_state_releasing(ase); break; default: __ASSERT_PRINT("Invalid state %d", new_state); @@ -533,9 +665,9 @@ int ascs_ep_set_state(struct bt_bap_ep *ep, uint8_t state) ase->state_pending = state; - err = k_work_submit(&ase->state_transition_work); + err = k_work_schedule(&ase->state_transition_work, K_NO_WAIT); if (err < 0) { - LOG_ERR("Failed to submit state transition work err %d", err); + LOG_ERR("Failed to schedule state transition work err %d", err); return err; } @@ -808,6 +940,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) { @@ -832,6 +965,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 @@ -839,8 +979,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) @@ -864,6 +1002,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; @@ -872,7 +1011,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); @@ -899,7 +1044,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; } @@ -1020,6 +1164,12 @@ static int ase_release(struct bt_ascs_ase *ase, uint8_t reason, struct bt_bap_as int bt_ascs_release_ase(struct bt_bap_ep *ep) { struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep); + const enum bt_bap_ep_state state = ascs_ep_get_state(&ase->ep); + + if (state == BT_BAP_EP_STATE_IDLE) { + ase_free(ase); + return 0; + } return ase_release(ase, BT_HCI_ERR_LOCALHOST_TERM_CONN, BT_BAP_ASCS_RSP_NULL); } @@ -1103,12 +1253,12 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) * should expect there to be only a single reference to the bt_conn pointer * from the stack. * We trigger the work handler directly rather than e.g. calling - * ase_set_state_idle to trigger "regular" state change behavior (such) as + * ase_enter_state_idle to trigger "regular" state change behavior (such) as * calling stream->stopped when leaving the streaming state. */ ase->ep.reason = reason; ase->state_pending = BT_BAP_EP_STATE_IDLE; - state_transition_work_handler(&ase->state_transition_work); + state_transition_work_handler(&ase->state_transition_work.work); /* At this point, `ase` object have been free'd */ } } @@ -1205,9 +1355,8 @@ static void ase_init(struct bt_ascs_ase *ase, struct bt_conn *conn, uint8_t id) __ASSERT(ase->attr, "ASE characteristic not found\n"); - k_work_init_delayable(&ase->disconnect_work, - ascs_disconnect_stream_work_handler); - k_work_init(&ase->state_transition_work, state_transition_work_handler); + k_work_init_delayable(&ase->disconnect_work, ascs_disconnect_stream_work_handler); + k_work_init_delayable(&ase->state_transition_work, state_transition_work_handler); } static struct bt_ascs_ase *ase_new(struct bt_conn *conn, uint8_t id) @@ -1414,6 +1563,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; @@ -1432,6 +1582,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); @@ -1461,6 +1613,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); @@ -1675,23 +1829,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) */ @@ -1703,19 +1849,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) { @@ -1729,7 +1888,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; } } @@ -1741,12 +1900,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) { @@ -1755,7 +1914,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); @@ -1770,43 +1929,13 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qo * we have the ISO <-> EP coupling completed (due to setting * the CIS ID in the QoS procedure). */ - if (ep->dir == BT_AUDIO_DIR_SINK) { - bt_audio_codec_cfg_to_iso_path(&ep->iso->rx.path, stream->codec_cfg); - } else { - bt_audio_codec_cfg_to_iso_path(&ep->iso->tx.path, stream->codec_cfg); - } + bt_bap_iso_configure_data_path(ep, stream->codec_cfg); ep->cig_id = cig_id; ep->cis_id = cis_id; 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); } @@ -1902,10 +2031,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; @@ -1945,7 +2080,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); @@ -2030,7 +2165,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, @@ -2104,6 +2241,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); @@ -2159,6 +2298,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); @@ -2305,6 +2446,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); @@ -2507,6 +2650,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 31e8548376e0d2e..164a52afa5ee1ce 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 000000000000000..67a58c27a3b9773 --- /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 36c8c46171fce45..07f83bd7c131154 100644 --- a/subsys/bluetooth/audio/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/bap_broadcast_assistant.c @@ -768,7 +768,8 @@ int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn, subgroup = net_buf_simple_add(&cp_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"); @@ -860,7 +861,8 @@ int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn, } subgroup = net_buf_simple_add(&cp_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"); diff --git a/subsys/bluetooth/audio/bap_broadcast_sink.c b/subsys/bluetooth/audio/bap_broadcast_sink.c index 04771ab53ef575a..3ec003349f56cbe 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) { @@ -151,12 +139,14 @@ static void update_recv_state_big_cleared(const struct bt_bap_broadcast_sink *si recv_state = bt_bap_scan_delegator_find_state(find_recv_state_by_sink_cb, (void *)sink); if (recv_state == NULL) { - LOG_WRN("Failed to find receive state for sink %p", sink); + /* This is likely due to the receive state being removed while we are BIG synced */ + LOG_DBG("Could not find receive state for sink %p", sink); return; } - if (recv_state->encrypt_state == BT_BAP_BIG_ENC_STATE_BCODE_REQ && + if ((recv_state->encrypt_state == BT_BAP_BIG_ENC_STATE_BCODE_REQ || + recv_state->encrypt_state == BT_BAP_BIG_ENC_STATE_DEC) && reason == BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL) { /* Sync failed due to bad broadcast code */ mod_src_param.encrypt_state = BT_BAP_BIG_ENC_STATE_BAD_CODE; @@ -306,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); @@ -321,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; @@ -359,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); @@ -441,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); @@ -477,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); @@ -496,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; + } + + 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 (num_bis > sink->biginfo_num_bis) { - LOG_WRN("BASE contains more BIS than reported by BIGInfo"); + 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); } } @@ -762,7 +892,7 @@ static int bt_bap_broadcast_sink_setup_stream(struct bt_bap_broadcast_sink *sink bt_bap_iso_bind_ep(iso, ep); bt_audio_codec_qos_to_iso_qos(iso->chan.qos->rx, &sink->codec_qos); - bt_audio_codec_cfg_to_iso_path(iso->chan.qos->rx->path, codec_cfg); + bt_bap_iso_configure_data_path(ep, codec_cfg); bt_bap_iso_unref(iso); @@ -802,8 +932,8 @@ static void broadcast_sink_cleanup(struct bt_bap_broadcast_sink *sink) err = bt_bap_scan_delegator_rem_src(sink->bass_src_id); if (err != 0) { - LOG_WRN("Failed to remove Receive State for sink %p: %d", - sink, err); + /* This is likely due to the receive state been removed */ + LOG_DBG("Could not remove Receive State for sink %p: %d", sink, err); } } @@ -813,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) { @@ -892,6 +1006,7 @@ int bt_bap_broadcast_sink_create(struct bt_le_per_adv_sync *pa_sync, uint32_t br } sink->bass_src_id = recv_state->src_id; + atomic_set_bit(sink->flags, BT_BAP_BROADCAST_SINK_FLAG_SRC_ID_VALID); } atomic_set_bit(sink->flags, BT_BAP_BROADCAST_SINK_FLAG_INITIALIZED); @@ -903,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; @@ -951,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 8e5010cc007e9ab..3982be82e7494cb 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) { @@ -288,7 +294,10 @@ static int broadcast_source_setup_stream(uint8_t index, struct bt_bap_stream *st bt_bap_iso_bind_ep(iso, ep); bt_audio_codec_qos_to_iso_qos(iso->chan.qos->tx, qos); - bt_audio_codec_cfg_to_iso_path(iso->chan.qos->tx->path, codec_cfg); + bt_bap_iso_configure_data_path(ep, codec_cfg); +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + iso->chan.qos->num_subevents = qos->num_subevents; +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ bt_bap_iso_unref(iso); @@ -725,6 +734,11 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param *param, broadcast_source_set_state(source, BT_BAP_EP_STATE_QOS_CONFIGURED); source->qos = qos; source->packing = param->packing; +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + source->irc = param->irc; + source->pto = param->pto; + source->iso_interval = param->iso_interval; +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ source->encryption = param->encryption; if (source->encryption) { @@ -780,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; @@ -870,7 +884,7 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, iso_qos = stream->ep->iso->chan.qos->tx; bt_bap_stream_attach(NULL, stream, stream->ep, codec_cfg); - bt_audio_codec_cfg_to_iso_path(iso_qos->path, codec_cfg); + bt_bap_iso_configure_data_path(stream->ep, codec_cfg); } } @@ -930,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; @@ -980,6 +995,11 @@ int bt_bap_broadcast_source_start(struct bt_bap_broadcast_source *source, struct (void)memcpy(param.bcode, source->broadcast_code, sizeof(param.bcode)); } +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + param.irc = source->irc; + param.pto = source->pto; + param.iso_interval = source->iso_interval; +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ /* Set the enabling state early in case that the BIS is connected before we can manage to * set it afterwards diff --git a/subsys/bluetooth/audio/bap_endpoint.h b/subsys/bluetooth/audio/bap_endpoint.h index 46ef3031e68c1c8..aa2f326a71f8221 100644 --- a/subsys/bluetooth/audio/bap_endpoint.h +++ b/subsys/bluetooth/audio/bap_endpoint.h @@ -83,6 +83,12 @@ struct bt_bap_broadcast_source { struct bt_iso_big *big; struct bt_audio_codec_qos *qos; +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + /* Stored advanced parameters */ + uint8_t irc; + uint8_t pto; + uint16_t iso_interval; +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 /* The codec specific configured data for each stream in the subgroup */ @@ -118,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; @@ -138,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 5a4bf8fb819cb40..5eb53f5de586cab 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_iso.c b/subsys/bluetooth/audio/bap_iso.c index cb68a8032f51660..3fa2059ea94de62 100644 --- a/subsys/bluetooth/audio/bap_iso.c +++ b/subsys/bluetooth/audio/bap_iso.c @@ -129,19 +129,12 @@ void bt_bap_iso_init(struct bt_bap_iso *iso, struct bt_iso_chan_ops *ops) iso->chan.ops = ops; iso->chan.qos = &iso->qos; - /* Setup points for both Tx and Rx + /* Setup the QoS for both Tx and Rx * This is due to the limitation in the ISO API where pointers like - * the `qos->tx` shall be initialized before the CIS is connected if - * ever want to use it for TX, and ditto for RX. They cannot be - * initialized after the CIS has been connected + * the `qos->tx` shall be initialized before the CIS is created */ iso->chan.qos->rx = &iso->rx.qos; - iso->chan.qos->rx->path = &iso->rx.path; - iso->chan.qos->rx->path->cc = iso->rx.cc; - iso->chan.qos->tx = &iso->tx.qos; - iso->chan.qos->tx->path = &iso->tx.path; - iso->chan.qos->tx->path->cc = iso->tx.cc; } static struct bt_bap_iso_dir *bap_iso_get_iso_dir(bool unicast_client, struct bt_bap_iso *iso, @@ -164,6 +157,43 @@ static struct bt_bap_iso_dir *bap_iso_get_iso_dir(bool unicast_client, struct bt } } +void bt_bap_iso_configure_data_path(struct bt_bap_ep *ep, struct bt_audio_codec_cfg *codec_cfg) +{ + struct bt_bap_iso *bap_iso = ep->iso; + struct bt_iso_chan_qos *qos = bap_iso->chan.qos; + const bool is_unicast_client = + IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && bt_bap_ep_is_unicast_client(ep); + struct bt_bap_iso_dir *iso_dir = bap_iso_get_iso_dir(is_unicast_client, bap_iso, ep->dir); + struct bt_iso_chan_path *path = &iso_dir->path; + + /* Setup the data path objects */ + if (iso_dir == &bap_iso->rx) { + qos->rx->path = path; + } else { + qos->tx->path = path; + } + + /* Configure the data path to either use the controller for transcoding, or set the path to + * be transparant to indicate that the transcoding happens somewhere else + */ + path->pid = codec_cfg->path_id; + + if (codec_cfg->ctlr_transcode) { + path->format = codec_cfg->id; + path->cid = codec_cfg->cid; + path->vid = codec_cfg->vid; + path->delay = 0; + path->cc_len = codec_cfg->data_len; + path->cc = codec_cfg->data; + } else { + path->format = BT_HCI_CODING_FORMAT_TRANSPARENT; + path->cid = 0; + path->vid = 0; + path->delay = 0; + path->cc_len = 0; + path->cc = NULL; + } +} static bool is_unicast_client_ep(struct bt_bap_ep *ep) { return IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && bt_bap_ep_is_unicast_client(ep); diff --git a/subsys/bluetooth/audio/bap_iso.h b/subsys/bluetooth/audio/bap_iso.h index d3b27f3823afc72..4384182d697fa14 100644 --- a/subsys/bluetooth/audio/bap_iso.h +++ b/subsys/bluetooth/audio/bap_iso.h @@ -41,6 +41,7 @@ void bt_bap_iso_foreach(bt_bap_iso_func_t func, void *user_data); struct bt_bap_iso *bt_bap_iso_find(bt_bap_iso_func_t func, void *user_data); void bt_bap_iso_init(struct bt_bap_iso *iso, struct bt_iso_chan_ops *ops); void bt_bap_iso_bind_ep(struct bt_bap_iso *iso, struct bt_bap_ep *ep); +void bt_bap_iso_configure_data_path(struct bt_bap_ep *ep, struct bt_audio_codec_cfg *codec_cfg); void bt_bap_iso_unbind_ep(struct bt_bap_iso *iso, struct bt_bap_ep *ep); struct bt_bap_ep *bt_bap_iso_get_ep(bool unicast_client, struct bt_bap_iso *iso, enum bt_audio_dir dir); diff --git a/subsys/bluetooth/audio/bap_scan_delegator.c b/subsys/bluetooth/audio/bap_scan_delegator.c index 19d339974539a5f..03ebe87275f7497 100644 --- a/subsys/bluetooth/audio/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/bap_scan_delegator.c @@ -177,7 +177,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); @@ -459,7 +459,7 @@ static int scan_delegator_add_source(struct bt_conn *conn, /* subtract 1 as the opcode has already been pulled */ if (buf->len < sizeof(struct bt_bap_bass_cp_add_src) - 1) { LOG_DBG("Invalid length %u", buf->size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } internal_state = get_free_recv_state(); @@ -510,10 +510,14 @@ static int scan_delegator_add_source(struct bt_conn *conn, if (buf->len < (sizeof(subgroup->bis_sync) + sizeof(subgroup->metadata_len))) { LOG_DBG("Invalid length %u", buf->size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } 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) { @@ -545,7 +549,7 @@ static int scan_delegator_add_source(struct bt_conn *conn, if (buf->len < subgroup->metadata_len) { LOG_DBG("Invalid length %u", buf->size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } @@ -563,7 +567,7 @@ static int scan_delegator_add_source(struct bt_conn *conn, if (buf->len != 0) { LOG_DBG("Invalid length %u", buf->size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } if (pa_sync != BT_BAP_BASS_PA_REQ_NO_SYNC) { @@ -581,10 +585,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); } } @@ -625,7 +629,7 @@ static int scan_delegator_mod_src(struct bt_conn *conn, if (buf->len < sizeof(struct bt_bap_bass_cp_mod_src) - 1) { LOG_DBG("Invalid length %u", buf->len); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } src_id = net_buf_simple_pull_u8(buf); @@ -664,12 +668,17 @@ static int scan_delegator_mod_src(struct bt_conn *conn, if (buf->len < (sizeof(subgroup->bis_sync) + sizeof(subgroup->metadata_len))) { LOG_DBG("Invalid length %u", buf->len); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } 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"); @@ -699,7 +708,7 @@ static int scan_delegator_mod_src(struct bt_conn *conn, if (buf->len < subgroup->metadata_len) { LOG_DBG("Invalid length %u", buf->len); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } if (subgroup->metadata_len > CONFIG_BT_BAP_SCAN_DELEGATOR_MAX_METADATA_LEN) { @@ -717,7 +726,7 @@ static int scan_delegator_mod_src(struct bt_conn *conn, if (buf->len != 0) { LOG_DBG("Invalid length %u", buf->size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } /* All input has been validated; update receive state and check for changes */ @@ -765,11 +774,24 @@ 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 || + state->pa_sync_state == BT_BAP_PA_STATE_SYNCED)) { + /* Terminate PA sync */ + const int err = pa_sync_term_request(conn, &internal_state->state); + + if (err != 0) { + LOG_DBG("PA sync term from %p was rejected with reason %d", conn, err); + + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } + + state_changed = true; } /* Notify if changed */ @@ -797,7 +819,7 @@ static int scan_delegator_broadcast_code(struct bt_conn *conn, /* subtract 1 as the opcode has already been pulled */ if (buf->len != sizeof(struct bt_bap_bass_cp_broadcase_code) - 1) { LOG_DBG("Invalid length %u", buf->size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } src_id = net_buf_simple_pull_u8(buf); @@ -830,12 +852,13 @@ static int scan_delegator_rem_src(struct bt_conn *conn, { struct bass_recv_state_internal *internal_state; struct bt_bap_scan_delegator_recv_state *state; + bool bis_sync_was_requested; uint8_t src_id; /* subtract 1 as the opcode has already been pulled */ if (buf->len != sizeof(struct bt_bap_bass_cp_rem_src) - 1) { LOG_DBG("Invalid length %u", buf->size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } src_id = net_buf_simple_pull_u8(buf); @@ -855,10 +878,17 @@ 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); + } + } + + bis_sync_was_requested = false; + for (uint8_t i = 0U; i < state->num_subgroups; i++) { + if (internal_state->requested_bis_sync[i] != 0U) { + bis_sync_was_requested = true; + break; } } @@ -873,6 +903,9 @@ static int scan_delegator_rem_src(struct bt_conn *conn, (void)memset(internal_state->requested_bis_sync, 0, sizeof(internal_state->requested_bis_sync)); + if (bis_sync_was_requested) { + bis_sync_request_updated(conn, internal_state); + } receive_state_updated(conn, internal_state); return 0; @@ -891,7 +924,7 @@ static ssize_t write_control_point(struct bt_conn *conn, if (offset != 0) { return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); } else if (len == 0) { - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } net_buf_simple_init_with_data(&buf, (void *)data, len); @@ -916,7 +949,7 @@ static ssize_t write_control_point(struct bt_conn *conn, if (buf.len != 0) { LOG_DBG("Invalid length %u", buf.size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } bap_broadcast_assistant->scanning = false; @@ -926,7 +959,7 @@ static ssize_t write_control_point(struct bt_conn *conn, if (buf.len != 0) { LOG_DBG("Invalid length %u", buf.size); - return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } bap_broadcast_assistant->scanning = true; break; @@ -1323,6 +1356,11 @@ int bt_bap_scan_delegator_mod_src(const struct bt_bap_scan_delegator_mod_src_par state_changed = true; } + if (state->encrypt_state != param->encrypt_state) { + state->encrypt_state = param->encrypt_state; + state_changed = true; + } + /* Verify that the BIS sync values is acceptable for the receive state */ for (uint8_t i = 0U; i < state->num_subgroups; i++) { const uint32_t bis_sync = param->subgroups[i].bis_sync; diff --git a/subsys/bluetooth/audio/bap_stream.c b/subsys/bluetooth/audio/bap_stream.c index 0a6a26014efb6eb..8377ec6e20e3a04 100644 --- a/subsys/bluetooth/audio/bap_stream.c +++ b/subsys/bluetooth/audio/bap_stream.c @@ -31,18 +31,6 @@ LOG_MODULE_REGISTER(bt_bap_stream, CONFIG_BT_BAP_STREAM_LOG_LEVEL); -void bt_audio_codec_cfg_to_iso_path(struct bt_iso_chan_path *path, - struct bt_audio_codec_cfg *codec_cfg) -{ - path->pid = codec_cfg->path_id; - path->format = codec_cfg->id; - path->cid = codec_cfg->cid; - path->vid = codec_cfg->vid; - path->delay = 0; /* TODO: Add to bt_audio_codec_cfg? Use presentation delay? */ - path->cc_len = codec_cfg->data_len; - path->cc = codec_cfg->data; -} - #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) || defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || \ defined(CONFIG_BT_BAP_BROADCAST_SINK) void bt_audio_codec_qos_to_iso_qos(struct bt_iso_chan_io_qos *io, @@ -51,6 +39,10 @@ void bt_audio_codec_qos_to_iso_qos(struct bt_iso_chan_io_qos *io, io->sdu = codec_qos->sdu; io->phy = codec_qos->phy; io->rtn = codec_qos->rtn; +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + io->burst_number = codec_qos->burst_number; + io->max_pdu = codec_qos->max_pdu; +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT || \ * CONFIG_BT_BAP_BROADCAST_SOURCE || \ @@ -273,6 +265,16 @@ int bt_bap_stream_send(struct bt_bap_stream *stream, struct net_buf *buf, return -EBADMSG; } +#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) { + LOG_WRN("Unexpected seq_num diff between %u and %u for %p", stream->_prev_seq_num, + seq_num, stream); + } + + stream->_prev_seq_num = seq_num; +#endif /* CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM */ + /* TODO: Add checks for broadcast sink */ return bt_iso_chan_send(bt_bap_stream_iso_chan_get(stream), @@ -392,20 +394,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; } @@ -789,7 +796,7 @@ int bt_bap_stream_release(struct bt_bap_stream *stream) LOG_DBG("stream %p", stream); CHECKIF(stream == NULL || stream->ep == NULL || stream->conn == NULL) { - LOG_DBG("Invalid stream"); + LOG_DBG("Invalid stream (ep %p, conn %p)", stream->ep, (void *)stream->conn); return -EINVAL; } diff --git a/subsys/bluetooth/audio/bap_stream.h b/subsys/bluetooth/audio/bap_stream.h index 67e8c0470dfd1bd..d16cf2cfcc9d036 100644 --- a/subsys/bluetooth/audio/bap_stream.h +++ b/subsys/bluetooth/audio/bap_stream.h @@ -17,8 +17,6 @@ void bt_bap_stream_reset(struct bt_bap_stream *stream); void bt_bap_stream_attach(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_bap_ep *ep, struct bt_audio_codec_cfg *codec_cfg); -void bt_audio_codec_cfg_to_iso_path(struct bt_iso_chan_path *path, - struct bt_audio_codec_cfg *codec_cfg); void bt_audio_codec_qos_to_iso_qos(struct bt_iso_chan_io_qos *io, const struct bt_audio_codec_qos *codec_qos); diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index 1ff81daeb606a2b..e823a094de5f1e4 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -296,6 +296,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 +314,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 +351,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 +363,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 +726,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 +740,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) { + 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; + } - if (disabled) { - stream->ops->disabled(stream); + ops->stopped(stream, reason); } } @@ -774,17 +806,8 @@ static void unicast_client_ep_qos_state(struct bt_bap_ep *ep, struct net_buf_sim * we have the ISO <-> EP coupling completed (due to setting * the CIS ID in the QoS procedure). */ - if (ep->dir == BT_AUDIO_DIR_SOURCE) { - /* If the endpoint is a source, then we need to - * configure our RX parameters - */ - bt_audio_codec_cfg_to_iso_path(&ep->iso->rx.path, stream->codec_cfg); - } else { - /* If the endpoint is a sink, then we need to - * configure our TX parameters - */ - bt_audio_codec_cfg_to_iso_path(&ep->iso->tx.path, stream->codec_cfg); - } + + bt_bap_iso_configure_data_path(ep, stream->codec_cfg); } /* Notify upper layer */ @@ -2085,13 +2108,25 @@ static void unicast_client_ep_reset(struct bt_conn *conn, uint8_t reason) } static void bt_audio_codec_qos_to_cig_param(struct bt_iso_cig_param *cig_param, - const struct bt_audio_codec_qos *qos) + const struct bt_audio_codec_qos *qos, + const struct bt_bap_unicast_group_param *group_param) { cig_param->framing = qos->framing; cig_param->packing = BT_ISO_PACKING_SEQUENTIAL; /* TODO: Add to QoS struct */ - cig_param->interval = qos->interval; - cig_param->latency = qos->latency; + cig_param->c_to_p_interval = qos->interval; + cig_param->p_to_c_interval = qos->interval; + cig_param->c_to_p_latency = qos->latency; + cig_param->p_to_c_latency = qos->latency; cig_param->sca = BT_GAP_SCA_UNKNOWN; + + if (group_param != NULL) { + cig_param->packing = group_param->packing; +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + cig_param->c_to_p_ft = group_param->c_to_p_ft; + cig_param->p_to_c_ft = group_param->p_to_c_ft; + cig_param->iso_interval = group_param->iso_interval; +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ + } } /* FIXME: Remove `qos` parameter. Some of the QoS related CIG can be different @@ -2099,7 +2134,8 @@ static void bt_audio_codec_qos_to_cig_param(struct bt_iso_cig_param *cig_param, * unicast_group instead. */ static int bt_audio_cig_create(struct bt_bap_unicast_group *group, - const struct bt_audio_codec_qos *qos) + const struct bt_audio_codec_qos *qos, + const struct bt_bap_unicast_group_param *group_param) { struct bt_iso_cig_param param; uint8_t cis_count; @@ -2119,7 +2155,7 @@ static int bt_audio_cig_create(struct bt_bap_unicast_group *group, param.num_cis = cis_count; param.cis_channels = group->cis; - bt_audio_codec_qos_to_cig_param(¶m, qos); + bt_audio_codec_qos_to_cig_param(¶m, qos, group_param); err = bt_iso_cig_create(¶m, &group->cig); if (err != 0) { @@ -2153,7 +2189,7 @@ static int bt_audio_cig_reconfigure(struct bt_bap_unicast_group *group, param.num_cis = cis_count; param.cis_channels = group->cis; - bt_audio_codec_qos_to_cig_param(¶m, qos); + bt_audio_codec_qos_to_cig_param(¶m, qos, NULL); err = bt_iso_cig_reconfigure(group->cig, ¶m); if (err != 0) { @@ -2301,6 +2337,9 @@ static void unicast_client_codec_qos_to_iso_qos(struct bt_bap_iso *iso, } bt_audio_codec_qos_to_iso_qos(io_qos, qos); +#if defined(CONFIG_BT_ISO_TEST_PARAMS) + iso->chan.qos->num_subevents = qos->num_subevents; +#endif /* CONFIG_BT_ISO_TEST_PARAMS */ if (other_io_qos != NULL) { /* If the opposing ASE of the CIS is not yet configured, we @@ -2591,7 +2630,7 @@ int bt_bap_unicast_group_create(struct bt_bap_unicast_group_param *param, } } - err = bt_audio_cig_create(unicast_group, group_qos); + err = bt_audio_cig_create(unicast_group, group_qos, param); if (err != 0) { LOG_DBG("bt_audio_cig_create failed: %d", err); unicast_group_free(unicast_group); diff --git a/subsys/bluetooth/audio/cap_acceptor.c b/subsys/bluetooth/audio/cap_acceptor.c index db32d382e2a8d8e..56ed5fa2daa96c9 100644 --- a/subsys/bluetooth/audio/cap_acceptor.c +++ b/subsys/bluetooth/audio/cap_acceptor.c @@ -27,6 +27,16 @@ int bt_cap_acceptor_register(const struct bt_csip_set_member_register_param *par static struct bt_gatt_service cas; int err; + CHECKIF(param->set_size == 0U) { + LOG_DBG("param->set_size shall be non-zero"); + return -EINVAL; + } + + CHECKIF(param->rank == 0U) { + LOG_DBG("param->rank shall be non-zero"); + return -EINVAL; + } + err = bt_csip_set_member_register(param, svc_inst); if (err != 0) { LOG_DBG("Failed to register CSIP"); diff --git a/subsys/bluetooth/audio/cap_commander.c b/subsys/bluetooth/audio/cap_commander.c new file mode 100644 index 000000000000000..93567f34038ac3d --- /dev/null +++ b/subsys/bluetooth/audio/cap_commander.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2022-2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include "cap_internal.h" +#include "ccid_internal.h" +#include "csip_internal.h" +#include "bap_endpoint.h" + +#include + +LOG_MODULE_REGISTER(bt_cap_commander, CONFIG_BT_CAP_COMMANDER_LOG_LEVEL); + +#include "common/bt_str.h" + +static const struct bt_cap_commander_cb *cap_cb; + +int bt_cap_commander_register_cb(const struct bt_cap_commander_cb *cb) +{ + 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( + const struct bt_cap_commander_broadcast_reception_start_param *param) +{ + return -ENOSYS; +} + +int bt_cap_commander_broadcast_reception_stop( + const struct bt_cap_commander_broadcast_reception_stop_param *param) +{ + 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; +#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 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]; + struct bt_cap_common_client *client = NULL; + + if (param->type == BT_CAP_SET_TYPE_AD_HOC) { + + CHECKIF(member->member == NULL) { + LOG_DBG("param->members[%zu].member is NULL", i); + return false; + } + + client = bt_cap_common_get_client_by_acl(member->member); + if (client == NULL || !client->cas_found) { + LOG_DBG("CAS was not found for param->members[%zu]", i); + return false; + } + } else if (param->type == BT_CAP_SET_TYPE_CSIP) { + CHECKIF(member->csip == NULL) { + LOG_DBG("param->members[%zu].csip is NULL", i); + return false; + } + + client = bt_cap_common_get_client_by_csis(member->csip); + if (client == NULL) { + LOG_DBG("CSIS was not found for param->members[%zu]", i); + return false; + } + } + + if (client == NULL || !client->cas_found) { + LOG_DBG("CAS was not found for 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) +{ + const struct bt_cap_commander_proc_param *proc_param; + static struct bt_vcp_vol_ctlr_cb vol_ctlr_cb = { + .vol_set = cap_commander_vcp_vol_set_cb, + }; + struct bt_cap_common_proc *active_proc; + static bool cb_registered; + 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); + + if (!cb_registered) { + /* Ensure that ops are registered before any procedures are started */ + err = bt_vcp_vol_ctlr_cb_register(&vol_ctlr_cb); + if (err != 0) { + LOG_DBG("Failed to register VCP callbacks: %d", err); + + return -ENOEXEC; + } + + cb_registered = true; + } + + 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; +} + +int bt_cap_commander_change_volume_offset( + const struct bt_cap_commander_change_volume_offset_param *param) +{ + return -ENOSYS; +} + +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) +{ + return -ENOSYS; +} + +int bt_cap_commander_change_microphone_gain_setting( + const struct bt_cap_commander_change_microphone_gain_setting_param *param) +{ + + return -ENOSYS; +} diff --git a/subsys/bluetooth/audio/cap_common.c b/subsys/bluetooth/audio/cap_common.c new file mode 100644 index 000000000000000..62ffbc7b8741c50 --- /dev/null +++ b/subsys/bluetooth/audio/cap_common.c @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#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, + 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: + 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; +} + +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 7362ea94341fee8..32d86b726a14e2f 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -10,6 +10,7 @@ #include #include #include "cap_internal.h" +#include "ccid_internal.h" #include "csip_internal.h" #include "bap_endpoint.h" @@ -38,9 +39,14 @@ int bt_cap_initiator_register_cb(const struct bt_cap_initiator_cb *cb) return 0; } +struct valid_metadata_param { + bool stream_context_found; + bool valid; +}; + static bool data_func_cb(struct bt_data *data, void *user_data) { - bool *stream_context_found = (bool *)user_data; + struct valid_metadata_param *metadata_param = (struct valid_metadata_param *)user_data; LOG_DBG("type %u len %u data %s", data->type, data->data_len, bt_hex(data->data, data->data_len)); @@ -50,8 +56,21 @@ static bool data_func_cb(struct bt_data *data, void *user_data) return false; } - *stream_context_found = true; - return false; + metadata_param->stream_context_found = true; + } else if (IS_ENABLED(CONFIG_BT_CCID) && data->type == BT_AUDIO_METADATA_TYPE_CCID_LIST) { + /* If the application supplies a CCID list, we verify that the CCIDs exist on our + * device + */ + for (uint8_t i = 0U; i < data->data_len; i++) { + const uint8_t ccid = data->data[i]; + + if (bt_ccid_find_attr(ccid) == NULL) { + LOG_DBG("Unknown characterstic for CCID 0x%02X", ccid); + metadata_param->valid = false; + + return false; + } + } } return true; @@ -59,21 +78,24 @@ static bool data_func_cb(struct bt_data *data, void *user_data) static bool cap_initiator_valid_metadata(const uint8_t meta[], size_t meta_len) { - bool stream_context_found = false; + struct valid_metadata_param metadata_param = { + .stream_context_found = false, + .valid = true, + }; int err; LOG_DBG("meta %p len %zu", meta, meta_len); - err = bt_audio_data_parse(meta, meta_len, data_func_cb, &stream_context_found); + err = bt_audio_data_parse(meta, meta_len, data_func_cb, &metadata_param); if (err != 0 && err != -ECANCELED) { return false; } - if (!stream_context_found) { + if (!metadata_param.stream_context_found) { LOG_DBG("No streaming context supplied"); } - return stream_context_found; + return metadata_param.stream_context_found && metadata_param.valid; } #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) @@ -290,358 +312,24 @@ 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) +static void +bt_cap_initiator_discover_complete(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_csis_inst *csis_inst) { - 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; + if (cap_cb && cap_cb->unicast_discovery_complete) { + cap_cb->unicast_discovery_complete(conn, err, csis_inst); } - - 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) -{ - 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); - } - } - - 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; -} - -static bool cap_stream_in_active_proc(const struct bt_cap_stream *cap_stream) -{ - 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; - } - } - - return false; + return bt_cap_common_discover(conn, bt_cap_initiator_discover_complete); } static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_start_param *param, @@ -699,14 +387,14 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st } if (param->type == BT_CAP_SET_TYPE_AD_HOC) { - struct cap_unicast_client *client; + struct bt_cap_common_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)]; + client = bt_cap_common_get_client_by_acl(member->member); if (!client->cas_found) { LOG_DBG("CAS was not found for param->members[%zu]", i); @@ -715,14 +403,14 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st } if (param->type == BT_CAP_SET_TYPE_CSIP) { - struct cap_unicast_client *client; + struct bt_cap_common_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); + client = bt_cap_common_get_client_by_csis(member->csip); if (client == NULL) { LOG_DBG("CSIS was not found for param->members[%zu]", i); return false; @@ -768,38 +456,39 @@ 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_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); struct bt_bap_unicast_group *unicast_group; - enum cap_unicast_proc_type proc_type; + 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)); + unicast_group = active_proc->unicast_group; + 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); } 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); } break; - case CAP_UNICAST_PROC_TYPE_NONE: + case BT_CAP_COMMON_PROC_TYPE_NONE: default: __ASSERT(false, "Invalid proc_type: %u", proc_type); } @@ -808,7 +497,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; @@ -828,12 +518,12 @@ static int cap_initiator_unicast_audio_configure( if (param->type == BT_CAP_SET_TYPE_AD_HOC) { conn = member->member; } else { - struct cap_unicast_client *client; + struct bt_cap_common_client *client; /* We have verified that `client` wont be NULL in * `valid_unicast_audio_start_param`. */ - client = lookup_unicast_client_by_csis(member->csip); + client = bt_cap_common_get_client_by_csis(member->csip); __ASSERT(client != NULL, "client is NULL"); conn = client->conn; } @@ -844,26 +534,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. @@ -873,9 +562,7 @@ 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; @@ -884,7 +571,9 @@ static int cap_initiator_unicast_audio_configure( int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param, struct bt_bap_unicast_group *unicast_group) { - if (cap_proc_is_active()) { + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + + if (bt_cap_common_proc_is_active()) { LOG_DBG("A CAP procedure is already in progress"); return -EBUSY; @@ -899,8 +588,7 @@ int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start return -EINVAL; } - active_proc.unicast_group = unicast_group; - active_proc.proc_type = CAP_UNICAST_PROC_TYPE_START; + active_proc->unicast_group = unicast_group; return cap_initiator_unicast_audio_configure(param); } @@ -909,49 +597,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. @@ -962,10 +657,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; @@ -976,8 +669,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; @@ -1004,9 +698,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; @@ -1016,6 +710,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", @@ -1025,57 +721,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. @@ -1086,47 +782,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. @@ -1138,17 +835,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 @@ -1163,7 +858,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; @@ -1172,29 +867,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; @@ -1207,7 +903,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 { @@ -1238,7 +934,8 @@ static bool can_update_metadata(const struct bt_bap_stream *bap_stream) int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param params[], size_t 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_stream *bap_stream; const uint8_t *meta; size_t meta_len; @@ -1256,7 +953,7 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda return -EINVAL; } - if (cap_proc_is_active()) { + if (bt_cap_common_proc_is_active()) { LOG_DBG("A CAP procedure is already in progress"); return -EBUSY; @@ -1298,30 +995,26 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda return -EINVAL; } - 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, + active_proc->proc_param.initiator[i].stream = cap_stream; + active_proc->proc_param.initiator[i].meta_update.meta_len = params[i].meta_len; + memcpy(&active_proc->proc_param.initiator[i].meta_update.meta, params[i].meta, params[i].meta_len); } - atomic_set_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ACTIVE); - active_proc.stream_cnt = count; + bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_UPDATE, count); + bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE); - active_proc.proc_type = CAP_UNICAST_PROC_TYPE_UPDATE; - cap_set_subproc(CAP_UNICAST_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; @@ -1329,13 +1022,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; @@ -1343,40 +1036,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. @@ -1389,10 +1089,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; @@ -1422,12 +1120,13 @@ static bool can_release(const struct bt_bap_stream *bap_stream) int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_group) { - 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; 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; @@ -1443,7 +1142,7 @@ int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_gro 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; + active_proc->proc_param.initiator[stream_cnt].stream = cap_stream; stream_cnt++; } } @@ -1454,28 +1153,24 @@ int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_gro return -EALREADY; } - 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, stream_cnt); + active_proc->unicast_group = unicast_group; - 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; @@ -1483,36 +1178,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. @@ -1523,10 +1220,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 ac07f3f817c403c..4c833a1d8e59bbb 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,119 @@ 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, +}; + +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 */ + + /* 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) + struct bt_bap_unicast_group *unicast_group; + 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, + 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); + +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 863d32874a2465b..9d0a10045176d56 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.c b/subsys/bluetooth/audio/ccid.c index c7bd56db2341205..c3a9d6a2b42ea2c 100644 --- a/subsys/bluetooth/audio/ccid.c +++ b/subsys/bluetooth/audio/ccid.c @@ -6,6 +6,9 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include +#include +#include #include "ccid_internal.h" @@ -23,3 +26,41 @@ uint8_t bt_ccid_get_value(void) return ccid_value++; } + +struct ccid_search_param { + const struct bt_gatt_attr *attr; + uint8_t ccid; +}; + +static uint8_t ccid_attr_cb(const struct bt_gatt_attr *attr, uint16_t handle, void *user_data) +{ + struct ccid_search_param *search_param = user_data; + + if (attr->read != NULL) { + uint8_t ccid = 0U; + ssize_t res; + + res = attr->read(NULL, attr, &ccid, sizeof(ccid), 0); + + if (res == sizeof(ccid) && search_param->ccid == ccid) { + search_param->attr = attr; + + return BT_GATT_ITER_STOP; + } + } + + return BT_GATT_ITER_CONTINUE; +} + +const struct bt_gatt_attr *bt_ccid_find_attr(uint8_t ccid) +{ + struct ccid_search_param search_param = { + .attr = NULL, + .ccid = ccid, + }; + + bt_gatt_foreach_attr_type(BT_ATT_FIRST_ATTRIBUTE_HANDLE, BT_ATT_LAST_ATTRIBUTE_HANDLE, + BT_UUID_CCID, NULL, 0, ccid_attr_cb, &search_param); + + return search_param.attr; +} diff --git a/subsys/bluetooth/audio/ccid_internal.h b/subsys/bluetooth/audio/ccid_internal.h index e68b7bdb8f898d7..bf48877529d8716 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 /** @@ -23,4 +22,16 @@ */ uint8_t bt_ccid_get_value(void); +/** + * @brief Get the GATT attribute of a CCID value + * + * Searches the current GATT database for a CCID characteristic that has the supplied CCID value. + * + * @param ccid The CCID the search for + * + * @retval NULL if none was found + * @retval A pointer to a GATT attribute if found + */ +const struct bt_gatt_attr *bt_ccid_find_attr(uint8_t ccid); + #endif /* ZEPHYR_INCLUDE_BLUETOOTH_CCID_H_ */ diff --git a/subsys/bluetooth/audio/codec.c b/subsys/bluetooth/audio/codec.c index 8a9826f8633eb63..6eec848a9b44705 100644 --- a/subsys/bluetooth/audio/codec.c +++ b/subsys/bluetooth/audio/codec.c @@ -88,6 +88,35 @@ int bt_audio_codec_cfg_freq_hz_to_freq(uint32_t freq_hz) } } +int bt_audio_codec_cfg_frame_dur_to_frame_dur_us(enum bt_audio_codec_config_frame_dur frame_dur) +{ + switch (frame_dur) { + case BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5: + return 7500; + case BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10: + return 10000; + default: + return -EINVAL; + } +} + +int bt_audio_codec_cfg_frame_dur_us_to_frame_dur(uint32_t frame_dur_us) +{ + switch (frame_dur_us) { + case 7500U: + return BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5; + case 10000U: + return BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10; + default: + return -EINVAL; + } +} + +#if 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 || \ + CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 + struct search_type_param { bool found; uint8_t type; @@ -110,6 +139,135 @@ static bool parse_cb(struct bt_data *data, void *user_data) return true; } +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++]; + const uint8_t value_len = *len - sizeof(data_type); + + if (data_type == type) { + uint8_t *value = &buf->data[i]; + + if (data_len == value_len) { + memcpy(value, data, data_len); + } else { + const int16_t diff = data_len - value_len; + uint8_t *old_next_data_start; + uint8_t *new_next_data_start; + uint8_t data_len_to_move; + + /* Check if this is the last value in the buffer */ + if (value + value_len == buf->data + buf->len) { + data_len_to_move = 0U; + } else { + 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); + } + + if (diff < 0) { + /* In this case we need to move memory around after the copy + * to fit the new shorter data + */ + + memcpy(value, data, data_len); + if (data_len_to_move > 0U) { + memmove(new_next_data_start, old_next_data_start, + data_len_to_move); + } + } else { + /* In this case we need to move memory around before + * the copy to fit the new longer data + */ + if ((buf->len + diff) > buf->size) { + LOG_DBG("Cannot fit data_len %zu in buf with len " + "%u and size %u", + data_len, buf->len, buf->size); + return -ENOMEM; + } + + if (data_len_to_move > 0) { + memmove(new_next_data_start, old_next_data_start, + data_len_to_move); + } + memcpy(value, data, data_len); + } + + buf->len += diff; + *len += diff; + } + + return buf->len; + } + + i += value_len; + } + + /* If we reach here, we did not find the data in the buffer, so we simply add it */ + 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); /* value */ + } + } else { + LOG_DBG("Cannot fit data_len %zu in codec_cfg with len %u and size %u", data_len, + buf->len, buf->size); + return -ENOMEM; + } + + 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 || \ + * CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 \ + */ + #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 static void init_net_buf_simple_from_codec_cfg(struct net_buf_simple *buf, @@ -121,12 +279,12 @@ 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, uint8_t type, - const uint8_t **data) +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) { struct search_type_param param = { .found = false, - .type = type, + .type = (uint8_t)type, .data_len = 0, .data = data, }; @@ -158,9 +316,13 @@ uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, u return param.data_len; } -int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, uint8_t type, - const uint8_t *data, size_t data_len) +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) { + struct net_buf_simple buf; + int ret; + CHECKIF(codec_cfg == NULL) { LOG_DBG("codec_cfg is NULL"); return -EINVAL; @@ -176,92 +338,35 @@ int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, uint8_t typ return -EINVAL; } - for (uint16_t i = 0U; i < codec_cfg->data_len;) { - uint8_t *len = &codec_cfg->data[i++]; - const uint8_t data_type = codec_cfg->data[i++]; - const uint8_t value_len = *len - sizeof(data_type); - - if (data_type == type) { - uint8_t *value = &codec_cfg->data[i]; - - if (data_len == value_len) { - memcpy(value, data, data_len); - } else { - const int16_t diff = data_len - value_len; - uint8_t *old_next_data_start; - uint8_t *new_next_data_start; - uint8_t data_len_to_move; - - /* Check if this is the last value in the buffer */ - if (value + value_len == codec_cfg->data + codec_cfg->data_len) { - data_len_to_move = 0U; - } else { - old_next_data_start = value + value_len + 1; - new_next_data_start = value + data_len + 1; - data_len_to_move = codec_cfg->data_len - - (old_next_data_start - codec_cfg->data); - } - - if (diff < 0) { - /* In this case we need to move memory around after the copy - * to fit the new shorter data - */ - - memcpy(value, data, data_len); - if (data_len_to_move > 0U) { - memmove(new_next_data_start, old_next_data_start, - data_len_to_move); - } - } else { - /* In this case we need to move memory around before - * the copy to fit the new longer data - */ - if ((codec_cfg->data_len + diff) > - ARRAY_SIZE(codec_cfg->data)) { - LOG_DBG("Cannot fit data_len %zu in buf with len " - "%u and size %u", - data_len, codec_cfg->data_len, - ARRAY_SIZE(codec_cfg->data)); - return -ENOMEM; - } - - if (data_len_to_move > 0) { - memmove(new_next_data_start, old_next_data_start, - data_len_to_move); - } + init_net_buf_simple_from_codec_cfg(&buf, codec_cfg); - memcpy(value, data, data_len); - } + ret = ltv_set_val(&buf, type, data, data_len); + if (ret >= 0) { + codec_cfg->data_len = ret; + } - codec_cfg->data_len += diff; - *len += diff; - } + return ret; +} - return codec_cfg->data_len; - } +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; - i += value_len; + CHECKIF(codec_cfg == NULL) { + LOG_DBG("codec_cfg is NULL"); + return -EINVAL; } - /* If we reach here, we did not find the data in the buffer, so we simply add it */ - if ((codec_cfg->data_len + data_len) <= ARRAY_SIZE(codec_cfg->data)) { - struct net_buf_simple buf; - - init_net_buf_simple_from_codec_cfg(&buf, codec_cfg); + init_net_buf_simple_from_codec_cfg(&buf, codec_cfg); - net_buf_simple_add_u8(&buf, data_len + sizeof(type)); - net_buf_simple_add_u8(&buf, type); - if (data_len > 0) { - net_buf_simple_add_mem(&buf, data, data_len); - } - codec_cfg->data_len = buf.len; - } else { - LOG_DBG("Cannot fit data_len %zu in codec_cfg with len %u and size %u", data_len, - codec_cfg->data_len, ARRAY_SIZE(codec_cfg->data)); - return -ENOMEM; + ret = ltv_unset_val(&buf, type); + if (ret >= 0) { + codec_cfg->data_len = ret; } - return codec_cfg->data_len; + return ret; } int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg) @@ -309,8 +414,9 @@ int bt_audio_codec_cfg_set_freq(struct bt_audio_codec_cfg *codec_cfg, sizeof(freq_u8)); } -int bt_audio_codec_cfg_get_frame_duration_us(const struct bt_audio_codec_cfg *codec_cfg) +int bt_audio_codec_cfg_get_frame_dur(const struct bt_audio_codec_cfg *codec_cfg) { + enum bt_audio_codec_config_frame_dur frame_dur; const uint8_t *data; uint8_t data_len; @@ -328,14 +434,29 @@ int bt_audio_codec_cfg_get_frame_duration_us(const struct bt_audio_codec_cfg *co return -EBADMSG; } - switch (data[0]) { - case BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5: - return 7500; - case BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10: - return 10000; - default: + frame_dur = data[0]; + if (bt_audio_codec_cfg_frame_dur_to_frame_dur_us(frame_dur) < 0) { + LOG_DBG("Invalid frame_dur value: 0x%02X", frame_dur); return -EBADMSG; } + + return frame_dur; +} + +int bt_audio_codec_cfg_set_frame_dur(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_frame_dur frame_dur) +{ + uint8_t frame_dur_u8; + + if (bt_audio_codec_cfg_frame_dur_to_frame_dur_us(frame_dur) < 0) { + LOG_DBG("Invalid freq value: %d", frame_dur); + return -EINVAL; + } + + frame_dur_u8 = (uint8_t)frame_dur; + + return bt_audio_codec_cfg_set_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_DURATION, + &frame_dur_u8, sizeof(frame_dur_u8)); } int bt_audio_codec_cfg_get_chan_allocation(const struct bt_audio_codec_cfg *codec_cfg, @@ -461,10 +582,20 @@ int bt_audio_codec_cfg_set_frame_blocks_per_sdu(struct bt_audio_codec_cfg *codec #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \ CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 +static void init_net_buf_simple_from_meta(struct net_buf_simple *buf, uint8_t meta[], + size_t meta_len, size_t meta_size) +{ + buf->__buf = meta; + buf->data = meta; + buf->size = meta_size; + 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) { struct search_type_param param = { + .found = false, .type = type, .data_len = 0, .data = data, @@ -497,6 +628,47 @@ static int codec_meta_get_val(const uint8_t meta[], size_t meta_len, uint8_t typ return param.data_len; } +static int codec_meta_set_val(uint8_t meta[], size_t meta_len, size_t meta_size, + enum bt_audio_metadata_type type, const uint8_t *data, + size_t data_len) +{ + struct net_buf_simple buf; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + CHECKIF(data == NULL && data_len != 0) { + LOG_DBG("data is NULL"); + return -EINVAL; + } + + CHECKIF(data_len > UINT8_MAX) { + LOG_DBG("Invalid data_len %zu", data_len); + return -EINVAL; + } + + init_net_buf_simple_from_meta(&buf, meta, meta_len, 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; @@ -519,6 +691,27 @@ static int codec_meta_get_pref_context(const uint8_t meta[], size_t meta_len) return sys_get_le16(data); } +static int codec_meta_set_pref_context(uint8_t meta[], size_t meta_len, size_t meta_size, + enum bt_audio_context ctx) +{ + uint16_t ctx_le16; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + if ((ctx & BT_AUDIO_CONTEXT_TYPE_ANY) != ctx) { + LOG_DBG("Invalid ctx value: %d", ctx); + return -EINVAL; + } + + ctx_le16 = sys_cpu_to_le16((uint16_t)ctx); + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, + (const uint8_t *)&ctx_le16, sizeof(ctx_le16)); +} + static int codec_meta_get_stream_context(const uint8_t meta[], size_t meta_len) { const uint8_t *data; @@ -541,6 +734,27 @@ static int codec_meta_get_stream_context(const uint8_t meta[], size_t meta_len) return sys_get_le16(data); } +static int codec_meta_set_stream_context(uint8_t meta[], size_t meta_len, size_t meta_size, + enum bt_audio_context ctx) +{ + uint16_t ctx_le16; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + if ((ctx & BT_AUDIO_CONTEXT_TYPE_ANY) != ctx) { + LOG_DBG("Invalid ctx value: %d", ctx); + return -EINVAL; + } + + ctx_le16 = sys_cpu_to_le16((uint16_t)ctx); + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + (const uint8_t *)&ctx_le16, sizeof(ctx_le16)); +} + static int codec_meta_get_program_info(const uint8_t meta[], size_t meta_len, const uint8_t **program_info) { @@ -567,6 +781,23 @@ static int codec_meta_get_program_info(const uint8_t meta[], size_t meta_len, return ret; } +static int codec_meta_set_program_info(uint8_t meta[], size_t meta_len, size_t meta_size, + const uint8_t *program_info, size_t program_info_len) +{ + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + CHECKIF(program_info == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_PROGRAM_INFO, + program_info, program_info_len); +} + static int codec_meta_get_stream_lang(const uint8_t meta[], size_t meta_len) { const uint8_t *data; @@ -589,23 +820,44 @@ static int codec_meta_get_stream_lang(const uint8_t meta[], size_t meta_len) return sys_get_le24(data); } -static int codec_meta_get_ccid_list(const uint8_t meta[], size_t meta_len, - const uint8_t **ccid_list) +static int codec_meta_set_stream_lang(uint8_t meta[], size_t meta_len, size_t meta_size, + uint32_t stream_lang) { - const uint8_t *data; - int ret; + uint8_t stream_lang_le[3]; CHECKIF(meta == NULL) { LOG_DBG("meta is NULL"); return -EINVAL; } - CHECKIF(ccid_list == NULL) { - LOG_DBG("ccid_list is NULL"); + if ((stream_lang & 0xFFFFFFU) != stream_lang) { + LOG_DBG("Invalid stream_lang value: %d", stream_lang); return -EINVAL; } - ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_CCID_LIST, &data); + sys_put_le24(stream_lang, stream_lang_le); + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_STREAM_LANG, + stream_lang_le, sizeof(stream_lang_le)); +} + +static int codec_meta_get_ccid_list(const uint8_t meta[], size_t meta_len, + const uint8_t **ccid_list) +{ + const uint8_t *data; + int ret; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + CHECKIF(ccid_list == NULL) { + LOG_DBG("ccid_list is NULL"); + return -EINVAL; + } + + ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_CCID_LIST, &data); if (data == NULL) { return -ENODATA; } @@ -615,6 +867,23 @@ static int codec_meta_get_ccid_list(const uint8_t meta[], size_t meta_len, return ret; } +static int codec_meta_set_ccid_list(uint8_t meta[], size_t meta_len, size_t meta_size, + const uint8_t *ccid_list, size_t ccid_list_len) +{ + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + CHECKIF(ccid_list == NULL) { + LOG_DBG("ccid_list is NULL"); + return -EINVAL; + } + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_CCID_LIST, + ccid_list, ccid_list_len); +} + static int codec_meta_get_parental_rating(const uint8_t meta[], size_t meta_len) { const uint8_t *data; @@ -637,6 +906,27 @@ static int codec_meta_get_parental_rating(const uint8_t meta[], size_t meta_len) return data[0]; } +static int codec_meta_set_parental_rating(uint8_t meta[], size_t meta_len, size_t meta_size, + enum bt_audio_parental_rating parental_rating) +{ + uint8_t parental_rating_u8; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + if (parental_rating > BT_AUDIO_PARENTAL_RATING_AGE_18_OR_ABOVE) { + LOG_DBG("Invalid parental_rating value: %d", parental_rating); + return -EINVAL; + } + + parental_rating_u8 = (uint8_t)parental_rating; + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, + &parental_rating_u8, sizeof(parental_rating_u8)); +} + static int codec_meta_get_program_info_uri(const uint8_t meta[], size_t meta_len, const uint8_t **program_info_uri) { @@ -663,6 +953,25 @@ static int codec_meta_get_program_info_uri(const uint8_t meta[], size_t meta_len return ret; } +static int codec_meta_set_program_info_uri(uint8_t meta[], size_t meta_len, size_t meta_size, + const uint8_t *program_info_uri, + size_t program_info_uri_len) +{ + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + CHECKIF(program_info_uri == NULL) { + LOG_DBG("program_info_uri is NULL"); + return -EINVAL; + } + + return codec_meta_set_val(meta, meta_len, meta_size, + BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI, program_info_uri, + program_info_uri_len); +} + static int codec_meta_get_audio_active_state(const uint8_t meta[], size_t meta_len) { const uint8_t *data; @@ -685,6 +994,27 @@ static int codec_meta_get_audio_active_state(const uint8_t meta[], size_t meta_l return data[0]; } +static int codec_meta_set_audio_active_state(uint8_t meta[], size_t meta_len, size_t meta_size, + enum bt_audio_active_state state) +{ + uint8_t state_u8; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + if (state != BT_AUDIO_ACTIVE_STATE_DISABLED && state != BT_AUDIO_ACTIVE_STATE_ENABLED) { + LOG_DBG("Invalid state value: %d", state); + return -EINVAL; + } + + state_u8 = (uint8_t)state; + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_AUDIO_STATE, + &state_u8, sizeof(state_u8)); +} + static int codec_meta_get_bcast_audio_immediate_rend_flag(const uint8_t meta[], size_t meta_len) { const uint8_t *data; @@ -698,6 +1028,18 @@ static int codec_meta_get_bcast_audio_immediate_rend_flag(const uint8_t meta[], &data); } +static int codec_meta_set_bcast_audio_immediate_rend_flag(uint8_t meta[], size_t meta_len, + size_t meta_size) +{ + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + return codec_meta_set_val(meta, meta_len, meta_size, + BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE, NULL, 0); +} + static int codec_meta_get_extended(const uint8_t meta[], size_t meta_len, const uint8_t **extended_meta) { @@ -724,6 +1066,23 @@ static int codec_meta_get_extended(const uint8_t meta[], size_t meta_len, return ret; } +static int codec_meta_set_extended(uint8_t meta[], size_t meta_len, size_t meta_size, + const uint8_t *extended, size_t extended_len) +{ + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + CHECKIF(extended == NULL) { + LOG_DBG("extended is NULL"); + return -EINVAL; + } + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_EXTENDED, + extended, extended_len); +} + static int codec_meta_get_vendor(const uint8_t meta[], size_t meta_len, const uint8_t **vendor_meta) { const uint8_t *data; @@ -749,6 +1108,23 @@ static int codec_meta_get_vendor(const uint8_t meta[], size_t meta_len, const ui return ret; } +static int codec_meta_set_vendor(uint8_t meta[], size_t meta_len, size_t meta_size, + const uint8_t *vendor, size_t vendor_len) +{ + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + CHECKIF(vendor == NULL) { + LOG_DBG("vendor is NULL"); + return -EINVAL; + } + + return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_VENDOR, vendor, + vendor_len); +} + #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 int bt_audio_codec_cfg_meta_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type, const uint8_t **data) @@ -761,6 +1137,45 @@ int bt_audio_codec_cfg_meta_get_val(const struct bt_audio_codec_cfg *codec_cfg, return codec_meta_get_val(codec_cfg->meta, codec_cfg->meta_len, type, data); } +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) +{ + int ret; + + CHECKIF(codec_cfg == NULL) { + LOG_DBG("codec_cfg is NULL"); + return -EINVAL; + } + + ret = codec_meta_set_val(codec_cfg->meta, codec_cfg->meta_len, ARRAY_SIZE(codec_cfg->meta), + type, data, data_len); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + 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) { @@ -771,6 +1186,20 @@ int bt_audio_codec_cfg_meta_get_pref_context(const struct bt_audio_codec_cfg *co return codec_meta_get_pref_context(codec_cfg->meta, codec_cfg->meta_len); } +int bt_audio_codec_cfg_meta_set_pref_context(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_context ctx) +{ + int ret; + + ret = codec_meta_set_pref_context(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), ctx); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_stream_context(const struct bt_audio_codec_cfg *codec_cfg) { CHECKIF(codec_cfg == NULL) { @@ -781,6 +1210,20 @@ int bt_audio_codec_cfg_meta_get_stream_context(const struct bt_audio_codec_cfg * return codec_meta_get_stream_context(codec_cfg->meta, codec_cfg->meta_len); } +int bt_audio_codec_cfg_meta_set_stream_context(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_context ctx) +{ + int ret; + + ret = codec_meta_set_stream_context(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), ctx); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_program_info(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **program_info) { @@ -792,6 +1235,21 @@ int bt_audio_codec_cfg_meta_get_program_info(const struct bt_audio_codec_cfg *co return codec_meta_get_program_info(codec_cfg->meta, codec_cfg->meta_len, program_info); } +int bt_audio_codec_cfg_meta_set_program_info(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *program_info, size_t program_info_len) +{ + int ret; + + ret = codec_meta_set_program_info(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), program_info, + program_info_len); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_stream_lang(const struct bt_audio_codec_cfg *codec_cfg) { CHECKIF(codec_cfg == NULL) { @@ -802,6 +1260,20 @@ int bt_audio_codec_cfg_meta_get_stream_lang(const struct bt_audio_codec_cfg *cod return codec_meta_get_stream_lang(codec_cfg->meta, codec_cfg->meta_len); } +int bt_audio_codec_cfg_meta_set_stream_lang(struct bt_audio_codec_cfg *codec_cfg, + uint32_t stream_lang) +{ + int ret; + + ret = codec_meta_set_stream_lang(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), stream_lang); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_ccid_list(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **ccid_list) { @@ -813,6 +1285,20 @@ int bt_audio_codec_cfg_meta_get_ccid_list(const struct bt_audio_codec_cfg *codec return codec_meta_get_ccid_list(codec_cfg->meta, codec_cfg->meta_len, ccid_list); } +int bt_audio_codec_cfg_meta_set_ccid_list(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *ccid_list, size_t ccid_list_len) +{ + int ret; + + ret = codec_meta_set_ccid_list(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), ccid_list, ccid_list_len); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_parental_rating(const struct bt_audio_codec_cfg *codec_cfg) { CHECKIF(codec_cfg == NULL) { @@ -823,6 +1309,20 @@ int bt_audio_codec_cfg_meta_get_parental_rating(const struct bt_audio_codec_cfg return codec_meta_get_parental_rating(codec_cfg->meta, codec_cfg->meta_len); } +int bt_audio_codec_cfg_meta_set_parental_rating(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_parental_rating parental_rating) +{ + int ret; + + ret = codec_meta_set_parental_rating(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), parental_rating); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_program_info_uri(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **program_info_uri) { @@ -835,6 +1335,22 @@ int bt_audio_codec_cfg_meta_get_program_info_uri(const struct bt_audio_codec_cfg program_info_uri); } +int bt_audio_codec_cfg_meta_set_program_info_uri(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *program_info_uri, + size_t program_info_uri_len) +{ + int ret; + + ret = codec_meta_set_program_info_uri(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), program_info_uri, + program_info_uri_len); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_audio_active_state(const struct bt_audio_codec_cfg *codec_cfg) { CHECKIF(codec_cfg == NULL) { @@ -845,6 +1361,20 @@ int bt_audio_codec_cfg_meta_get_audio_active_state(const struct bt_audio_codec_c return codec_meta_get_audio_active_state(codec_cfg->meta, codec_cfg->meta_len); } +int bt_audio_codec_cfg_meta_set_audio_active_state(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_active_state state) +{ + int ret; + + ret = codec_meta_set_audio_active_state(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), state); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag( const struct bt_audio_codec_cfg *codec_cfg) { @@ -853,11 +1383,23 @@ int bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag( return -EINVAL; } - LOG_ERR("codec_cfg->meta_len %zu", codec_cfg->meta_len); - return codec_meta_get_bcast_audio_immediate_rend_flag(codec_cfg->meta, codec_cfg->meta_len); } +int bt_audio_codec_cfg_meta_set_bcast_audio_immediate_rend_flag( + struct bt_audio_codec_cfg *codec_cfg) +{ + int ret; + + ret = codec_meta_set_bcast_audio_immediate_rend_flag(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta)); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_extended(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **extended_meta) { @@ -869,6 +1411,21 @@ int bt_audio_codec_cfg_meta_get_extended(const struct bt_audio_codec_cfg *codec_ return codec_meta_get_extended(codec_cfg->meta, codec_cfg->meta_len, extended_meta); } +int bt_audio_codec_cfg_meta_set_extended(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *extended_meta, size_t extended_meta_len) +{ + int ret; + + ret = codec_meta_set_extended(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), extended_meta, + extended_meta_len); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_vendor(const struct bt_audio_codec_cfg *codec_cfg, const uint8_t **vendor_meta) { @@ -879,6 +1436,20 @@ int bt_audio_codec_cfg_meta_get_vendor(const struct bt_audio_codec_cfg *codec_cf return codec_meta_get_vendor(codec_cfg->meta, codec_cfg->meta_len, vendor_meta); } + +int bt_audio_codec_cfg_meta_set_vendor(struct bt_audio_codec_cfg *codec_cfg, + const uint8_t *vendor_meta, size_t vendor_meta_len) +{ + int ret; + + ret = codec_meta_set_vendor(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), vendor_meta, vendor_meta_len); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */ #if CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 @@ -893,6 +1464,45 @@ int bt_audio_codec_cap_meta_get_val(const struct bt_audio_codec_cap *codec_cap, return codec_meta_get_val(codec_cap->meta, codec_cap->meta_len, type, data); } +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) +{ + int ret; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + ret = codec_meta_set_val(codec_cap->meta, codec_cap->meta_len, ARRAY_SIZE(codec_cap->meta), + type, data, data_len); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + 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) { @@ -903,6 +1513,20 @@ int bt_audio_codec_cap_meta_get_pref_context(const struct bt_audio_codec_cap *co return codec_meta_get_pref_context(codec_cap->meta, codec_cap->meta_len); } +int bt_audio_codec_cap_meta_set_pref_context(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_context ctx) +{ + int ret; + + ret = codec_meta_set_pref_context(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), ctx); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_stream_context(const struct bt_audio_codec_cap *codec_cap) { CHECKIF(codec_cap == NULL) { @@ -913,6 +1537,20 @@ int bt_audio_codec_cap_meta_get_stream_context(const struct bt_audio_codec_cap * return codec_meta_get_stream_context(codec_cap->meta, codec_cap->meta_len); } +int bt_audio_codec_cap_meta_set_stream_context(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_context ctx) +{ + int ret; + + ret = codec_meta_set_stream_context(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), ctx); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_program_info(const struct bt_audio_codec_cap *codec_cap, const uint8_t **program_info) { @@ -924,6 +1562,21 @@ int bt_audio_codec_cap_meta_get_program_info(const struct bt_audio_codec_cap *co return codec_meta_get_program_info(codec_cap->meta, codec_cap->meta_len, program_info); } +int bt_audio_codec_cap_meta_set_program_info(struct bt_audio_codec_cap *codec_cap, + const uint8_t *program_info, size_t program_info_len) +{ + int ret; + + ret = codec_meta_set_program_info(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), program_info, + program_info_len); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_stream_lang(const struct bt_audio_codec_cap *codec_cap) { CHECKIF(codec_cap == NULL) { @@ -934,6 +1587,20 @@ int bt_audio_codec_cap_meta_get_stream_lang(const struct bt_audio_codec_cap *cod return codec_meta_get_stream_lang(codec_cap->meta, codec_cap->meta_len); } +int bt_audio_codec_cap_meta_set_stream_lang(struct bt_audio_codec_cap *codec_cap, + uint32_t stream_lang) +{ + int ret; + + ret = codec_meta_set_stream_lang(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), stream_lang); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_ccid_list(const struct bt_audio_codec_cap *codec_cap, const uint8_t **ccid_list) { @@ -945,6 +1612,20 @@ int bt_audio_codec_cap_meta_get_ccid_list(const struct bt_audio_codec_cap *codec return codec_meta_get_ccid_list(codec_cap->meta, codec_cap->meta_len, ccid_list); } +int bt_audio_codec_cap_meta_set_ccid_list(struct bt_audio_codec_cap *codec_cap, + const uint8_t *ccid_list, size_t ccid_list_len) +{ + int ret; + + ret = codec_meta_set_ccid_list(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), ccid_list, ccid_list_len); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_parental_rating(const struct bt_audio_codec_cap *codec_cap) { CHECKIF(codec_cap == NULL) { @@ -955,6 +1636,20 @@ int bt_audio_codec_cap_meta_get_parental_rating(const struct bt_audio_codec_cap return codec_meta_get_parental_rating(codec_cap->meta, codec_cap->meta_len); } +int bt_audio_codec_cap_meta_set_parental_rating(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_parental_rating parental_rating) +{ + int ret; + + ret = codec_meta_set_parental_rating(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), parental_rating); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_program_info_uri(const struct bt_audio_codec_cap *codec_cap, const uint8_t **program_info_uri) { @@ -967,6 +1662,22 @@ int bt_audio_codec_cap_meta_get_program_info_uri(const struct bt_audio_codec_cap program_info_uri); } +int bt_audio_codec_cap_meta_set_program_info_uri(struct bt_audio_codec_cap *codec_cap, + const uint8_t *program_info_uri, + size_t program_info_uri_len) +{ + int ret; + + ret = codec_meta_set_program_info_uri(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), program_info_uri, + program_info_uri_len); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_audio_active_state(const struct bt_audio_codec_cap *codec_cap) { CHECKIF(codec_cap == NULL) { @@ -977,6 +1688,20 @@ int bt_audio_codec_cap_meta_get_audio_active_state(const struct bt_audio_codec_c return codec_meta_get_audio_active_state(codec_cap->meta, codec_cap->meta_len); } +int bt_audio_codec_cap_meta_set_audio_active_state(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_active_state state) +{ + int ret; + + ret = codec_meta_set_audio_active_state(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), state); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag( const struct bt_audio_codec_cap *codec_cap) { @@ -988,6 +1713,20 @@ int bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag( return codec_meta_get_bcast_audio_immediate_rend_flag(codec_cap->meta, codec_cap->meta_len); } +int bt_audio_codec_cap_meta_set_bcast_audio_immediate_rend_flag( + struct bt_audio_codec_cap *codec_cap) +{ + int ret; + + ret = codec_meta_set_bcast_audio_immediate_rend_flag(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta)); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_extended(const struct bt_audio_codec_cap *codec_cap, const uint8_t **extended_meta) { @@ -999,6 +1738,21 @@ int bt_audio_codec_cap_meta_get_extended(const struct bt_audio_codec_cap *codec_ return codec_meta_get_extended(codec_cap->meta, codec_cap->meta_len, extended_meta); } +int bt_audio_codec_cap_meta_set_extended(struct bt_audio_codec_cap *codec_cap, + const uint8_t *extended_meta, size_t extended_meta_len) +{ + int ret; + + ret = codec_meta_set_extended(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), extended_meta, + extended_meta_len); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_vendor(const struct bt_audio_codec_cap *codec_cap, const uint8_t **vendor_meta) { @@ -1009,6 +1763,20 @@ int bt_audio_codec_cap_meta_get_vendor(const struct bt_audio_codec_cap *codec_ca return codec_meta_get_vendor(codec_cap->meta, codec_cap->meta_len, vendor_meta); } + +int bt_audio_codec_cap_meta_set_vendor(struct bt_audio_codec_cap *codec_cap, + const uint8_t *vendor_meta, size_t vendor_meta_len) +{ + int ret; + + ret = codec_meta_set_vendor(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), vendor_meta, vendor_meta_len); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} #endif /* CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 */ #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \ * CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 \ @@ -1016,11 +1784,21 @@ int bt_audio_codec_cap_meta_get_vendor(const struct bt_audio_codec_cap *codec_ca #if CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 -uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type, - const uint8_t **data) +static void init_net_buf_simple_from_codec_cap(struct net_buf_simple *buf, + struct bt_audio_codec_cap *codec_cap) +{ + buf->__buf = codec_cap->data; + buf->data = codec_cap->data; + buf->size = sizeof(codec_cap->data); + 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) { struct search_type_param param = { - .type = type, + .found = false, + .type = (uint8_t)type, .data_len = 0, .data = data, }; @@ -1052,6 +1830,59 @@ uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, u return param.data_len; } +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) +{ + struct net_buf_simple buf; + int ret; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + CHECKIF(data == NULL) { + LOG_DBG("data is NULL"); + return -EINVAL; + } + + CHECKIF(data_len == 0U || data_len > UINT8_MAX) { + LOG_DBG("Invalid data_len %zu", data_len); + return -EINVAL; + } + + init_net_buf_simple_from_codec_cap(&buf, codec_cap); + + ret = ltv_set_val(&buf, type, data, data_len); + if (ret >= 0) { + codec_cap->data_len = ret; + } + + 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; @@ -1074,7 +1905,28 @@ int bt_audio_codec_cap_get_freq(const struct bt_audio_codec_cap *codec_cap) return sys_get_le16(data); } -int bt_audio_codec_cap_get_frame_duration(const struct bt_audio_codec_cap *codec_cap) +int bt_audio_codec_cap_set_freq(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_cap_freq freq) +{ + uint16_t freq_le16; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + if ((freq & BT_AUDIO_CODEC_LC3_FREQ_ANY) != freq) { + LOG_DBG("Invalid freq value: %d", freq); + return -EINVAL; + } + + freq_le16 = sys_cpu_to_le16((uint16_t)freq); + + return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_LC3_FREQ, (uint8_t *)&freq_le16, + sizeof(freq_le16)); +} + +int bt_audio_codec_cap_get_frame_dur(const struct bt_audio_codec_cap *codec_cap) { const uint8_t *data; uint8_t data_len; @@ -1096,6 +1948,45 @@ int bt_audio_codec_cap_get_frame_duration(const struct bt_audio_codec_cap *codec return data[0]; } +int bt_audio_codec_cap_set_frame_dur(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_cap_frame_dur frame_dur) +{ + uint8_t frame_dur_u8; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + if ((frame_dur & BT_AUDIO_CODEC_LC3_DURATION_ANY) == 0) { + LOG_DBG("Invalid frame_dur value: %d", frame_dur); + return -EINVAL; + } + + if ((frame_dur & BT_AUDIO_CODEC_LC3_DURATION_PREFER_7_5) != 0) { + if ((frame_dur & BT_AUDIO_CODEC_LC3_DURATION_PREFER_10) != 0) { + LOG_DBG("Cannot prefer both 7.5 and 10ms: %d", frame_dur); + return -EINVAL; + } + + if ((frame_dur & BT_AUDIO_CODEC_LC3_DURATION_7_5) == 0) { + LOG_DBG("Cannot prefer 7.5ms when not supported: %d", frame_dur); + return -EINVAL; + } + } + + if ((frame_dur & BT_AUDIO_CODEC_LC3_DURATION_PREFER_10) != 0 && + (frame_dur & BT_AUDIO_CODEC_LC3_DURATION_10) == 0) { + LOG_DBG("Cannot prefer 10ms when not supported: %d", frame_dur); + return -EINVAL; + } + + frame_dur_u8 = (uint8_t)frame_dur; + + return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_LC3_DURATION, &frame_dur_u8, + sizeof(frame_dur_u8)); +} + int bt_audio_codec_cap_get_supported_audio_chan_counts(const struct bt_audio_codec_cap *codec_cap) { const uint8_t *data; @@ -1118,6 +2009,27 @@ int bt_audio_codec_cap_get_supported_audio_chan_counts(const struct bt_audio_cod return data[0]; } +int bt_audio_codec_cap_set_supported_audio_chan_counts( + struct bt_audio_codec_cap *codec_cap, enum bt_audio_codec_cap_chan_count chan_count) +{ + uint8_t chan_count_u8; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + if ((chan_count & BT_AUDIO_CODEC_CAP_CHAN_COUNT_ALL) != chan_count) { + LOG_DBG("Invalid chan_count value: %d", chan_count); + return -EINVAL; + } + + chan_count_u8 = (uint8_t)chan_count; + + return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_LC3_CHAN_COUNT, &chan_count_u8, + sizeof(chan_count_u8)); +} + int bt_audio_codec_cap_get_octets_per_frame( const struct bt_audio_codec_cap *codec_cap, struct bt_audio_codec_octets_per_codec_frame *codec_frame) @@ -1150,6 +2062,34 @@ int bt_audio_codec_cap_get_octets_per_frame( return 0; } +int bt_audio_codec_cap_set_octets_per_frame( + struct bt_audio_codec_cap *codec_cap, + const struct bt_audio_codec_octets_per_codec_frame *codec_frame) +{ + uint8_t codec_frame_le32[4]; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + CHECKIF(codec_frame == NULL) { + LOG_DBG("codec_frame is NULL"); + return -EINVAL; + } + + if (codec_frame->min > codec_frame->max) { + LOG_DBG("Invalid codec_frame values: %u/%u", codec_frame->min, codec_frame->max); + return -EINVAL; + } + + sys_put_le16(codec_frame->min, codec_frame_le32); + sys_put_le16(codec_frame->max, codec_frame_le32 + 2); + + return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_LC3_FRAME_LEN, codec_frame_le32, + sizeof(codec_frame_le32)); +} + int bt_audio_codec_cap_get_max_codec_frames_per_sdu(const struct bt_audio_codec_cap *codec_cap) { const uint8_t *data; @@ -1172,4 +2112,16 @@ int bt_audio_codec_cap_get_max_codec_frames_per_sdu(const struct bt_audio_codec_ return data[0]; } +int bt_audio_codec_cap_set_max_codec_frames_per_sdu(struct bt_audio_codec_cap *codec_cap, + uint8_t codec_frames_per_sdu) +{ + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_LC3_FRAME_COUNT, + &codec_frames_per_sdu, sizeof(codec_frames_per_sdu)); +} + #endif /* CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 */ diff --git a/subsys/bluetooth/audio/csip_crypto.c b/subsys/bluetooth/audio/csip_crypto.c index d51855f02a583ec..3240e6d053ee594 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_member.c b/subsys/bluetooth/audio/csip_set_member.c index b6bd487af823c31..d738cf05f4c8959 100644 --- a/subsys/bluetooth/audio/csip_set_member.c +++ b/subsys/bluetooth/audio/csip_set_member.c @@ -235,6 +235,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; } diff --git a/subsys/bluetooth/audio/gmap_client.c b/subsys/bluetooth/audio/gmap_client.c new file mode 100644 index 000000000000000..dff67356b760bed --- /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 000000000000000..5bc16ee686f1544 --- /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 b8e70e4e16460d5..b018e034bb7b63b 100644 --- a/subsys/bluetooth/audio/has.c +++ b/subsys/bluetooth/audio/has.c @@ -4,11 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include -#include - -#include #include #include @@ -16,21 +12,23 @@ #include #include #include +#include -#include "../bluetooth/host/conn_internal.h" #include "../bluetooth/host/hci_core.h" +#include "../bluetooth/host/settings.h" #include "audio_internal.h" #include "has_internal.h" +#include "common/bt_str.h" + #include LOG_MODULE_REGISTER(bt_has, CONFIG_BT_HAS_LOG_LEVEL); /* The service allows operations with paired devices only. - * For now, the context is kept for connected devices only, thus the number of contexts is - * equal to maximum number of simultaneous connections to paired devices. + * The number of clients is set to maximum number of simultaneous connections to paired devices. */ -#define BT_HAS_MAX_CONN MIN(CONFIG_BT_MAX_CONN, CONFIG_BT_MAX_PAIRED) +#define MAX_INSTS MIN(CONFIG_BT_MAX_CONN, CONFIG_BT_MAX_PAIRED) #define BITS_CHANGED(_new_value, _old_value) ((_new_value) ^ (_old_value)) #define FEATURE_DEVICE_TYPE_UNCHANGED(_new_value) \ @@ -39,6 +37,8 @@ LOG_MODULE_REGISTER(bt_has, CONFIG_BT_HAS_LOG_LEVEL); !BITS_CHANGED(_new_value, ((has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) != 0 ? 1 : 0)) #define FEATURE_IND_PRESETS_UNCHANGED(_new_value) \ !BITS_CHANGED(_new_value, ((has.features & BT_HAS_FEAT_INDEPENDENT_PRESETS) != 0 ? 1 : 0)) +#define BONDED_CLIENT_INIT_FLAGS \ + (BIT(FLAG_ACTIVE_INDEX_CHANGED) | BIT(FLAG_NOTIFY_PRESET_LIST) | BIT(FLAG_FEATURES_CHANGED)) static struct bt_has has; @@ -52,12 +52,10 @@ static void active_preset_index_cfg_changed(const struct bt_gatt_attr *attr, uin #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) struct has_client; -/* Active preset notification work */ -static void active_preset_work_process(struct k_work *work); -static K_WORK_DEFINE(active_preset_work, active_preset_work_process); - -static void process_control_point_work(struct k_work *work); -static void read_presets_req_free(struct has_client *client); +static int read_preset_response(struct has_client *client); +static int preset_list_changed(struct has_client *client); +static int preset_list_changed_generic_update_tail(struct has_client *client); +static int preset_list_changed_record_deleted_last(struct has_client *client); static ssize_t write_control_point(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *data, uint16_t len, uint16_t offset, uint8_t flags); @@ -69,14 +67,17 @@ static void preset_cp_cfg_changed(const struct bt_gatt_attr *attr, uint16_t valu static ssize_t read_active_preset_index(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { + uint8_t active_index; + LOG_DBG("conn %p attr %p offset %d", (void *)conn, attr, offset); - if (offset > sizeof(has.active_index)) { + if (offset > sizeof(active_index)) { return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); } - return bt_gatt_attr_read(conn, attr, buf, len, offset, &has.active_index, - sizeof(has.active_index)); + active_index = bt_has_preset_active_get(); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &active_index, sizeof(active_index)); } #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */ @@ -115,8 +116,6 @@ static ssize_t read_features(struct bt_conn *conn, const struct bt_gatt_attr *at read_features, NULL, NULL), #endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ - - #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) #if defined(CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE) #define BT_HAS_CHR_PRESET_CONTROL_POINT \ @@ -157,32 +156,35 @@ static struct bt_gatt_attr has_attrs[] = { }; static struct bt_gatt_service has_svc; - -#if defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE) -/* Features notification work */ -static void features_work_process(struct k_work *work); -static K_WORK_DEFINE(features_work, features_work_process); - -#define FEATURES_ATTR &has_attrs[2] -#if defined(CONFIG_BT_HAS_PRESET_SUPPORT) -#define PRESET_CONTROL_POINT_ATTR &has_attrs[5] -#define ACTIVE_PRESET_INDEX_ATTR &has_attrs[8] -#endif /* CONFIG_BT_HAS_PRESET_SUPPORT */ -#else -#if defined(CONFIG_BT_HAS_PRESET_SUPPORT) -#define PRESET_CONTROL_POINT_ATTR &has_attrs[4] -#define ACTIVE_PRESET_INDEX_ATTR &has_attrs[7] -#endif /* CONFIG_BT_HAS_PRESET_SUPPORT */ -#endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ +static struct bt_gatt_attr *hearing_aid_features_attr; +static struct bt_gatt_attr *preset_control_point_attr; +static struct bt_gatt_attr *active_preset_index_attr; #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) || defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE) -enum { +static void notify_work_handler(struct k_work *work); + +enum flag_internal { FLAG_ACTIVE_INDEX_CHANGED, - FLAG_CONTROL_POINT_NOTIFY, + FLAG_PENDING_READ_PRESET_RESPONSE, + FLAG_NOTIFY_PRESET_LIST, + FLAG_NOTIFY_PRESET_LIST_GENERIC_UPDATE_TAIL, + FLAG_NOTIFY_PRESET_LIST_RECORD_DELETED_LAST, FLAG_FEATURES_CHANGED, FLAG_NUM, }; +/* Stored client context */ +static struct client_context { + bt_addr_le_t addr; + + /* Pending notification flags */ + ATOMIC_DEFINE(flags, FLAG_NUM); + + /* Last notified preset index */ + uint8_t last_preset_index_known; +} contexts[CONFIG_BT_MAX_PAIRED]; + +/* Connected client clientance */ static struct has_client { struct bt_conn *conn; #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) @@ -195,14 +197,76 @@ static struct has_client { uint8_t preset_changed_index_next; struct bt_has_cp_read_presets_req read_presets_req; - struct k_work control_point_work; #endif /* CONFIG_BT_HAS_PRESET_SUPPORT */ - ATOMIC_DEFINE(flags, FLAG_NUM); -} has_client_list[BT_HAS_MAX_CONN]; + struct k_work_delayable notify_work; + struct client_context *context; +} has_client_list[MAX_INSTS]; -static struct has_client *client_get_or_new(struct bt_conn *conn) + +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]; + } + } + + return NULL; +} + +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) { + return NULL; + } + + memset(context, 0, sizeof(*context)); + + bt_addr_le_copy(&context->addr, addr); + + return context; +} + +static void context_free(struct client_context *context) +{ + bt_addr_le_copy(&context->addr, BT_ADDR_LE_ANY); +} + +static void client_free(struct has_client *client) +{ + struct bt_conn_info info = { 0 }; + int err; + +#if defined(CONFIG_BT_HAS_PRESET_SUPPORT) || defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE) + (void)k_work_cancel_delayable(&client->notify_work); +#endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ + + err = bt_conn_get_info(client->conn, &info); + __ASSERT_NO_MSG(err == 0); + + if (client->context != NULL && !bt_addr_le_is_bonded(info.id, info.le.dst)) { + /* Free stored context of non-bonded client */ + context_free(client->context); + client->context = NULL; + } + + bt_conn_unref(client->conn); + client->conn = NULL; +} + +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) { @@ -210,39 +274,47 @@ static struct has_client *client_get_or_new(struct bt_conn *conn) } /* first free slot */ - if (!client && !has_client_list[i].conn) { + if (!client && has_client_list[i].conn == NULL) { client = &has_client_list[i]; } } __ASSERT(client, "failed to get client for conn %p", (void *)conn); + memset(client, 0, sizeof(*client)); + client->conn = bt_conn_ref(conn); -#if defined(CONFIG_BT_HAS_PRESET_SUPPORT) - k_work_init(&client->control_point_work, process_control_point_work); -#endif /* CONFIG_BT_HAS_PRESET_SUPPORT */ +#if defined(CONFIG_BT_HAS_PRESET_SUPPORT) || defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE) + k_work_init_delayable(&client->notify_work, notify_work_handler); +#endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ - return client; -} + err = bt_conn_get_info(conn, &info); + if (err != 0) { + LOG_DBG("Could not get conn info: %d", err); -static void client_free(struct has_client *client) -{ -#if defined(CONFIG_BT_HAS_PRESET_SUPPORT) - (void)k_work_cancel(&client->control_point_work); - read_presets_req_free(client); -#endif /* CONFIG_BT_HAS_PRESET_SUPPORT */ + return NULL; + } - atomic_clear_bit(client->flags, FLAG_CONTROL_POINT_NOTIFY); - atomic_clear_bit(client->flags, FLAG_ACTIVE_INDEX_CHANGED); - atomic_clear_bit(client->flags, FLAG_FEATURES_CHANGED); + client->context = context_find(info.le.dst); + if (client->context == NULL) { + client->context = context_alloc(info.le.dst); + if (client->context == NULL) { + LOG_ERR("Failed to allocate client_context for %s", + bt_addr_le_str(info.le.dst)); - bt_conn_unref(client->conn); + client_free(client); - client->conn = NULL; + return NULL; + } + + LOG_DBG("New client_context for %s", bt_addr_le_str(info.le.dst)); + } + + return client; } -static struct has_client *client_get(struct bt_conn *conn) +static struct has_client *client_find_by_conn(struct bt_conn *conn) { for (size_t i = 0; i < ARRAY_SIZE(has_client_list); i++) { if (conn == has_client_list[i].conn) { @@ -253,9 +325,27 @@ static struct has_client *client_get(struct bt_conn *conn) return NULL; } +static void notify_work_reschedule(struct has_client *client, k_timeout_t delay) +{ + int err; + + __ASSERT(client->conn, "Not connected"); + + if (k_work_delayable_remaining_get(&client->notify_work) > 0) { + return; + } + + err = k_work_reschedule(&client->notify_work, delay); + if (err < 0) { + LOG_ERR("Failed to reschedule notification work err %d", err); + } +} + static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { struct has_client *client; + struct bt_conn_info info; + int ret; LOG_DBG("conn %p level %d err %d", (void *)conn, level, err); @@ -263,74 +353,184 @@ static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_ return; } - client = client_get_or_new(conn); + client = client_alloc(conn); if (unlikely(!client)) { LOG_ERR("Failed to allocate client"); return; } - if (!bt_addr_le_is_bonded(conn->id, &conn->le.dst)) { + ret = bt_conn_get_info(client->conn, &info); + if (ret < 0) { + LOG_ERR("bt_conn_get_info err %d", ret); return; } -#if defined(CONFIG_BT_HAS_PRESET_SUPPORT) - /* Notify after reconnection */ - if (atomic_test_and_clear_bit(client->flags, FLAG_ACTIVE_INDEX_CHANGED)) { - /* Emit active preset notification */ - k_work_submit(&active_preset_work); + if (!bt_addr_le_is_bonded(info.id, info.le.dst)) { + return; } - if (atomic_test_and_clear_bit(client->flags, FLAG_CONTROL_POINT_NOTIFY)) { - /* Emit preset changed notifications */ - k_work_submit(&client->control_point_work); + if (atomic_get(client->context->flags) != 0) { + notify_work_reschedule(client, K_NO_WAIT); } -#endif /* CONFIG_BT_HAS_PRESET_SUPPORT */ +} -#if defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE) - if (atomic_test_and_clear_bit(client->flags, FLAG_FEATURES_CHANGED)) { - /* Emit preset changed notifications */ - k_work_submit(&features_work); +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + struct has_client *client; + + LOG_DBG("conn %p reason %d", (void *)conn, reason); + + client = client_find_by_conn(conn); + if (client) { + client_free(client); } -#endif /* CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ } -static void connected(struct bt_conn *conn, uint8_t err) +static void identity_resolved(struct bt_conn *conn, const bt_addr_le_t *rpa, + const bt_addr_le_t *identity) { struct has_client *client; - LOG_DBG("conn %p err %d", conn, err); + LOG_DBG("conn %p %s -> %s", (void *)conn, bt_addr_le_str(rpa), bt_addr_le_str(identity)); - if (err != 0 || !bt_addr_le_is_bonded(conn->id, &conn->le.dst)) { + client = client_find_by_conn(conn); + if (client == NULL) { return; } - client = client_get_or_new(conn); - if (unlikely(!client)) { - LOG_ERR("Failed to allocate client"); + bt_addr_le_copy(&client->context->addr, identity); +} + +BT_CONN_CB_DEFINE(conn_cb) = { + .disconnected = disconnected, + .security_changed = security_changed, + .identity_resolved = identity_resolved, +}; + +static void notify_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct has_client *client = CONTAINER_OF(dwork, struct has_client, notify_work); + int err; + + if (IS_ENABLED(CONFIG_BT_HAS_FEATURES_NOTIFIABLE) && + atomic_test_and_clear_bit(client->context->flags, FLAG_FEATURES_CHANGED) && + bt_gatt_is_subscribed(client->conn, hearing_aid_features_attr, BT_GATT_CCC_NOTIFY)) { + err = bt_gatt_notify(client->conn, hearing_aid_features_attr, &has.features, + sizeof(has.features)); + if (err == -ENOMEM) { + atomic_set_bit(client->context->flags, FLAG_FEATURES_CHANGED); + notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US)); + } else if (err < 0) { + LOG_ERR("Notify features err %d", err); + } + } + +#if defined(CONFIG_BT_HAS_PRESET_SUPPORT) + if (atomic_test_and_clear_bit(client->context->flags, FLAG_PENDING_READ_PRESET_RESPONSE)) { + err = read_preset_response(client); + if (err == -ENOMEM) { + atomic_set_bit(client->context->flags, FLAG_PENDING_READ_PRESET_RESPONSE); + notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US)); + } else if (err < 0) { + LOG_ERR("Notify read preset response err %d", err); + } + } else if (atomic_test_and_clear_bit(client->context->flags, FLAG_NOTIFY_PRESET_LIST)) { + err = preset_list_changed(client); + if (err == -ENOMEM) { + atomic_set_bit(client->context->flags, FLAG_NOTIFY_PRESET_LIST); + notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US)); + } else if (err < 0) { + LOG_ERR("Notify preset list changed err %d", err); + } + } else if (atomic_test_and_clear_bit(client->context->flags, + FLAG_NOTIFY_PRESET_LIST_GENERIC_UPDATE_TAIL)) { + err = preset_list_changed_generic_update_tail(client); + if (err == -ENOMEM) { + atomic_set_bit(client->context->flags, + FLAG_NOTIFY_PRESET_LIST_GENERIC_UPDATE_TAIL); + notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US)); + } else if (err < 0) { + LOG_ERR("Notify preset list changed generic update tail err %d", err); + } + } else if (atomic_test_and_clear_bit(client->context->flags, + FLAG_NOTIFY_PRESET_LIST_RECORD_DELETED_LAST)) { + err = preset_list_changed_record_deleted_last(client); + if (err == -ENOMEM) { + atomic_set_bit(client->context->flags, + FLAG_NOTIFY_PRESET_LIST_RECORD_DELETED_LAST); + notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US)); + } else if (err < 0) { + LOG_ERR("Notify preset list changed recoed deleted last err %d", err); + } + } + +#endif /* CONFIG_BT_HAS_PRESET_SUPPORT */ + + if (IS_ENABLED(CONFIG_BT_HAS_PRESET_SUPPORT) && + atomic_test_and_clear_bit(client->context->flags, FLAG_ACTIVE_INDEX_CHANGED) && + bt_gatt_is_subscribed(client->conn, active_preset_index_attr, BT_GATT_CCC_NOTIFY)) { + uint8_t active_index; + + active_index = bt_has_preset_active_get(); + + err = bt_gatt_notify(client->conn, active_preset_index_attr, + &active_index, sizeof(active_index)); + if (err == -ENOMEM) { + atomic_set_bit(client->context->flags, FLAG_ACTIVE_INDEX_CHANGED); + notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US)); + } else if (err < 0) { + LOG_ERR("Notify active index err %d", err); + } + } +} + +static void notify(struct has_client *client, enum flag_internal flag) +{ + if (client != NULL) { + atomic_set_bit(client->context->flags, flag); + notify_work_reschedule(client, K_NO_WAIT); return; } + + /* Mark notification to be sent to all clients */ + for (size_t i = 0U; i < ARRAY_SIZE(contexts); i++) { + atomic_set_bit(contexts[i].flags, flag); + } + + for (size_t i = 0U; i < ARRAY_SIZE(has_client_list); i++) { + client = &has_client_list[i]; + + if (client->conn == NULL) { + continue; + } + + notify_work_reschedule(client, K_NO_WAIT); + } } -static void disconnected(struct bt_conn *conn, uint8_t reason) +static void bond_deleted_cb(uint8_t id, const bt_addr_le_t *addr) { - struct has_client *client; + struct client_context *context; - LOG_DBG("conn %p reason %d", (void *)conn, reason); + context = context_find(addr); + if (context != NULL) { + context_free(context); + } - client = client_get(conn); - if (client) { - client_free(client); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_settings_delete("has", 0, addr); } } -BT_CONN_CB_DEFINE(conn_cb) = { - .connected = connected, - .disconnected = disconnected, - .security_changed = security_changed, +static struct bt_conn_auth_info_cb auth_info_cb = { + .bond_deleted = bond_deleted_cb, }; #endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) +static struct has_preset *active_preset; + /* HAS internal preset representation */ static struct has_preset { uint8_t index; @@ -341,29 +541,20 @@ static struct has_preset { const char *name; #endif /* CONFIG_BT_HAS_PRESET_NAME_DYNAMIC */ const struct bt_has_preset_ops *ops; -} has_preset_list[CONFIG_BT_HAS_PRESET_COUNT]; - -/* Number of registered presets */ -static uint8_t has_preset_num; - -static bool read_presets_req_pending_cp(const struct has_client *client) -{ - return client->read_presets_req.num_presets > 0; -} + sys_snode_t node; +} preset_pool[CONFIG_BT_HAS_PRESET_COUNT]; -static void read_presets_req_free(struct has_client *client) -{ - client->read_presets_req.num_presets = 0; -} +static sys_slist_t preset_list = SYS_SLIST_STATIC_INIT(&preset_list); +static sys_slist_t preset_free_list = SYS_SLIST_STATIC_INIT(&preset_free_list); typedef uint8_t (*preset_func_t)(const struct has_preset *preset, void *user_data); static void preset_foreach(uint8_t start_index, uint8_t end_index, preset_func_t func, void *user_data) { - for (size_t i = 0; i < ARRAY_SIZE(has_preset_list); i++) { - const struct has_preset *preset = &has_preset_list[i]; + struct has_preset *preset, *tmp; + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&preset_list, preset, tmp, node) { if (preset->index < start_index) { continue; } @@ -387,70 +578,143 @@ static uint8_t preset_found(const struct has_preset *preset, void *user_data) return BT_HAS_PRESET_ITER_STOP; } -static int preset_index_compare(const void *p1, const void *p2) +static void preset_insert(struct has_preset *preset) { - const struct has_preset *preset_1 = p1; - const struct has_preset *preset_2 = p2; - - if (preset_1->index == BT_HAS_PRESET_INDEX_NONE) { - return 1; - } + struct has_preset *tmp, *prev = NULL; + + SYS_SLIST_FOR_EACH_CONTAINER(&preset_list, tmp, node) { + if (tmp->index > preset->index) { + if (prev) { + sys_slist_insert(&preset_list, &prev->node, &preset->node); + } else { + sys_slist_prepend(&preset_list, &preset->node); + } + return; + } - if (preset_2->index == BT_HAS_PRESET_INDEX_NONE) { - return -1; + prev = tmp; } - return preset_1->index - preset_2->index; + sys_slist_append(&preset_list, &preset->node); } static struct has_preset *preset_alloc(uint8_t index, enum bt_has_properties properties, const char *name, const struct bt_has_preset_ops *ops) { - struct has_preset *preset = NULL; + struct has_preset *preset; + sys_snode_t *node; - if (has_preset_num < ARRAY_SIZE(has_preset_list)) { - preset = &has_preset_list[has_preset_num]; - preset->index = index; - preset->properties = properties; + node = sys_slist_get(&preset_free_list); + if (node == NULL) { + return NULL; + } + + preset = CONTAINER_OF(node, struct has_preset, node); + preset->index = index; + preset->properties = properties; #if defined(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC) - utf8_lcpy(preset->name, name, ARRAY_SIZE(preset->name)); + utf8_lcpy(preset->name, name, ARRAY_SIZE(preset->name)); #else - preset->name = name; + preset->name = name; #endif /* CONFIG_BT_HAS_PRESET_NAME_DYNAMIC */ - preset->ops = ops; + preset->ops = ops; - has_preset_num++; - - /* sort the presets in index ascending order */ - qsort(has_preset_list, has_preset_num, sizeof(*preset), preset_index_compare); - } + preset_insert(preset); return preset; } static void preset_free(struct has_preset *preset) { - preset->index = BT_HAS_PRESET_INDEX_NONE; + bool removed; - /* sort the presets in index ascending order */ - if (has_preset_num > 1) { - qsort(has_preset_list, has_preset_num, sizeof(*preset), preset_index_compare); + removed = sys_slist_find_and_remove(&preset_list, &preset->node); + if (removed) { + sys_slist_append(&preset_free_list, &preset->node); } +} - has_preset_num--; +static struct has_preset *preset_get_head(void) +{ + struct has_preset *next; + + return SYS_SLIST_PEEK_HEAD_CONTAINER(&preset_list, next, node); +} + +static struct has_preset *preset_get_tail(void) +{ + struct has_preset *prev; + + return SYS_SLIST_PEEK_TAIL_CONTAINER(&preset_list, prev, node); +} + +static struct has_preset *preset_get_prev(const struct has_preset *preset) +{ + struct has_preset *prev; + + SYS_SLIST_FOR_EACH_CONTAINER(&preset_list, prev, node) { + if (SYS_SLIST_PEEK_NEXT_CONTAINER(prev, node) == preset) { + return prev; + } + } + + prev = preset_get_tail(); + if (prev == preset) { + return NULL; + } + + return prev; +} + +static struct has_preset *preset_lookup_index(uint8_t index) +{ + struct has_preset *preset; + + SYS_SLIST_FOR_EACH_CONTAINER(&preset_list, preset, node) { + if (preset->index == index) { + return preset; + } + } + + return NULL; +} + +static struct has_preset *preset_get_next(struct has_preset *preset) +{ + struct has_preset *next; + + next = SYS_SLIST_PEEK_NEXT_CONTAINER(preset, node); + if (next == NULL) { + next = preset_get_head(); + if (next == preset) { + return NULL; + } + } + + return next; +} + +static uint8_t preset_get_prev_index(const struct has_preset *preset) +{ + const struct has_preset *prev; + + prev = preset_get_prev(preset); + if (prev == NULL || prev->index >= preset->index) { + return BT_HAS_PRESET_INDEX_NONE; + } + + return prev->index; } static void control_point_ntf_complete(struct bt_conn *conn, void *user_data) { - struct has_client *client = client_get(conn); + struct has_client *client = client_find_by_conn(conn); LOG_DBG("conn %p", (void *)conn); /* Resubmit if needed */ - if (client != NULL && - (read_presets_req_pending_cp(client) || - atomic_test_and_clear_bit(client->flags, FLAG_CONTROL_POINT_NOTIFY))) { - k_work_submit(&client->control_point_work); + if (client != NULL && atomic_get(client->context->flags) != 0) { + notify_work_reschedule(client, K_NO_WAIT); } } @@ -468,10 +732,20 @@ static void control_point_ind_complete(struct bt_conn *conn, static int control_point_send(struct has_client *client, struct net_buf_simple *buf) { + const uint16_t mtu_size = bt_gatt_get_mtu(client->conn); + /* PDU structure is [Opcode (1)] [Handle (2)] [...] */ + const uint16_t pdu_size = 3 + buf->len; + + if (mtu_size < pdu_size) { + LOG_WRN("Sending truncated control point PDU %d < %d", mtu_size, pdu_size); + buf->len -= (pdu_size - mtu_size); + } + #if defined(CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE) if (bt_eatt_count(client->conn) > 0 && - bt_gatt_is_subscribed(client->conn, PRESET_CONTROL_POINT_ATTR, BT_GATT_CCC_NOTIFY)) { - client->params.ntf.attr = PRESET_CONTROL_POINT_ATTR; + bt_gatt_is_subscribed(client->conn, preset_control_point_attr, BT_GATT_CCC_NOTIFY)) { + memset(&client->params.ntf, 0, sizeof(client->params.ntf)); + client->params.ntf.attr = preset_control_point_attr; client->params.ntf.func = control_point_ntf_complete; client->params.ntf.data = buf->data; client->params.ntf.len = buf->len; @@ -480,8 +754,9 @@ static int control_point_send(struct has_client *client, struct net_buf_simple * } #endif /* CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE */ - if (bt_gatt_is_subscribed(client->conn, PRESET_CONTROL_POINT_ATTR, BT_GATT_CCC_INDICATE)) { - client->params.ind.attr = PRESET_CONTROL_POINT_ATTR; + if (bt_gatt_is_subscribed(client->conn, preset_control_point_attr, BT_GATT_CCC_INDICATE)) { + memset(&client->params.ind, 0, sizeof(client->params.ind)); + client->params.ind.attr = preset_control_point_attr; client->params.ind.func = control_point_ind_complete; client->params.ind.destroy = NULL; client->params.ind.data = buf->data; @@ -497,22 +772,25 @@ static int control_point_send_all(struct net_buf_simple *buf) { int result = 0; - for (size_t i = 0; i < ARRAY_SIZE(has_client_list); i++) { - struct has_client *client = &has_client_list[i]; + for (size_t i = 0U; i < ARRAY_SIZE(contexts); i++) { + struct client_context *context = &contexts[i]; + struct has_client *client = NULL; int err; - if (!client->conn) { + for (size_t j = 0U; j < ARRAY_SIZE(has_client_list); j++) { + if (has_client_list[j].context == context) { + client = &has_client_list[j]; + break; + } + } + + if (client == NULL || client->conn == NULL) { /* Mark preset changed operation as pending */ - atomic_set_bit(client->flags, FLAG_CONTROL_POINT_NOTIFY); - /* For simplicity we simply start with the first index, - * rather than keeping detailed logs of which clients - * have knowledge of which presets - */ - client->preset_changed_index_next = BT_HAS_PRESET_INDEX_FIRST; + atomic_set_bit(context->flags, FLAG_NOTIFY_PRESET_LIST); continue; } - if (!bt_gatt_is_subscribed(client->conn, PRESET_CONTROL_POINT_ATTR, + if (!bt_gatt_is_subscribed(client->conn, preset_control_point_attr, BT_GATT_CCC_NOTIFY | BT_GATT_CCC_INDICATE)) { continue; } @@ -533,145 +811,333 @@ static int bt_has_cp_read_preset_rsp(struct has_client *client, const struct has struct bt_has_cp_hdr *hdr; struct bt_has_cp_read_preset_rsp *rsp; - NET_BUF_SIMPLE_DEFINE(buf, sizeof(*hdr) + sizeof(*rsp) + BT_HAS_PRESET_NAME_MAX); + NET_BUF_SIMPLE_DEFINE(buf, sizeof(*hdr) + sizeof(*rsp) + BT_HAS_PRESET_NAME_MAX); + + LOG_DBG("conn %p index 0x%02x prop 0x%02x %s is_last 0x%02x", (void *)client->conn, + preset->index, preset->properties, preset->name, is_last); + + hdr = net_buf_simple_add(&buf, sizeof(*hdr)); + hdr->opcode = BT_HAS_OP_READ_PRESET_RSP; + rsp = net_buf_simple_add(&buf, sizeof(*rsp)); + rsp->is_last = is_last ? 0x01 : 0x00; + rsp->index = preset->index; + rsp->properties = preset->properties; + net_buf_simple_add_mem(&buf, preset->name, strlen(preset->name)); + + return control_point_send(client, &buf); +} + +static void preset_changed_prepare(struct net_buf_simple *buf, uint8_t change_id, uint8_t is_last) +{ + struct bt_has_cp_hdr *hdr; + struct bt_has_cp_preset_changed *preset_changed; + + hdr = net_buf_simple_add(buf, sizeof(*hdr)); + hdr->opcode = BT_HAS_OP_PRESET_CHANGED; + preset_changed = net_buf_simple_add(buf, sizeof(*preset_changed)); + preset_changed->change_id = change_id; + preset_changed->is_last = is_last; +} + +static int bt_has_cp_generic_update(struct has_client *client, uint8_t prev_index, uint8_t index, + uint8_t properties, const char *name, uint8_t is_last) +{ + struct bt_has_cp_generic_update *generic_update; + + NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) + + sizeof(struct bt_has_cp_preset_changed) + + sizeof(struct bt_has_cp_generic_update) + BT_HAS_PRESET_NAME_MAX); + + LOG_DBG("client %p prev_index 0x%02x index 0x%02x prop 0x%02x %s is_last %d", + client, prev_index, index, properties, name, is_last); + + preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_GENERIC_UPDATE, is_last); + + generic_update = net_buf_simple_add(&buf, sizeof(*generic_update)); + generic_update->prev_index = prev_index; + generic_update->index = index; + generic_update->properties = properties; + net_buf_simple_add_mem(&buf, name, strlen(name)); + + if (client) { + return control_point_send(client, &buf); + } else { + return control_point_send_all(&buf); + } +} + +#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 && client->context != NULL && + client->context->last_preset_index_known != index) { + client->context->last_preset_index_known = index; + store_client_context(client->context); + return; + } + + for (size_t i = 0; i < ARRAY_SIZE(has_client_list); i++) { + client = &has_client_list[i]; + + /* For each connected client */ + 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); + } + } +} + +static int read_preset_response(struct has_client *client) +{ + const struct has_preset *preset = NULL; + bool is_last = true; + int err; + + __ASSERT_NO_MSG(client != NULL); - LOG_DBG("conn %p preset %p is_last 0x%02x", (void *)client->conn, preset, is_last); + preset_foreach(client->read_presets_req.start_index, BT_HAS_PRESET_INDEX_LAST, + preset_found, &preset); - hdr = net_buf_simple_add(&buf, sizeof(*hdr)); - hdr->opcode = BT_HAS_OP_READ_PRESET_RSP; - rsp = net_buf_simple_add(&buf, sizeof(*rsp)); - rsp->is_last = is_last ? 0x01 : 0x00; - rsp->index = preset->index; - rsp->properties = preset->properties; - net_buf_simple_add_mem(&buf, preset->name, strlen(preset->name)); + if (unlikely(preset == NULL)) { + return bt_has_cp_read_preset_rsp(client, NULL, BT_HAS_IS_LAST); + } - return control_point_send(client, &buf); -} + if (client->read_presets_req.num_presets > 1) { + const struct has_preset *next = NULL; -static uint8_t get_prev_preset_index(const struct has_preset *preset) -{ - const struct has_preset *prev = NULL; + preset_foreach(preset->index + 1, BT_HAS_PRESET_INDEX_LAST, preset_found, &next); - for (size_t i = 0; i < ARRAY_SIZE(has_preset_list); i++) { - const struct has_preset *tmp = &has_preset_list[i]; + is_last = next == NULL; + } - if (tmp->index == BT_HAS_PRESET_INDEX_NONE || tmp == preset) { - break; - } + err = bt_has_cp_read_preset_rsp(client, preset, is_last); + if (err != 0) { + return err; + } - prev = tmp; + if (preset->index > client->context->last_preset_index_known) { + update_last_preset_index_known(client, preset->index); } - return prev ? prev->index : BT_HAS_PRESET_INDEX_NONE; -} + if (!is_last) { + client->read_presets_req.start_index = preset->index + 1; + client->read_presets_req.num_presets--; -static void preset_changed_prepare(struct net_buf_simple *buf, uint8_t change_id, uint8_t is_last) -{ - struct bt_has_cp_hdr *hdr; - struct bt_has_cp_preset_changed *preset_changed; + atomic_set_bit(client->context->flags, FLAG_PENDING_READ_PRESET_RESPONSE); + notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US)); + } - hdr = net_buf_simple_add(buf, sizeof(*hdr)); - hdr->opcode = BT_HAS_OP_PRESET_CHANGED; - preset_changed = net_buf_simple_add(buf, sizeof(*preset_changed)); - preset_changed->change_id = change_id; - preset_changed->is_last = is_last; + return 0; } -static int bt_has_cp_generic_update(struct has_client *client, const struct has_preset *preset, - uint8_t is_last) +static int bt_has_cp_preset_record_deleted(struct has_client *client, uint8_t index) { - struct bt_has_cp_generic_update *generic_update; - NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) + - sizeof(struct bt_has_cp_preset_changed) + - sizeof(struct bt_has_cp_generic_update) + BT_HAS_PRESET_NAME_MAX); + sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t)); - preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_GENERIC_UPDATE, is_last); + LOG_DBG("client %p index 0x%02x", client, index); - generic_update = net_buf_simple_add(&buf, sizeof(*generic_update)); - generic_update->prev_index = get_prev_preset_index(preset); - generic_update->index = preset->index; - generic_update->properties = preset->properties; - net_buf_simple_add_mem(&buf, preset->name, strlen(preset->name)); + preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_DELETED, BT_HAS_IS_LAST); + net_buf_simple_add_u8(&buf, index); - if (client) { + if (client != NULL) { return control_point_send(client, &buf); } else { return control_point_send_all(&buf); } } -static void process_control_point_work(struct k_work *work) +/* Generic Update the last (already deleted) preset */ +static int preset_list_changed_generic_update_tail(struct has_client *client) { - struct has_client *client = CONTAINER_OF(work, struct has_client, control_point_work); + const struct has_preset *prev; + struct has_preset last = { + /* The index value of the last preset the client knew about. */ + .index = client->context->last_preset_index_known, + + /* As the properties of deleted preset is not available anymore, we set this value + * to 0x00 meaning the preset is unavailable and non-writable which is actually true + */ + .properties = BT_HAS_PROP_NONE, + + /* As the name of deleted preset are not available anymore, we set this value + * to the value what is compliant with specification. + * As per HAS_v1.0 the Name is 1-40 octet value. + */ + .name = "N/A", + }; int err; - if (!client->conn) { - return; + prev = preset_get_tail(); + + err = bt_has_cp_generic_update(client, prev ? prev->index : BT_HAS_PRESET_INDEX_NONE, + last.index, last.properties, last.name, false); + if (err != 0) { + return err; } - if (read_presets_req_pending_cp(client)) { - const struct has_preset *preset = NULL; - bool is_last = true; + return 0; +} - preset_foreach(client->read_presets_req.start_index, BT_HAS_PRESET_INDEX_LAST, - preset_found, &preset); +static int preset_list_changed_record_deleted_last(struct has_client *client) +{ + const struct has_preset *last; + int err; - if (unlikely(preset == NULL)) { - (void)bt_has_cp_read_preset_rsp(client, NULL, 0x01); + err = bt_has_cp_preset_record_deleted(client, client->context->last_preset_index_known); + if (err != 0) { + return err; + } - return; - } + last = preset_get_tail(); - if (client->read_presets_req.num_presets > 1) { - const struct has_preset *next = NULL; + update_last_preset_index_known(client, last ? last->index : BT_HAS_PRESET_INDEX_NONE); - preset_foreach(preset->index + 1, BT_HAS_PRESET_INDEX_LAST, - preset_found, &next); + return 0; +} - is_last = next == NULL; +static int preset_list_changed(struct has_client *client) +{ + const struct has_preset *preset = NULL; + const struct has_preset *next = NULL; + bool is_last = true; + int err; - } + if (sys_slist_is_empty(&preset_list)) { + /* The preset list is empty. We need to indicate deletion of all presets */ + atomic_set_bit(client->context->flags, + FLAG_NOTIFY_PRESET_LIST_GENERIC_UPDATE_TAIL); + atomic_set_bit(client->context->flags, + FLAG_NOTIFY_PRESET_LIST_RECORD_DELETED_LAST); + notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US)); - err = bt_has_cp_read_preset_rsp(client, preset, is_last); - if (err) { - LOG_ERR("bt_has_cp_read_preset_rsp failed (err %d)", err); - } + return 0; + } - if (err || is_last) { - read_presets_req_free(client); - } else { - client->read_presets_req.start_index = preset->index + 1; - client->read_presets_req.num_presets--; - } - } else if (atomic_test_and_clear_bit(client->flags, FLAG_CONTROL_POINT_NOTIFY)) { - const struct has_preset *preset = NULL; - const struct has_preset *next = NULL; - bool is_last = true; + preset_foreach(client->preset_changed_index_next, BT_HAS_PRESET_INDEX_LAST, + preset_found, &preset); + + if (preset == NULL) { + return 0; + } - preset_foreach(client->preset_changed_index_next, - BT_HAS_PRESET_INDEX_LAST, preset_found, &preset); + preset_foreach(preset->index + 1, BT_HAS_PRESET_INDEX_LAST, preset_found, &next); - if (preset == NULL) { - return; - } + /* It is last Preset Changed notification if there are no presets left to notify and the + * currently notified preset have the highest index known to the client. + */ + is_last = next == NULL && preset->index >= client->context->last_preset_index_known; - preset_foreach(preset->index + 1, BT_HAS_PRESET_INDEX_LAST, - preset_found, &next); + err = bt_has_cp_generic_update(client, preset_get_prev_index(preset), preset->index, + preset->properties, preset->name, is_last); + if (err != 0) { + return err; + } - is_last = next == NULL; + if (is_last) { + client->preset_changed_index_next = 0; - err = bt_has_cp_generic_update(client, preset, is_last); - if (err) { - LOG_ERR("bt_has_cp_read_preset_rsp failed (err %d)", err); - } + /* It's the last preset notified, so update the highest index known to the client */ + update_last_preset_index_known(client, preset->index); - if (err || is_last) { - atomic_clear_bit(client->flags, FLAG_CONTROL_POINT_NOTIFY); - } else { - client->preset_changed_index_next = preset->index + 1; - } + return 0; + } + + if (next == NULL) { + /* If we end up here, the last preset known to the client has been removed. + * As we do not hold the information about the deleted presets, we need to use + * Generic Update procedure to: + * 1. Notify the presets that have been removed in range + * (PrevIndex = current_preset_last, Index=previous_preset_last) + * 2. Notify deletion of preset Index=previous_preset_last. + */ + atomic_set_bit(client->context->flags, + FLAG_NOTIFY_PRESET_LIST_GENERIC_UPDATE_TAIL); + atomic_set_bit(client->context->flags, + FLAG_NOTIFY_PRESET_LIST_RECORD_DELETED_LAST); + } else { + client->preset_changed_index_next = preset->index + 1; + + atomic_set_bit(client->context->flags, FLAG_NOTIFY_PRESET_LIST); } + + notify_work_reschedule(client, K_USEC(BT_AUDIO_NOTIFY_RETRY_DELAY_US)); + + return 0; } static uint8_t handle_read_preset_req(struct bt_conn *conn, struct net_buf_simple *buf) @@ -688,12 +1154,12 @@ static uint8_t handle_read_preset_req(struct bt_conn *conn, struct net_buf_simpl * shall be returned if client writes Read Presets Request but is not registered for * indications. */ - if (!bt_gatt_is_subscribed(conn, PRESET_CONTROL_POINT_ATTR, BT_GATT_CCC_INDICATE)) { + if (!bt_gatt_is_subscribed(conn, preset_control_point_attr, BT_GATT_CCC_INDICATE)) { return BT_ATT_ERR_CCC_IMPROPER_CONF; } - client = client_get(conn); - if (!client) { + client = client_find_by_conn(conn); + if (client == NULL) { return BT_ATT_ERR_UNLIKELY; } @@ -709,7 +1175,7 @@ static uint8_t handle_read_preset_req(struct bt_conn *conn, struct net_buf_simpl } /* Reject if already in progress */ - if (read_presets_req_pending_cp(client)) { + if (atomic_test_bit(client->context->flags, FLAG_PENDING_READ_PRESET_RESPONSE)) { return BT_HAS_ERR_OPERATION_NOT_POSSIBLE; } @@ -717,7 +1183,7 @@ static uint8_t handle_read_preset_req(struct bt_conn *conn, struct net_buf_simpl client->read_presets_req.start_index = req->start_index; client->read_presets_req.num_presets = req->num_presets; - k_work_submit(&client->control_point_work); + notify(client, FLAG_PENDING_READ_PRESET_RESPONSE); return 0; } @@ -759,7 +1225,8 @@ static int set_preset_name(uint8_t index, const char *name, size_t len) preset->ops->name_changed(index, preset->name); } - return bt_has_cp_generic_update(NULL, preset, BT_HAS_IS_LAST); + return bt_has_cp_generic_update(NULL, preset_get_prev_index(preset), preset->index, + preset->properties, preset->name, BT_HAS_IS_LAST); } static uint8_t handle_write_preset_name(struct bt_conn *conn, struct net_buf_simple *buf) @@ -776,11 +1243,11 @@ static uint8_t handle_write_preset_name(struct bt_conn *conn, struct net_buf_sim * shall be returned if client writes Write Preset Name opcode but is not registered for * indications. */ - if (!bt_gatt_is_subscribed(conn, PRESET_CONTROL_POINT_ATTR, BT_GATT_CCC_INDICATE)) { + if (!bt_gatt_is_subscribed(conn, preset_control_point_attr, BT_GATT_CCC_INDICATE)) { return BT_ATT_ERR_CCC_IMPROPER_CONF; } - client = client_get(conn); + client = client_find_by_conn(conn); if (!client) { return BT_ATT_ERR_UNLIKELY; } @@ -801,46 +1268,16 @@ static uint8_t handle_write_preset_name(struct bt_conn *conn, struct net_buf_sim return BT_ATT_ERR_SUCCESS; } -static void active_preset_work_process(struct k_work *work) -{ - const uint8_t active_index = bt_has_preset_active_get(); - - for (size_t i = 0U; i < ARRAY_SIZE(has_client_list); i++) { - struct has_client *client = &has_client_list[i]; - int err; - - if (client->conn == NULL) { - /* mark to notify on reconnect */ - atomic_set_bit(client->flags, FLAG_ACTIVE_INDEX_CHANGED); - continue; - } else if (atomic_test_and_clear_bit(client->flags, FLAG_ACTIVE_INDEX_CHANGED)) { - err = bt_gatt_notify(client->conn, ACTIVE_PRESET_INDEX_ATTR, &active_index, - sizeof(active_index)); - if (err != 0) { - LOG_DBG("failed to notify active_index for %p: %d", client->conn, - err); - } - } - } -} - -static void preset_active_set(uint8_t index) +static void preset_set_active(struct has_preset *preset) { - if (index != has.active_index) { - has.active_index = index; - - for (size_t i = 0U; i < ARRAY_SIZE(has_client_list); i++) { - struct has_client *client = &has_client_list[i]; - /* mark to notify */ - atomic_set_bit(client->flags, FLAG_ACTIVE_INDEX_CHANGED); - } + if (active_preset != preset) { + active_preset = preset; - /* Emit active preset notification */ - k_work_submit(&active_preset_work); + notify(NULL, FLAG_ACTIVE_INDEX_CHANGED); } } -static uint8_t preset_select(const struct has_preset *preset, bool sync) +static uint8_t preset_select(struct has_preset *preset, bool sync) { const int err = preset->ops->select(preset->index, sync); @@ -859,15 +1296,20 @@ static uint8_t preset_select(const struct has_preset *preset, bool sync) return BT_ATT_ERR_UNLIKELY; } - preset_active_set(preset->index); + preset_set_active(preset); return 0; } +static bool is_preset_available(const struct has_preset *preset) +{ + return (preset->properties & BT_HAS_PROP_AVAILABLE) != 0; +} + static uint8_t handle_set_active_preset(struct net_buf_simple *buf, bool sync) { const struct bt_has_cp_set_active_preset *pdu; - const struct has_preset *preset = NULL; + struct has_preset *preset; if (buf->len < sizeof(*pdu)) { return BT_HAS_ERR_INVALID_PARAM_LEN; @@ -875,12 +1317,12 @@ static uint8_t handle_set_active_preset(struct net_buf_simple *buf, bool sync) pdu = net_buf_simple_pull_mem(buf, sizeof(*pdu)); - preset_foreach(pdu->index, pdu->index, preset_found, &preset); + preset = preset_lookup_index(pdu->index); if (preset == NULL) { return BT_ATT_ERR_OUT_OF_RANGE; } - if (!(preset->properties & BT_HAS_PROP_AVAILABLE)) { + if (!is_preset_available(preset)) { return BT_HAS_ERR_OPERATION_NOT_POSSIBLE; } @@ -889,80 +1331,52 @@ static uint8_t handle_set_active_preset(struct net_buf_simple *buf, bool sync) static uint8_t handle_set_next_preset(bool sync) { - const struct has_preset *next_avail = NULL; - const struct has_preset *first_avail = NULL; + struct has_preset *next, *tmp; - for (size_t i = 0; i < has_preset_num; i++) { - const struct has_preset *tmp = &has_preset_list[i]; + if (active_preset == NULL) { + next = preset_get_head(); + } else { + next = preset_get_next(active_preset); + } - if (tmp->index == BT_HAS_PRESET_INDEX_NONE) { + tmp = next; + do { + if (next == NULL) { break; } - if (!(tmp->properties & BT_HAS_PROP_AVAILABLE)) { - continue; - } - - if (tmp->index < has.active_index && !first_avail) { - first_avail = tmp; - continue; - } - - if (tmp->index > has.active_index) { - next_avail = tmp; - break; + if (is_preset_available(next)) { + return preset_select(next, sync); } - } - - if (next_avail) { - return preset_select(next_avail, sync); - } - if (first_avail) { - return preset_select(first_avail, sync); - } + next = preset_get_next(next); + } while (tmp != next); return BT_HAS_ERR_OPERATION_NOT_POSSIBLE; } static uint8_t handle_set_prev_preset(bool sync) { - const struct has_preset *prev_available = NULL; - const struct has_preset *last_available = NULL; - - for (size_t i = 0; i < ARRAY_SIZE(has_preset_list); i++) { - const struct has_preset *tmp = &has_preset_list[i]; - - if (tmp->index == BT_HAS_PRESET_INDEX_NONE) { - break; - } - - if (!(tmp->properties & BT_HAS_PROP_AVAILABLE)) { - continue; - } + struct has_preset *prev, *tmp; - if (tmp->index < has.active_index) { - prev_available = tmp; - continue; - } + if (active_preset == NULL) { + prev = preset_get_tail(); + } else { + prev = preset_get_prev(active_preset); + } - if (prev_available) { + tmp = prev; + do { + if (prev == NULL) { break; } - if (tmp->index > has.active_index) { - last_available = tmp; - continue; + if (is_preset_available(prev)) { + return preset_select(prev, sync); } - } - - if (prev_available) { - return preset_select(prev_available, sync); - } - if (last_available) { - return preset_select(last_available, sync); - } + prev = preset_get_prev(prev); + } while (tmp != prev); return BT_HAS_ERR_OPERATION_NOT_POSSIBLE; } @@ -982,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: @@ -1034,7 +1450,7 @@ static ssize_t write_control_point(struct bt_conn *conn, const struct bt_gatt_at err = handle_control_point_op(conn, &buf); if (err) { - LOG_WRN("err 0x%02x", err); + LOG_WRN("handle_control_point_op err 0x%02x", err); return BT_GATT_ERR(err); } @@ -1043,7 +1459,7 @@ static ssize_t write_control_point(struct bt_conn *conn, const struct bt_gatt_at int bt_has_preset_register(const struct bt_has_preset_register_param *param) { - struct has_preset *preset = NULL; + struct has_preset *preset; size_t name_len; CHECKIF(param == NULL) { @@ -1082,102 +1498,107 @@ int bt_has_preset_register(const struct bt_has_preset_register_param *param) return -EINVAL; } - preset_foreach(param->index, param->index, preset_found, &preset); + preset = preset_lookup_index(param->index); if (preset != NULL) { 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; } - return bt_has_cp_generic_update(NULL, preset, BT_HAS_IS_LAST); + if (preset == preset_get_tail()) { + update_last_preset_index_known(NULL, preset->index); + } + + return bt_has_cp_generic_update(NULL, preset_get_prev_index(preset), preset->index, + preset->properties, preset->name, BT_HAS_IS_LAST); } int bt_has_preset_unregister(uint8_t index) { - struct has_preset *preset = NULL; - - NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) + - sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t)); + struct has_preset *preset; + int err; CHECKIF(index == BT_HAS_PRESET_INDEX_NONE) { LOG_ERR("index is invalid"); return -EINVAL; } - preset_foreach(index, index, preset_found, &preset); + preset = preset_lookup_index(index); if (preset == NULL) { return -ENOENT; } - preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_DELETED, BT_HAS_IS_LAST); - net_buf_simple_add_u8(&buf, preset->index); - - preset_free(preset); - - return control_point_send_all(&buf); -} - -int bt_has_preset_available(uint8_t index) -{ - struct has_preset *preset = NULL; - - CHECKIF(index == BT_HAS_PRESET_INDEX_NONE) { - LOG_ERR("index is invalid"); - return -EINVAL; + if (preset == active_preset) { + return -EADDRINUSE; } - preset_foreach(index, index, preset_found, &preset); - if (preset == NULL) { - return -ENOENT; + err = bt_has_cp_preset_record_deleted(NULL, preset->index); + if (err != 0) { + return err; } - /* toggle property bit if needed */ - if (!(preset->properties & BT_HAS_PROP_AVAILABLE)) { - NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) + - sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t)); - - preset->properties ^= BT_HAS_PROP_AVAILABLE; - - preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_AVAILABLE, BT_HAS_IS_LAST); - net_buf_simple_add_u8(&buf, preset->index); - - return control_point_send_all(&buf); + if (preset == preset_get_tail()) { + update_last_preset_index_known(NULL, preset_get_prev_index(preset)); } + preset_free(preset); + return 0; } -int bt_has_preset_unavailable(uint8_t index) +static int set_preset_availability(uint8_t index, bool available) { - struct has_preset *preset = NULL; + NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) + + sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t)); + struct has_preset *preset; + uint8_t change_id; CHECKIF(index == BT_HAS_PRESET_INDEX_NONE) { LOG_ERR("index is invalid"); return -EINVAL; } - preset_foreach(index, index, preset_found, &preset); + preset = preset_lookup_index(index); if (preset == NULL) { return -ENOENT; } - /* toggle property bit if needed */ - if (preset->properties & BT_HAS_PROP_AVAILABLE) { - NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) + - sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t)); - - preset->properties ^= BT_HAS_PROP_AVAILABLE; + if (is_preset_available(preset) == available) { + /* availability not changed */ + return 0; + } - preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_UNAVAILABLE, BT_HAS_IS_LAST); - net_buf_simple_add_u8(&buf, preset->index); + preset->properties ^= BT_HAS_PROP_AVAILABLE; - return control_point_send_all(&buf); + if (is_preset_available(preset)) { + change_id = BT_HAS_CHANGE_ID_PRESET_AVAILABLE; + } else { + change_id = BT_HAS_CHANGE_ID_PRESET_UNAVAILABLE; } - return 0; + preset_changed_prepare(&buf, change_id, BT_HAS_IS_LAST); + net_buf_simple_add_u8(&buf, preset->index); + + return control_point_send_all(&buf); +} + +int bt_has_preset_available(uint8_t index) +{ + return set_preset_availability(index, true); +} + +int bt_has_preset_unavailable(uint8_t index) +{ + return set_preset_availability(index, false); } struct bt_has_preset_foreach_data { @@ -1212,27 +1633,34 @@ void bt_has_preset_foreach(uint8_t index, bt_has_preset_func_t func, void *user_ int bt_has_preset_active_set(uint8_t index) { - if (index != BT_HAS_PRESET_INDEX_NONE) { - struct has_preset *preset = NULL; + struct has_preset *preset; - preset_foreach(index, index, preset_found, &preset); - if (preset == NULL) { - return -ENOENT; - } + if (index == BT_HAS_PRESET_INDEX_NONE) { + preset_set_active(NULL); + return 0; + } - if (!(preset->properties & BT_HAS_PROP_AVAILABLE)) { - return -EINVAL; - } + preset = preset_lookup_index(index); + if (preset == NULL) { + return -ENOENT; + } + + if (!is_preset_available(preset)) { + return -EINVAL; } - preset_active_set(index); + preset_set_active(preset); return 0; } uint8_t bt_has_preset_active_get(void) { - return has.active_index; + if (active_preset == NULL) { + return BT_HAS_PRESET_INDEX_NONE; + } + + return active_preset->index; } int bt_has_preset_name_change(uint8_t index, const char *name) @@ -1286,29 +1714,8 @@ static int has_features_register(const struct bt_has_features_param *features) } #if defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE) -static void features_work_process(struct k_work *work) -{ - for (size_t i = 0U; i < ARRAY_SIZE(has_client_list); i++) { - struct has_client *client = &has_client_list[i]; - int err; - - if (client->conn == NULL) { - /* mark to notify on reconnect */ - atomic_set_bit(client->flags, FLAG_FEATURES_CHANGED); - continue; - } else if (atomic_test_and_clear_bit(client->flags, FLAG_CONTROL_POINT_NOTIFY)) { - err = bt_gatt_notify(client->conn, FEATURES_ATTR, &has.features, - sizeof(has.features)); - if (err != 0) { - LOG_DBG("failed to notify features for %p: %d", client->conn, err); - } - } - } -} - int bt_has_features_set(const struct bt_has_features_param *features) { - uint8_t tmp_features; int err; if (!has.registered) { @@ -1322,37 +1729,13 @@ int bt_has_features_set(const struct bt_has_features_param *features) return 0; } - tmp_features = has.features; - err = has_features_register(features); if (err != 0) { LOG_DBG("Failed to register features"); return err; } - bool tmp_pending_ntf_features[ARRAY_SIZE(has_client_list)]; - - for (size_t i = 0U; i < ARRAY_SIZE(has_client_list); i++) { - struct has_client *client = &has_client_list[i]; - /* save old state */ - tmp_pending_ntf_features[i] = atomic_test_bit(client->flags, FLAG_FEATURES_CHANGED); - /* mark to notify */ - atomic_set_bit(client->flags, FLAG_FEATURES_CHANGED); - } - - err = k_work_submit(&features_work); - if (err < 0) { - /* restore old values */ - for (size_t i = 0U; i < ARRAY_SIZE(has_client_list); i++) { - struct has_client *client = &has_client_list[i]; - - atomic_set_bit_to(client->flags, FLAG_FEATURES_CHANGED, - tmp_pending_ntf_features[i]); - } - has.features = tmp_features; - - return err; - } + notify(NULL, FLAG_FEATURES_CHANGED); return 0; } @@ -1386,6 +1769,34 @@ int bt_has_register(const struct bt_has_features_param *features) return err; } + if (IS_ENABLED(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)) { + hearing_aid_features_attr = bt_gatt_find_by_uuid(has_svc.attrs, has_svc.attr_count, + BT_UUID_HAS_HEARING_AID_FEATURES); + __ASSERT_NO_MSG(hearing_aid_features_attr != NULL); + } + + if (IS_ENABLED(CONFIG_BT_HAS_PRESET_SUPPORT)) { + preset_control_point_attr = bt_gatt_find_by_uuid(has_svc.attrs, has_svc.attr_count, + BT_UUID_HAS_PRESET_CONTROL_POINT); + __ASSERT_NO_MSG(preset_control_point_attr != NULL); + + active_preset_index_attr = bt_gatt_find_by_uuid(has_svc.attrs, has_svc.attr_count, + BT_UUID_HAS_ACTIVE_PRESET_INDEX); + __ASSERT_NO_MSG(active_preset_index_attr != NULL); + } + +#if defined(CONFIG_BT_HAS_PRESET_SUPPORT) + for (size_t i = 0; i < ARRAY_SIZE(preset_pool); i++) { + struct has_preset *preset = &preset_pool[i]; + + sys_slist_append(&preset_free_list, &preset->node); + } +#endif /* CONFIG_BT_HAS_PRESET_SUPPORT */ + +#if defined(CONFIG_BT_HAS_PRESET_SUPPORT) || defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE) + bt_conn_auth_info_cb_register(&auth_info_cb); +#endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ + has.registered = true; return 0; diff --git a/subsys/bluetooth/audio/has_client.c b/subsys/bluetooth/audio/has_client.c index 77f40d48bd547bf..437fa425e21469f 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,7 +423,7 @@ 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) { LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); @@ -489,11 +443,9 @@ 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 +472,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 +490,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,7 +517,7 @@ 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) { LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); @@ -591,13 +542,11 @@ static int control_point_subscribe(struct has_inst *inst, uint16_t value_handle, 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 +569,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 +586,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 +600,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 +635,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 +652,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 +680,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 +697,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,7 +707,7 @@ 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) { LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); @@ -785,12 +726,10 @@ static int features_subscribe(struct has_inst *inst, uint16_t value_handle) 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 +765,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 +807,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 +816,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 +831,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 +839,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 +848,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 +857,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 +872,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 +880,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 +897,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 +909,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 +922,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 +934,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 +947,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 +959,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 96fafda94733002..5c5dc6b94109323 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 @@ -77,6 +80,7 @@ struct bt_has_cp_read_preset_rsp { struct bt_has_cp_preset_changed { uint8_t change_id; uint8_t is_last; + uint8_t additional_params[0]; } __packed; struct bt_has_cp_generic_update { @@ -138,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 65972e87125a73a..560ac41b11df3da 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; diff --git a/subsys/bluetooth/audio/mcc_internal.h b/subsys/bluetooth/audio/mcc_internal.h new file mode 100644 index 000000000000000..61c954d47af1f22 --- /dev/null +++ b/subsys/bluetooth/audio/mcc_internal.h @@ -0,0 +1,112 @@ +/** @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 { + 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 */ +}; + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MCP_INTERNAL_ */ diff --git a/subsys/bluetooth/audio/mcs.c b/subsys/bluetooth/audio/mcs.c index 3d31af7a828b4ee..271ea690ad73516 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/micp_mic_ctlr.c b/subsys/bluetooth/audio/micp_mic_ctlr.c index 55fa6c3c5db306d..0bceb26d189aa9b 100644 --- a/subsys/bluetooth/audio/micp_mic_ctlr.c +++ b/subsys/bluetooth/audio/micp_mic_ctlr.c @@ -31,7 +31,12 @@ LOG_MODULE_REGISTER(bt_micp_mic_ctlr, CONFIG_BT_MICP_MIC_CTLR_LOG_LEVEL); static struct bt_micp_mic_ctlr_cb *micp_mic_ctlr_cb; 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 struct bt_micp_mic_ctlr *mic_ctlr_get_by_conn(const struct bt_conn *conn) +{ + return &mic_ctlrs[bt_conn_index(conn)]; +} static uint8_t mute_notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, @@ -44,7 +49,7 @@ 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)) { @@ -66,9 +71,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; @@ -94,7 +99,7 @@ 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); @@ -155,7 +160,7 @@ 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); @@ -218,7 +223,7 @@ 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; @@ -290,7 +295,7 @@ 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"); @@ -359,7 +364,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 +395,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)); @@ -481,6 +486,25 @@ int bt_micp_mic_ctlr_included_get(struct bt_micp_mic_ctlr *mic_ctlr, return 0; } +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) { CHECKIF(mic_ctlr == NULL) { diff --git a/subsys/bluetooth/audio/mpl.c b/subsys/bluetooth/audio/mpl.c index cce2403b5b6231a..94e15071d2cb5e0 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; @@ -2442,12 +2033,23 @@ void set_track_position(int32_t position) } } -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 +2058,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 +2104,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 +2120,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 +2139,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 +2163,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 +2172,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 +2187,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 +2209,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 +2276,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 +2287,35 @@ 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) +{ + if (media_player.state == MEDIA_PROXY_STATE_SEEKING) { + const int32_t pos_diff_cs = + TRACK_POS_WORK_DELAY_MS / 10; /* position is in centiseconds*/ + + /* When seeking, apply the seeking speed factor */ + set_relative_track_position(pos_diff_cs * media_player.seeking_speed_factor); + + 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 +2417,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 +2522,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 b66b83abed4872e..c8a553da2166d9a 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 2ce6db23a9ffe1d..64f750523ff71f1 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 9f5291ae5797fd2..2c449f7f4adc540 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 000000000000000..9cb589c90950a2c --- /dev/null +++ b/subsys/bluetooth/audio/pbp.c @@ -0,0 +1,81 @@ +/* + * 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; +} + +uint8_t bt_pbp_parse_announcement(struct bt_data *data, + enum bt_pbp_announcement_feature *features, + uint8_t *meta) +{ + uint8_t meta_len = 0; + struct bt_uuid_16 adv_uuid; + + CHECKIF(!data || !features || !meta) { + return -EINVAL; + } + + if (data->data_len < BT_PBP_MIN_PBA_SIZE) { + return -EBADMSG; + } + + if (data->type != BT_DATA_SVC_DATA16) { + return -EINVAL; + } + + if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) { + return -EINVAL; + } + + if (bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_PBA)) { + return -EBADMSG; + } + + /* Copy source features, metadata length and metadata from the Announcement */ + *features = data->data[BT_UUID_SIZE_16]; + meta_len = data->data[BT_UUID_SIZE_16 + sizeof(uint8_t)]; + memcpy(meta, data->data + BT_PBP_MIN_PBA_SIZE, meta_len); + + return meta_len; +} diff --git a/subsys/bluetooth/audio/shell/CMakeLists.txt b/subsys/bluetooth/audio/shell/CMakeLists.txt index a5230278330d426..9913d92994a7212 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 7f19d9105d89c76..a674b474d078b10 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) @@ -286,29 +334,6 @@ static inline void copy_broadcast_source_preset(struct broadcast_source *source, memcpy(&source->qos, &named_preset->preset.qos, sizeof(source->qos)); memcpy(&source->codec_cfg, &named_preset->preset.codec_cfg, sizeof(source->codec_cfg)); } - -static inline int codec_set_chan_alloc(struct bt_audio_codec_cfg *codec_cfg, - enum bt_audio_location loc) -{ - for (size_t i = 0U; i < codec_cfg->data_len;) { - const uint8_t len = codec_cfg->data[i++]; - const uint8_t type = codec_cfg->data[i++]; - uint8_t *value = &codec_cfg->data[i]; - const uint8_t value_len = len - sizeof(type); - - if (type == BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC) { - const uint32_t loc_32 = loc; - - sys_put_le32(loc_32, value); - - return 0; - } - i += value_len; - } - - return -ENODATA; -} - #endif /* CONFIG_BT_AUDIO */ #endif /* __AUDIO_H */ diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 82ed1d3c5e4c2f7..302be473d70b84d 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); } @@ -245,7 +243,13 @@ static int init_lc3(const struct bt_bap_stream *stream) return ret; } - lc3_frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(stream->codec_cfg); + ret = bt_audio_codec_cfg_get_frame_dur(stream->codec_cfg); + if (ret > 0) { + lc3_frame_duration_us = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret); + } else { + return ret; + } + lc3_octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg); lc3_frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(stream->codec_cfg, true); lc3_octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg); @@ -394,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++) { @@ -410,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; } @@ -582,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, @@ -985,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; @@ -1023,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; @@ -1030,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; @@ -1065,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; @@ -1077,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; @@ -1098,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) { @@ -1157,7 +1165,7 @@ static int cmd_stream_qos(const struct shell *sh, size_t argc, char *argv[]) { struct bt_audio_codec_qos *qos; unsigned long interval; - int err; + int err = 0; if (default_stream == NULL) { shell_print(sh, "No stream selected"); @@ -1416,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 { @@ -1432,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; @@ -1695,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) +static void base_recv(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size) { - 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) -{ - 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; - - if (memcmp(base, &default_broadcast_sink.received_base, - sizeof(default_broadcast_sink.received_base)) == 0) { - /* Don't print duplicates */ - return; - } - - 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); + /* 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; - 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); + print_base(base); } - - 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) @@ -2106,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); @@ -2276,7 +2230,7 @@ static int cmd_sync_broadcast(const struct shell *sh, size_t argc, char *argv[]) struct bt_bap_stream *streams[ARRAY_SIZE(broadcast_sink_streams)]; uint32_t bis_bitfield; size_t stream_cnt; - int err; + int err = 0; bis_bitfield = 0; stream_cnt = 0U; @@ -2390,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; @@ -2555,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[]) { @@ -2611,7 +2564,6 @@ static int cmd_send(const struct shell *sh, size_t argc, char *argv[]) #if defined(CONFIG_LIBLC3) static bool stream_start_sine_verify(const struct bt_bap_stream *bap_stream) { - int stream_frame_duration_us; struct bt_bap_ep_info info; int err; @@ -2637,8 +2589,12 @@ static bool stream_start_sine_verify(const struct bt_bap_stream *bap_stream) return false; } - stream_frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(bap_stream->codec_cfg); - if (stream_frame_duration_us != lc3_frame_duration_us) { + err = bt_audio_codec_cfg_get_frame_dur(bap_stream->codec_cfg); + if (err > 0) { + if (bt_audio_codec_cfg_frame_dur_to_frame_dur_us(err) != lc3_frame_duration_us) { + return false; + } + } else { return false; } @@ -2737,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); @@ -2749,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, @@ -2982,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 5f98a26f8c1197d..64f0f5f38906839 100644 --- a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c @@ -25,8 +25,11 @@ #include "audio.h" #define INVALID_BROADCAST_ID 0xFFFFFFFFU +/* 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; @@ -38,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; @@ -161,7 +153,7 @@ static void bap_broadcast_assistant_recv_state_cb( } } - if (per_adv_sync) { + if (per_adv_sync && IS_ENABLED(CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER)) { shell_print(ctx_shell, "Sending PAST"); err = bt_le_per_adv_sync_transfer(per_adv_sync, @@ -200,7 +192,8 @@ static void bap_broadcast_assistant_recv_state_cb( } } - if (ext_adv != NULL && IS_ENABLED(CONFIG_BT_PER_ADV)) { + if (ext_adv != NULL && IS_ENABLED(CONFIG_BT_PER_ADV) && + IS_ENABLED(CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER)) { shell_print(ctx_shell, "Sending local PAST"); err = bt_le_per_adv_set_info_transfer(ext_adv, conn, @@ -453,7 +446,7 @@ static int cmd_bap_broadcast_assistant_add_src(const struct shell *sh, return -ENOEXEC; } - if (bis_sync > UINT32_MAX) { + if (!VALID_BIS_SYNC(bis_sync)) { shell_error(sh, "Invalid bis_sync: %lu", bis_sync); return -ENOEXEC; @@ -640,7 +633,7 @@ static int cmd_bap_broadcast_assistant_add_broadcast_id(const struct shell *sh, shell_error(sh, "failed to parse bis_sync: %d", err); return -ENOEXEC; - } else if (bis_sync > UINT32_MAX) { + } else if (!VALID_BIS_SYNC(bis_sync)) { shell_error(sh, "Invalid bis_sync: %lu", bis_sync); return -ENOEXEC; @@ -738,7 +731,7 @@ static int cmd_bap_broadcast_assistant_mod_src(const struct shell *sh, return -ENOEXEC; } - if (bis_sync > UINT32_MAX) { + if (!VALID_BIS_SYNC(bis_sync)) { shell_error(sh, "Invalid bis_sync: %lu", bis_sync); return -ENOEXEC; @@ -776,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) { @@ -852,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 ab4ee9ede0deb0f..721553f4ad116e2 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